blob: 71c0c48e71783f8df7d4d67158f9033e6352efc6 [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
reed@google.com46799cd2011-02-22 20:56:26 +0000297void SkGpuDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& clip,
298 const SkClipStack& clipStack) {
299 this->INHERITED::setMatrixClip(matrix, clip, clipStack);
reed@google.comac10a2d2010-12-22 21:39:39 +0000300
301 convert_matrixclip(fContext, matrix, clip);
302}
303
304void SkGpuDevice::gainFocus(SkCanvas* canvas, const SkMatrix& matrix,
305 const SkRegion& clip) {
306 fContext->setRenderTarget(fRenderTarget);
307
308 this->INHERITED::gainFocus(canvas, matrix, clip);
309
310 convert_matrixclip(fContext, matrix, clip);
311
312 if (fNeedClear) {
313 fContext->eraseColor(0x0);
314 fNeedClear = false;
315 }
316}
317
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000318bool SkGpuDevice::bindDeviceAsTexture(GrPaint* paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000319 if (NULL != fTexture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000320 paint->setTexture(fTexture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000321 return true;
322 }
323 return false;
324}
325
326///////////////////////////////////////////////////////////////////////////////
327
bsalomon@google.com5782d712011-01-21 21:03:59 +0000328// must be in SkShader::BitmapTypeOrder
reed@google.comac10a2d2010-12-22 21:39:39 +0000329
bsalomon@google.com5782d712011-01-21 21:03:59 +0000330static const GrSamplerState::SampleMode sk_bmp_type_to_sample_mode[] = {
331 (GrSamplerState::SampleMode) -1, // kNone_BitmapType
332 GrSamplerState::kNormal_SampleMode, // kDefault_BitmapType
333 GrSamplerState::kRadial_SampleMode, // kRadial_BitmapType
334 GrSamplerState::kSweep_SampleMode, // kSweep_BitmapType
335 GrSamplerState::kRadial2_SampleMode, // kTwoPointRadial_BitmapType
336};
337
338bool SkGpuDevice::skPaint2GrPaintNoShader(const SkPaint& skPaint,
339 bool justAlpha,
340 GrPaint* grPaint) {
341
342 grPaint->fDither = skPaint.isDither();
343 grPaint->fAntiAlias = skPaint.isAntiAlias();
344
345 SkXfermode::Coeff sm = SkXfermode::kOne_Coeff;
346 SkXfermode::Coeff dm = SkXfermode::kISA_Coeff;
347
348 SkXfermode* mode = skPaint.getXfermode();
349 if (mode) {
350 if (!mode->asCoeff(&sm, &dm)) {
reed@google.com1a2e8d22011-01-21 22:08:29 +0000351 SkDEBUGCODE(SkDebugf("Unsupported xfer mode.\n");)
bsalomon@google.com5782d712011-01-21 21:03:59 +0000352#if 0
353 return false;
354#endif
355 }
356 }
357 grPaint->fSrcBlendCoeff = sk_blend_to_grblend(sm);
358 grPaint->fDstBlendCoeff = sk_blend_to_grblend(dm);
359
360 if (justAlpha) {
361 uint8_t alpha = skPaint.getAlpha();
362 grPaint->fColor = GrColorPackRGBA(alpha, alpha, alpha, alpha);
363 } else {
364 grPaint->fColor = SkGr::SkColor2GrColor(skPaint.getColor());
365 grPaint->setTexture(NULL);
366 }
367 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000368}
369
bsalomon@google.com5782d712011-01-21 21:03:59 +0000370bool SkGpuDevice::skPaint2GrPaintShader(const SkPaint& skPaint,
371 SkAutoCachedTexture* act,
372 const SkMatrix& ctm,
373 GrPaint* grPaint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000374
bsalomon@google.com5782d712011-01-21 21:03:59 +0000375 SkASSERT(NULL != act);
reed@google.comac10a2d2010-12-22 21:39:39 +0000376
bsalomon@google.com5782d712011-01-21 21:03:59 +0000377 SkShader* shader = skPaint.getShader();
reed@google.comac10a2d2010-12-22 21:39:39 +0000378 if (NULL == shader) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000379 return this->skPaint2GrPaintNoShader(skPaint, false, grPaint);
380 grPaint->setTexture(NULL);
381 return true;
382 } else if (!this->skPaint2GrPaintNoShader(skPaint, true, grPaint)) {
383 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000384 }
385
bsalomon@google.com5782d712011-01-21 21:03:59 +0000386 SkPaint noAlphaPaint(skPaint);
387 noAlphaPaint.setAlpha(255);
388 shader->setContext(this->accessBitmap(false), noAlphaPaint, ctm);
reed@google.comac10a2d2010-12-22 21:39:39 +0000389
reed@google.comac10a2d2010-12-22 21:39:39 +0000390 SkBitmap bitmap;
391 SkMatrix matrix;
392 SkShader::TileMode tileModes[2];
393 SkScalar twoPointParams[3];
394 SkShader::BitmapType bmptype = shader->asABitmap(&bitmap, &matrix,
395 tileModes, twoPointParams);
396
bsalomon@google.com5782d712011-01-21 21:03:59 +0000397 GrSamplerState::SampleMode sampleMode = sk_bmp_type_to_sample_mode[bmptype];
398 if (-1 == sampleMode) {
399 SkDebugf("shader->asABitmap() == kNone_BitmapType\n");
400 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000401 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000402 grPaint->fSampler.setSampleMode(sampleMode);
bsalomon@google.com0748f212011-02-01 22:56:16 +0000403 grPaint->fSampler.setFilter(skPaint.isFilterBitmap());
bsalomon@google.com5782d712011-01-21 21:03:59 +0000404 grPaint->fSampler.setWrapX(sk_tile_mode_to_grwrap(tileModes[0]));
405 grPaint->fSampler.setWrapY(sk_tile_mode_to_grwrap(tileModes[1]));
reed@google.comac10a2d2010-12-22 21:39:39 +0000406 if (GrSamplerState::kRadial2_SampleMode == sampleMode) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000407 grPaint->fSampler.setRadial2Params(twoPointParams[0],
408 twoPointParams[1],
409 twoPointParams[2] < 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000410 }
411
bsalomon@google.com5782d712011-01-21 21:03:59 +0000412 GrTexture* texture = act->set(this, bitmap, grPaint->fSampler);
reed@google.comac10a2d2010-12-22 21:39:39 +0000413 if (NULL == texture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000414 SkDebugf("Couldn't convert bitmap to texture.\n");
415 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000416 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000417 grPaint->setTexture(texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000418
419 // since our texture coords will be in local space, we wack the texture
420 // matrix to map them back into 0...1 before we load it
421 SkMatrix localM;
422 if (shader->getLocalMatrix(&localM)) {
423 SkMatrix inverse;
424 if (localM.invert(&inverse)) {
425 matrix.preConcat(inverse);
426 }
427 }
428 if (SkShader::kDefault_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000429 GrScalar sx = GrFixedToScalar(GR_Fixed1 / bitmap.width());
430 GrScalar sy = GrFixedToScalar(GR_Fixed1 / bitmap.height());
reed@google.comac10a2d2010-12-22 21:39:39 +0000431 matrix.postScale(sx, sy);
reed@google.comac10a2d2010-12-22 21:39:39 +0000432 } else if (SkShader::kRadial_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000433 GrScalar s = GrFixedToScalar(GR_Fixed1 / bitmap.width());
reed@google.comac10a2d2010-12-22 21:39:39 +0000434 matrix.postScale(s, s);
435 }
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000436 GrMatrix grMat;
437 SkGr::SkMatrix2GrMatrix(matrix, &grMat);
438 grPaint->fSampler.setMatrix(grMat);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000439
440 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000441}
442
443///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com5782d712011-01-21 21:03:59 +0000444
445class SkPositionSource {
446public:
447 SkPositionSource(const SkPoint* points, int count)
448 : fPoints(points), fCount(count) {}
449
450 int count() const { return fCount; }
451
452 void writeValue(int i, GrPoint* dstPosition) const {
453 SkASSERT(i < fCount);
454 dstPosition->fX = SkScalarToGrScalar(fPoints[i].fX);
455 dstPosition->fY = SkScalarToGrScalar(fPoints[i].fY);
456 }
457private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000458 const SkPoint* fPoints;
bsalomon@google.com19628322011-02-03 21:30:17 +0000459 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000460};
461
462class SkTexCoordSource {
463public:
464 SkTexCoordSource(const SkPoint* coords)
465 : fCoords(coords) {}
466
467 void writeValue(int i, GrPoint* dstCoord) const {
468 dstCoord->fX = SkScalarToGrScalar(fCoords[i].fX);
469 dstCoord->fY = SkScalarToGrScalar(fCoords[i].fY);
470 }
471private:
472 const SkPoint* fCoords;
473};
474
475class SkColorSource {
476public:
477 SkColorSource(const SkColor* colors) : fColors(colors) {}
478
479 void writeValue(int i, GrColor* dstColor) const {
480 *dstColor = SkGr::SkColor2GrColor(fColors[i]);
481 }
482private:
483 const SkColor* fColors;
484};
485
486class SkIndexSource {
487public:
488 SkIndexSource(const uint16_t* indices, int count)
489 : fIndices(indices), fCount(count) {
490 }
491
492 int count() const { return fCount; }
493
494 void writeValue(int i, uint16_t* dstIndex) const {
495 *dstIndex = fIndices[i];
496 }
497
498private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000499 const uint16_t* fIndices;
bsalomon@google.com19628322011-02-03 21:30:17 +0000500 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000501};
502
503///////////////////////////////////////////////////////////////////////////////
504
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000505#if 0 // not currently being used so don't compile,
506
bsalomon@google.com5782d712011-01-21 21:03:59 +0000507// can be used for positions or texture coordinates
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000508
bsalomon@google.com5782d712011-01-21 21:03:59 +0000509class SkRectFanSource {
510public:
511 SkRectFanSource(const SkRect& rect) : fRect(rect) {}
512
513 int count() const { return 4; }
514
515 void writeValue(int i, GrPoint* dstPoint) const {
516 SkASSERT(i < 4);
517 dstPoint->fX = SkScalarToGrScalar((i % 3) ? fRect.fRight :
518 fRect.fLeft);
519 dstPoint->fY = SkScalarToGrScalar((i < 2) ? fRect.fTop :
520 fRect.fBottom);
521 }
522private:
523 const SkRect& fRect;
524};
525
526class SkIRectFanSource {
527public:
528 SkIRectFanSource(const SkIRect& rect) : fRect(rect) {}
529
530 int count() const { return 4; }
531
532 void writeValue(int i, GrPoint* dstPoint) const {
533 SkASSERT(i < 4);
534 dstPoint->fX = (i % 3) ? GrIntToScalar(fRect.fRight) :
535 GrIntToScalar(fRect.fLeft);
536 dstPoint->fY = (i < 2) ? GrIntToScalar(fRect.fTop) :
537 GrIntToScalar(fRect.fBottom);
538 }
539private:
540 const SkIRect& fRect;
541};
542
543class SkMatRectFanSource {
544public:
545 SkMatRectFanSource(const SkRect& rect, const SkMatrix& matrix)
546 : fRect(rect), fMatrix(matrix) {}
547
548 int count() const { return 4; }
549
550 void writeValue(int i, GrPoint* dstPoint) const {
551 SkASSERT(i < 4);
552
553#if SK_SCALAR_IS_GR_SCALAR
554 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
555 (i < 2) ? fRect.fTop : fRect.fBottom,
556 (SkPoint*)dstPoint);
557#else
558 SkPoint dst;
559 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
560 (i < 2) ? fRect.fTop : fRect.fBottom,
561 &dst);
562 dstPoint->fX = SkScalarToGrScalar(dst.fX);
563 dstPoint->fY = SkScalarToGrScalar(dst.fY);
564#endif
565 }
566private:
567 const SkRect& fRect;
568 const SkMatrix& fMatrix;
569};
570
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000571#endif
572
reed@google.comac10a2d2010-12-22 21:39:39 +0000573///////////////////////////////////////////////////////////////////////////////
574
575void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
576 CHECK_SHOULD_DRAW(draw);
577
bsalomon@google.com5782d712011-01-21 21:03:59 +0000578 GrPaint grPaint;
579 SkAutoCachedTexture act;
580 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000581 return;
582 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000583
584 fContext->drawPaint(grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000585}
586
587// must be in SkCanvas::PointMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +0000588static const GrPrimitiveType gPointMode2PrimtiveType[] = {
589 kPoints_PrimitiveType,
590 kLines_PrimitiveType,
591 kLineStrip_PrimitiveType
reed@google.comac10a2d2010-12-22 21:39:39 +0000592};
593
594void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000595 size_t count, const SkPoint pts[], const SkPaint& paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000596 CHECK_SHOULD_DRAW(draw);
597
598 SkScalar width = paint.getStrokeWidth();
599 if (width < 0) {
600 return;
601 }
602
603 // we only handle hairlines here, else we let the SkDraw call our drawPath()
604 if (width > 0) {
605 draw.drawPoints(mode, count, pts, paint, true);
606 return;
607 }
608
bsalomon@google.com5782d712011-01-21 21:03:59 +0000609 GrPaint grPaint;
610 SkAutoCachedTexture act;
611 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000612 return;
613 }
614
reed@google.comac10a2d2010-12-22 21:39:39 +0000615#if SK_SCALAR_IS_GR_SCALAR
bsalomon@google.com5782d712011-01-21 21:03:59 +0000616 fContext->drawVertices(grPaint,
617 gPointMode2PrimtiveType[mode],
618 count,
619 (GrPoint*)pts,
620 NULL,
621 NULL,
622 NULL,
623 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000624#else
bsalomon@google.com5782d712011-01-21 21:03:59 +0000625 fContext->drawCustomVertices(grPaint,
626 gPointMode2PrimtiveType[mode],
627 SkPositionSource(pts, count));
reed@google.comac10a2d2010-12-22 21:39:39 +0000628#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000629}
630
631void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
632 const SkPaint& paint) {
633 CHECK_SHOULD_DRAW(draw);
634
635 bool doStroke = paint.getStyle() == SkPaint::kStroke_Style;
636 SkScalar width = paint.getStrokeWidth();
637
638 /*
639 We have special code for hairline strokes, miter-strokes, and fills.
reed@google.com69302852011-02-16 18:08:07 +0000640 Anything else we just call our path code.
reed@google.comac10a2d2010-12-22 21:39:39 +0000641 */
reed@google.com69302852011-02-16 18:08:07 +0000642 bool usePath = doStroke && width > 0 &&
643 paint.getStrokeJoin() != SkPaint::kMiter_Join;
644 // another reason we might need to call drawPath...
645 if (paint.getMaskFilter()) {
646 usePath = true;
647 }
648
649 if (usePath) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000650 SkPath path;
651 path.addRect(rect);
652 this->drawPath(draw, path, paint, NULL, true);
653 return;
654 }
655
bsalomon@google.com5782d712011-01-21 21:03:59 +0000656 GrPaint grPaint;
657 SkAutoCachedTexture act;
658 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000659 return;
660 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000661 fContext->drawRect(grPaint, Sk2Gr(rect), doStroke ? width : -1);
reed@google.comac10a2d2010-12-22 21:39:39 +0000662}
663
reed@google.com69302852011-02-16 18:08:07 +0000664#include "SkMaskFilter.h"
665#include "SkBounder.h"
666
reed@google.com69302852011-02-16 18:08:07 +0000667static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
668 SkMaskFilter* filter, const SkMatrix& matrix,
669 const SkRegion& clip, SkBounder* bounder,
670 GrPaint* grp) {
671 SkMask srcM, dstM;
672
673 if (!SkDraw::DrawToMask(path, &clip.getBounds(), filter, &matrix, &srcM,
674 SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
675 return false;
676 }
677
678 SkAutoMaskImage autoSrc(&srcM, false);
679
680 if (!filter->filterMask(&dstM, srcM, matrix, NULL)) {
681 return false;
682 }
683 // this will free-up dstM when we're done (allocated in filterMask())
684 SkAutoMaskImage autoDst(&dstM, false);
685
686 if (clip.quickReject(dstM.fBounds)) {
687 return false;
688 }
689 if (bounder && !bounder->doIRect(dstM.fBounds)) {
690 return false;
691 }
692
693 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
694 // the current clip (and identity matrix) and grpaint settings
695
reed@google.com0c219b62011-02-16 21:31:18 +0000696 GrAutoMatrix avm(context, GrMatrix::I());
reed@google.com69302852011-02-16 18:08:07 +0000697
698 const GrGpu::TextureDesc desc = {
699 0,
700 GrGpu::kNone_AALevel,
701 dstM.fBounds.width(),
702 dstM.fBounds.height(),
703 GrTexture::kAlpha_8_PixelConfig
704 };
705
706 GrTexture* texture = context->createUncachedTexture(desc, dstM.fImage,
707 dstM.fRowBytes);
708 if (NULL == texture) {
709 return false;
710 }
711
reed@google.com0c219b62011-02-16 21:31:18 +0000712 grp->setTexture(texture);
713 texture->unref();
714 grp->fSampler.setClampNoFilter();
reed@google.com69302852011-02-16 18:08:07 +0000715
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000716 GrRect d;
717 d.setLTRB(GrIntToScalar(dstM.fBounds.fLeft),
reed@google.com0c219b62011-02-16 21:31:18 +0000718 GrIntToScalar(dstM.fBounds.fTop),
719 GrIntToScalar(dstM.fBounds.fRight),
720 GrIntToScalar(dstM.fBounds.fBottom));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000721 GrRect s;
722 s.setLTRB(0, 0, GR_Scalar1, GR_Scalar1);
723 context->drawRectToRect(*grp, d, s);
reed@google.com69302852011-02-16 18:08:07 +0000724 return true;
725}
reed@google.com69302852011-02-16 18:08:07 +0000726
reed@google.com0c219b62011-02-16 21:31:18 +0000727void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
reed@google.comac10a2d2010-12-22 21:39:39 +0000728 const SkPaint& paint, const SkMatrix* prePathMatrix,
729 bool pathIsMutable) {
730 CHECK_SHOULD_DRAW(draw);
731
bsalomon@google.com5782d712011-01-21 21:03:59 +0000732 GrPaint grPaint;
733 SkAutoCachedTexture act;
734 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000735 return;
736 }
737
reed@google.com0c219b62011-02-16 21:31:18 +0000738 // BEGIN lift from SkDraw::drawPath()
739
740 SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
741 bool doFill = true;
742 SkPath tmpPath;
reed@google.comac10a2d2010-12-22 21:39:39 +0000743
744 if (prePathMatrix) {
reed@google.come3445642011-02-16 23:20:39 +0000745 SkPath* result = pathPtr;
reed@google.com0c219b62011-02-16 21:31:18 +0000746
reed@google.come3445642011-02-16 23:20:39 +0000747 if (!pathIsMutable) {
748 result = &tmpPath;
749 pathIsMutable = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000750 }
reed@google.come3445642011-02-16 23:20:39 +0000751 // should I push prePathMatrix on our MV stack temporarily, instead
752 // of applying it here? See SkDraw.cpp
753 pathPtr->transform(*prePathMatrix, result);
754 pathPtr = result;
reed@google.comac10a2d2010-12-22 21:39:39 +0000755 }
reed@google.com0c219b62011-02-16 21:31:18 +0000756 // at this point we're done with prePathMatrix
757 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
reed@google.comac10a2d2010-12-22 21:39:39 +0000758
reed@google.com0c219b62011-02-16 21:31:18 +0000759 if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) {
760 doFill = paint.getFillPath(*pathPtr, &tmpPath);
761 pathPtr = &tmpPath;
762 }
763
764 // END lift from SkDraw::drawPath()
765
reed@google.com69302852011-02-16 18:08:07 +0000766 if (paint.getMaskFilter()) {
reed@google.com0c219b62011-02-16 21:31:18 +0000767 // avoid possibly allocating a new path in transform if we can
768 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
769
770 // transform the path into device space
reed@google.come3445642011-02-16 23:20:39 +0000771 pathPtr->transform(*draw.fMatrix, devPathPtr);
reed@google.com0c219b62011-02-16 21:31:18 +0000772
773 drawWithMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
reed@google.com69302852011-02-16 18:08:07 +0000774 *draw.fMatrix, *draw.fClip, draw.fBounder, &grPaint);
775 return;
776 }
reed@google.com69302852011-02-16 18:08:07 +0000777
bsalomon@google.comffca4002011-02-22 20:34:01 +0000778 GrPathFill fill = kHairLine_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000779
reed@google.com0c219b62011-02-16 21:31:18 +0000780 if (doFill) {
781 switch (pathPtr->getFillType()) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000782 case SkPath::kWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000783 fill = kWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000784 break;
785 case SkPath::kEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000786 fill = kEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000787 break;
788 case SkPath::kInverseWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000789 fill = kInverseWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000790 break;
791 case SkPath::kInverseEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000792 fill = kInverseEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000793 break;
794 default:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000795 SkDebugf("Unsupported path fill type\n");
reed@google.comac10a2d2010-12-22 21:39:39 +0000796 return;
797 }
798 }
799
reed@google.com0c219b62011-02-16 21:31:18 +0000800 SkGrPathIter iter(*pathPtr);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000801 fContext->drawPath(grPaint, &iter, fill);
reed@google.comac10a2d2010-12-22 21:39:39 +0000802}
803
reed@google.comac10a2d2010-12-22 21:39:39 +0000804void SkGpuDevice::drawBitmap(const SkDraw& draw,
805 const SkBitmap& bitmap,
806 const SkIRect* srcRectPtr,
807 const SkMatrix& m,
808 const SkPaint& paint) {
809 CHECK_SHOULD_DRAW(draw);
810
811 SkIRect srcRect;
812 if (NULL == srcRectPtr) {
813 srcRect.set(0, 0, bitmap.width(), bitmap.height());
814 } else {
815 srcRect = *srcRectPtr;
816 }
817
bsalomon@google.com5782d712011-01-21 21:03:59 +0000818 GrPaint grPaint;
819 if (!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
820 return;
821 }
822 grPaint.fSampler.setFilter(paint.isFilterBitmap());
823
reed@google.com02a7e6c2011-01-28 21:21:49 +0000824 const int maxTextureDim = fContext->getMaxTextureDimension();
825 if (bitmap.getTexture() || (bitmap.width() <= maxTextureDim &&
826 bitmap.height() <= maxTextureDim)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000827 // take the fast case
bsalomon@google.com5782d712011-01-21 21:03:59 +0000828 this->internalDrawBitmap(draw, bitmap, srcRect, m, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000829 return;
830 }
831
832 // undo the translate done by SkCanvas
833 int DX = SkMax32(0, srcRect.fLeft);
834 int DY = SkMax32(0, srcRect.fTop);
835 // compute clip bounds in local coordinates
836 SkIRect clipRect;
837 {
838 SkRect r;
839 r.set(draw.fClip->getBounds());
840 SkMatrix matrix, inverse;
841 matrix.setConcat(*draw.fMatrix, m);
842 if (!matrix.invert(&inverse)) {
843 return;
844 }
845 inverse.mapRect(&r);
846 r.roundOut(&clipRect);
847 // apply the canvas' translate to our local clip
848 clipRect.offset(DX, DY);
849 }
850
reed@google.com02a7e6c2011-01-28 21:21:49 +0000851 int nx = bitmap.width() / maxTextureDim;
852 int ny = bitmap.height() / maxTextureDim;
reed@google.comac10a2d2010-12-22 21:39:39 +0000853 for (int x = 0; x <= nx; x++) {
854 for (int y = 0; y <= ny; y++) {
855 SkIRect tileR;
reed@google.com02a7e6c2011-01-28 21:21:49 +0000856 tileR.set(x * maxTextureDim, y * maxTextureDim,
857 (x + 1) * maxTextureDim, (y + 1) * maxTextureDim);
reed@google.comac10a2d2010-12-22 21:39:39 +0000858 if (!SkIRect::Intersects(tileR, clipRect)) {
859 continue;
860 }
861
862 SkIRect srcR = tileR;
863 if (!srcR.intersect(srcRect)) {
864 continue;
865 }
866
867 SkBitmap tmpB;
868 if (bitmap.extractSubset(&tmpB, tileR)) {
869 // now offset it to make it "local" to our tmp bitmap
870 srcR.offset(-tileR.fLeft, -tileR.fTop);
871
872 SkMatrix tmpM(m);
873 {
874 int dx = tileR.fLeft - DX + SkMax32(0, srcR.fLeft);
875 int dy = tileR.fTop - DY + SkMax32(0, srcR.fTop);
876 tmpM.preTranslate(SkIntToScalar(dx), SkIntToScalar(dy));
877 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000878 this->internalDrawBitmap(draw, tmpB, srcR, tmpM, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000879 }
880 }
881 }
882}
883
884/*
885 * This is called by drawBitmap(), which has to handle images that may be too
886 * large to be represented by a single texture.
887 *
bsalomon@google.com5782d712011-01-21 21:03:59 +0000888 * internalDrawBitmap assumes that the specified bitmap will fit in a texture
889 * and that non-texture portion of the GrPaint has already been setup.
reed@google.comac10a2d2010-12-22 21:39:39 +0000890 */
891void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
892 const SkBitmap& bitmap,
893 const SkIRect& srcRect,
894 const SkMatrix& m,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000895 GrPaint* grPaint) {
reed@google.com02a7e6c2011-01-28 21:21:49 +0000896 SkASSERT(bitmap.width() <= fContext->getMaxTextureDimension() &&
897 bitmap.height() <= fContext->getMaxTextureDimension());
reed@google.comac10a2d2010-12-22 21:39:39 +0000898
899 SkAutoLockPixels alp(bitmap);
900 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
901 return;
902 }
903
bsalomon@google.com5782d712011-01-21 21:03:59 +0000904 grPaint->fSampler.setWrapX(GrSamplerState::kClamp_WrapMode);
905 grPaint->fSampler.setWrapY(GrSamplerState::kClamp_WrapMode);
906 grPaint->fSampler.setSampleMode(GrSamplerState::kNormal_SampleMode);
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000907 grPaint->fSampler.setMatrix(GrMatrix::I());
reed@google.comac10a2d2010-12-22 21:39:39 +0000908
909 GrTexture* texture;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000910 SkAutoCachedTexture act(this, bitmap, grPaint->fSampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000911 if (NULL == texture) {
912 return;
913 }
914
bsalomon@google.com5782d712011-01-21 21:03:59 +0000915 grPaint->setTexture(texture);
reed@google.com46799cd2011-02-22 20:56:26 +0000916
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000917 GrRect dstRect(0, 0, GrIntToScalar(srcRect.width()), GrIntToScalar(srcRect.height()));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000918 GrRect paintRect;
919 paintRect.setLTRB(GrFixedToScalar((srcRect.fLeft << 16) / bitmap.width()),
920 GrFixedToScalar((srcRect.fTop << 16) / bitmap.height()),
921 GrFixedToScalar((srcRect.fRight << 16) / bitmap.width()),
922 GrFixedToScalar((srcRect.fBottom << 16) / bitmap.height()));
reed@google.comac10a2d2010-12-22 21:39:39 +0000923
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000924 GrMatrix grMat;
925 SkGr::SkMatrix2GrMatrix(m, &grMat);
reed@google.comac10a2d2010-12-22 21:39:39 +0000926
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000927 fContext->drawRectToRect(*grPaint, dstRect, paintRect, &grMat);
reed@google.comac10a2d2010-12-22 21:39:39 +0000928}
929
930void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
931 int left, int top, const SkPaint& paint) {
932 CHECK_SHOULD_DRAW(draw);
933
934 SkAutoLockPixels alp(bitmap);
935 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
936 return;
937 }
938
bsalomon@google.com5782d712011-01-21 21:03:59 +0000939 GrPaint grPaint;
940 if(!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
941 return;
942 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000943
bsalomon@google.com5782d712011-01-21 21:03:59 +0000944 GrAutoMatrix avm(fContext, GrMatrix::I());
945
946 GrTexture* texture;
947 grPaint.fSampler.setClampNoFilter();
948 SkAutoCachedTexture act(this, bitmap, grPaint.fSampler, &texture);
949
bsalomon@google.com5782d712011-01-21 21:03:59 +0000950 grPaint.setTexture(texture);
951
bsalomon@google.com5782d712011-01-21 21:03:59 +0000952 fContext->drawRectToRect(grPaint,
953 GrRect(GrIntToScalar(left), GrIntToScalar(top),
954 GrIntToScalar(left + bitmap.width()),
955 GrIntToScalar(top + bitmap.height())),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000956 GrRect(0, 0, GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +0000957}
958
959void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
960 int x, int y, const SkPaint& paint) {
961 CHECK_SHOULD_DRAW(draw);
962
bsalomon@google.com5782d712011-01-21 21:03:59 +0000963 GrPaint grPaint;
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000964 if (!((SkGpuDevice*)dev)->bindDeviceAsTexture(&grPaint) ||
bsalomon@google.com5782d712011-01-21 21:03:59 +0000965 !this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
966 return;
reed@google.comac10a2d2010-12-22 21:39:39 +0000967 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000968
969 SkASSERT(NULL != grPaint.getTexture());
970
971 const SkBitmap& bm = dev->accessBitmap(false);
972 int w = bm.width();
973 int h = bm.height();
974
975 GrAutoMatrix avm(fContext, GrMatrix::I());
976
977 grPaint.fSampler.setClampNoFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +0000978
979 fContext->drawRectToRect(grPaint,
reed@google.com1a2e8d22011-01-21 22:08:29 +0000980 GrRect(GrIntToScalar(x),
981 GrIntToScalar(y),
982 GrIntToScalar(x + w),
bsalomon@google.com5782d712011-01-21 21:03:59 +0000983 GrIntToScalar(y + h)),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000984 GrRect(0, 0, GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +0000985}
986
987///////////////////////////////////////////////////////////////////////////////
988
989// must be in SkCanvas::VertexMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +0000990static const GrPrimitiveType gVertexMode2PrimitiveType[] = {
991 kTriangles_PrimitiveType,
992 kTriangleStrip_PrimitiveType,
993 kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +0000994};
995
996void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
997 int vertexCount, const SkPoint vertices[],
998 const SkPoint texs[], const SkColor colors[],
999 SkXfermode* xmode,
1000 const uint16_t indices[], int indexCount,
1001 const SkPaint& paint) {
1002 CHECK_SHOULD_DRAW(draw);
1003
bsalomon@google.com5782d712011-01-21 21:03:59 +00001004 GrPaint grPaint;
1005 SkAutoCachedTexture act;
1006 // we ignore the shader if texs is null.
1007 if (NULL == texs) {
1008 if (!this->skPaint2GrPaintNoShader(paint, false, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001009 return;
1010 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001011 } else {
reed@google.com1a2e8d22011-01-21 22:08:29 +00001012 if (!this->skPaint2GrPaintShader(paint, &act,
1013 *draw.fMatrix,
bsalomon@google.com5782d712011-01-21 21:03:59 +00001014 &grPaint)) {
1015 return;
1016 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001017 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001018
1019 if (NULL != xmode && NULL != texs && NULL != colors) {
1020 SkXfermode::Mode mode;
1021 if (!SkXfermode::IsMode(xmode, &mode) ||
1022 SkXfermode::kMultiply_Mode != mode) {
1023 SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
1024#if 0
1025 return
1026#endif
1027 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001028 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001029
1030#if SK_SCALAR_IS_GR_SCALAR
1031 // even if GrColor and SkColor byte offsets match we need
1032 // to perform pre-multiply.
1033 if (NULL == colors) {
1034 fContext->drawVertices(grPaint,
1035 gVertexMode2PrimitiveType[vmode],
1036 vertexCount,
1037 (GrPoint*) vertices,
1038 (GrPoint*) texs,
1039 NULL,
1040 indices,
1041 indexCount);
1042 } else
1043#endif
1044 {
1045 SkTexCoordSource texSrc(texs);
1046 SkColorSource colSrc(colors);
1047 SkIndexSource idxSrc(indices, indexCount);
1048
1049 fContext->drawCustomVertices(grPaint,
1050 gVertexMode2PrimitiveType[vmode],
1051 SkPositionSource(vertices, vertexCount),
1052 (NULL == texs) ? NULL : &texSrc,
1053 (NULL == colors) ? NULL : &colSrc,
1054 (NULL == indices) ? NULL : &idxSrc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001055 }
1056}
1057
1058///////////////////////////////////////////////////////////////////////////////
1059
1060static void GlyphCacheAuxProc(void* data) {
1061 delete (GrFontScaler*)data;
1062}
1063
1064static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) {
1065 void* auxData;
1066 GrFontScaler* scaler = NULL;
1067 if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
1068 scaler = (GrFontScaler*)auxData;
1069 }
1070 if (NULL == scaler) {
1071 scaler = new SkGrFontScaler(cache);
1072 cache->setAuxProc(GlyphCacheAuxProc, scaler);
1073 }
1074 return scaler;
1075}
1076
1077static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
1078 SkFixed fx, SkFixed fy,
1079 const SkGlyph& glyph) {
1080 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1081
1082 GrSkDrawProcs* procs = (GrSkDrawProcs*)state.fDraw->fProcs;
1083
1084 if (NULL == procs->fFontScaler) {
1085 procs->fFontScaler = get_gr_font_scaler(state.fCache);
1086 }
1087 procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0),
1088 SkIntToFixed(SkFixedFloor(fx)), fy,
1089 procs->fFontScaler);
1090}
1091
bsalomon@google.com5782d712011-01-21 21:03:59 +00001092SkDrawProcs* SkGpuDevice::initDrawForText(GrTextContext* context) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001093
1094 // deferred allocation
1095 if (NULL == fDrawProcs) {
1096 fDrawProcs = new GrSkDrawProcs;
1097 fDrawProcs->fD1GProc = SkGPU_Draw1Glyph;
1098 fDrawProcs->fContext = fContext;
1099 }
1100
1101 // init our (and GL's) state
1102 fDrawProcs->fTextContext = context;
1103 fDrawProcs->fFontScaler = NULL;
1104 return fDrawProcs;
1105}
1106
1107void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
1108 size_t byteLength, SkScalar x, SkScalar y,
1109 const SkPaint& paint) {
1110 CHECK_SHOULD_DRAW(draw);
1111
1112 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1113 // this guy will just call our drawPath()
1114 draw.drawText((const char*)text, byteLength, x, y, paint);
1115 } else {
1116 SkAutoExtMatrix aem(draw.fExtMatrix);
1117 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001118
1119 GrPaint grPaint;
1120 SkAutoCachedTexture act;
1121
1122 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1123 return;
1124 }
1125 GrTextContext context(fContext, grPaint, aem.extMatrix());
1126 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001127 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
1128 }
1129}
1130
1131void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
1132 size_t byteLength, const SkScalar pos[],
1133 SkScalar constY, int scalarsPerPos,
1134 const SkPaint& paint) {
1135 CHECK_SHOULD_DRAW(draw);
1136
1137 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1138 // this guy will just call our drawPath()
1139 draw.drawPosText((const char*)text, byteLength, pos, constY,
1140 scalarsPerPos, paint);
1141 } else {
1142 SkAutoExtMatrix aem(draw.fExtMatrix);
1143 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001144
1145 GrPaint grPaint;
1146 SkAutoCachedTexture act;
1147 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1148 return;
1149 }
1150
1151 GrTextContext context(fContext, grPaint, aem.extMatrix());
1152 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001153 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
1154 scalarsPerPos, paint);
1155 }
1156}
1157
1158void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
1159 size_t len, const SkPath& path,
1160 const SkMatrix* m, const SkPaint& paint) {
1161 CHECK_SHOULD_DRAW(draw);
1162
1163 SkASSERT(draw.fDevice == this);
1164 draw.drawTextOnPath((const char*)text, len, path, m, paint);
1165}
1166
1167///////////////////////////////////////////////////////////////////////////////
1168
1169SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
1170 const GrSamplerState& sampler,
1171 GrTexture** texture,
1172 bool forDeviceRenderTarget) {
1173 GrContext* ctx = this->context();
1174 uint32_t p0, p1;
1175 if (forDeviceRenderTarget) {
1176 p0 = p1 = -1;
1177 } else {
1178 p0 = bitmap.getGenerationID();
1179 p1 = bitmap.pixelRefOffset();
1180 }
1181
1182 GrTexture* newTexture = NULL;
1183 GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
1184 GrTextureEntry* entry = ctx->findAndLockTexture(&key, sampler);
1185
1186 if (NULL == entry) {
1187
1188 if (forDeviceRenderTarget) {
1189 const GrGpu::TextureDesc desc = {
1190 GrGpu::kRenderTarget_TextureFlag,
1191 GrGpu::kNone_AALevel,
1192 bitmap.width(),
1193 bitmap.height(),
1194 SkGr::Bitmap2PixelConfig(bitmap)
1195 };
1196 entry = ctx->createAndLockTexture(&key, sampler, desc, NULL, 0);
1197
1198 } else {
1199 entry = sk_gr_create_bitmap_texture(ctx, &key, sampler, bitmap);
1200 }
1201 if (NULL == entry) {
1202 GrPrintf("---- failed to create texture for cache [%d %d]\n",
1203 bitmap.width(), bitmap.height());
1204 }
1205 }
1206
1207 if (NULL != entry) {
1208 newTexture = entry->texture();
reed@google.comac10a2d2010-12-22 21:39:39 +00001209 if (texture) {
1210 *texture = newTexture;
1211 }
1212 // IMPORTANT: We can't allow another SkGpuDevice to get this
1213 // cache entry until this one is destroyed!
1214 if (forDeviceRenderTarget) {
1215 ctx->detachCachedTexture(entry);
1216 }
1217 }
1218 return (TexCache*)entry;
1219}
1220
1221void SkGpuDevice::unlockCachedTexture(TexCache* cache) {
1222 this->context()->unlockTexture((GrTextureEntry*)cache);
1223}
1224
reed@google.com7b201d22011-01-11 18:59:23 +00001225///////////////////////////////////////////////////////////////////////////////
1226
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001227SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context,
1228 GrRenderTarget* rootRenderTarget)
1229 : fContext(context) {
1230
1231 GrAssert(NULL != context);
1232 GrAssert(NULL != rootRenderTarget);
1233
1234 // check this now rather than passing this value to SkGpuDevice cons.
1235 // we want the rt that is bound *now* in the 3D API, not the one
1236 // at the time of newDevice.
1237 if (SkGpuDevice::Current3DApiRenderTarget() == rootRenderTarget) {
1238 fRootRenderTarget = context->createRenderTargetFrom3DApiState();
1239 } else {
1240 fRootRenderTarget = rootRenderTarget;
1241 rootRenderTarget->ref();
1242 }
reed@google.com7b201d22011-01-11 18:59:23 +00001243 context->ref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001244
reed@google.com7b201d22011-01-11 18:59:23 +00001245}
1246
1247SkGpuDeviceFactory::~SkGpuDeviceFactory() {
1248 fContext->unref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001249 fRootRenderTarget->unref();
reed@google.com7b201d22011-01-11 18:59:23 +00001250}
1251
1252SkDevice* SkGpuDeviceFactory::newDevice(SkCanvas*, SkBitmap::Config config,
1253 int width, int height,
1254 bool isOpaque, bool isLayer) {
1255 SkBitmap bm;
1256 bm.setConfig(config, width, height);
1257 bm.setIsOpaque(isOpaque);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001258 return new SkGpuDevice(fContext, bm, isLayer ? NULL : fRootRenderTarget);
reed@google.com7b201d22011-01-11 18:59:23 +00001259}
reed@google.comac10a2d2010-12-22 21:39:39 +00001260