blob: 606d197d2456abe4b22751708a16af2e6f62bd7f [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.com5782d712011-01-21 21:03:59 +0000317bool SkGpuDevice::bindDeviceAsTexture(GrPaint* paint, SkPoint* max) {
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 if (NULL != max) {
321 max->set(SkFixedToScalar((width() << 16) /
322 fTexture->allocWidth()),
323 SkFixedToScalar((height() << 16) /
324 fTexture->allocHeight()));
325 }
326 return true;
327 }
328 return false;
329}
330
331///////////////////////////////////////////////////////////////////////////////
332
bsalomon@google.com5782d712011-01-21 21:03:59 +0000333// must be in SkShader::BitmapTypeOrder
reed@google.comac10a2d2010-12-22 21:39:39 +0000334
bsalomon@google.com5782d712011-01-21 21:03:59 +0000335static const GrSamplerState::SampleMode sk_bmp_type_to_sample_mode[] = {
336 (GrSamplerState::SampleMode) -1, // kNone_BitmapType
337 GrSamplerState::kNormal_SampleMode, // kDefault_BitmapType
338 GrSamplerState::kRadial_SampleMode, // kRadial_BitmapType
339 GrSamplerState::kSweep_SampleMode, // kSweep_BitmapType
340 GrSamplerState::kRadial2_SampleMode, // kTwoPointRadial_BitmapType
341};
342
343bool SkGpuDevice::skPaint2GrPaintNoShader(const SkPaint& skPaint,
344 bool justAlpha,
345 GrPaint* grPaint) {
346
347 grPaint->fDither = skPaint.isDither();
348 grPaint->fAntiAlias = skPaint.isAntiAlias();
349
350 SkXfermode::Coeff sm = SkXfermode::kOne_Coeff;
351 SkXfermode::Coeff dm = SkXfermode::kISA_Coeff;
352
353 SkXfermode* mode = skPaint.getXfermode();
354 if (mode) {
355 if (!mode->asCoeff(&sm, &dm)) {
reed@google.com1a2e8d22011-01-21 22:08:29 +0000356 SkDEBUGCODE(SkDebugf("Unsupported xfer mode.\n");)
bsalomon@google.com5782d712011-01-21 21:03:59 +0000357#if 0
358 return false;
359#endif
360 }
361 }
362 grPaint->fSrcBlendCoeff = sk_blend_to_grblend(sm);
363 grPaint->fDstBlendCoeff = sk_blend_to_grblend(dm);
364
365 if (justAlpha) {
366 uint8_t alpha = skPaint.getAlpha();
367 grPaint->fColor = GrColorPackRGBA(alpha, alpha, alpha, alpha);
368 } else {
369 grPaint->fColor = SkGr::SkColor2GrColor(skPaint.getColor());
370 grPaint->setTexture(NULL);
371 }
372 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000373}
374
bsalomon@google.com5782d712011-01-21 21:03:59 +0000375bool SkGpuDevice::skPaint2GrPaintShader(const SkPaint& skPaint,
376 SkAutoCachedTexture* act,
377 const SkMatrix& ctm,
378 GrPaint* grPaint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000379
bsalomon@google.com5782d712011-01-21 21:03:59 +0000380 SkASSERT(NULL != act);
reed@google.comac10a2d2010-12-22 21:39:39 +0000381
bsalomon@google.com5782d712011-01-21 21:03:59 +0000382 SkShader* shader = skPaint.getShader();
reed@google.comac10a2d2010-12-22 21:39:39 +0000383 if (NULL == shader) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000384 return this->skPaint2GrPaintNoShader(skPaint, false, grPaint);
385 grPaint->setTexture(NULL);
386 return true;
387 } else if (!this->skPaint2GrPaintNoShader(skPaint, true, grPaint)) {
388 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000389 }
390
bsalomon@google.com5782d712011-01-21 21:03:59 +0000391 SkPaint noAlphaPaint(skPaint);
392 noAlphaPaint.setAlpha(255);
393 shader->setContext(this->accessBitmap(false), noAlphaPaint, ctm);
reed@google.comac10a2d2010-12-22 21:39:39 +0000394
reed@google.comac10a2d2010-12-22 21:39:39 +0000395 SkBitmap bitmap;
396 SkMatrix matrix;
397 SkShader::TileMode tileModes[2];
398 SkScalar twoPointParams[3];
399 SkShader::BitmapType bmptype = shader->asABitmap(&bitmap, &matrix,
400 tileModes, twoPointParams);
401
bsalomon@google.com5782d712011-01-21 21:03:59 +0000402 GrSamplerState::SampleMode sampleMode = sk_bmp_type_to_sample_mode[bmptype];
403 if (-1 == sampleMode) {
404 SkDebugf("shader->asABitmap() == kNone_BitmapType\n");
405 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000406 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000407 grPaint->fSampler.setSampleMode(sampleMode);
bsalomon@google.com0748f212011-02-01 22:56:16 +0000408 grPaint->fSampler.setFilter(skPaint.isFilterBitmap());
bsalomon@google.com5782d712011-01-21 21:03:59 +0000409 grPaint->fSampler.setWrapX(sk_tile_mode_to_grwrap(tileModes[0]));
410 grPaint->fSampler.setWrapY(sk_tile_mode_to_grwrap(tileModes[1]));
reed@google.comac10a2d2010-12-22 21:39:39 +0000411
412 if (GrSamplerState::kRadial2_SampleMode == sampleMode) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000413 grPaint->fSampler.setRadial2Params(twoPointParams[0],
414 twoPointParams[1],
415 twoPointParams[2] < 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000416 }
417
bsalomon@google.com5782d712011-01-21 21:03:59 +0000418 GrTexture* texture = act->set(this, bitmap, grPaint->fSampler);
reed@google.comac10a2d2010-12-22 21:39:39 +0000419 if (NULL == texture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000420 SkDebugf("Couldn't convert bitmap to texture.\n");
421 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000422 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000423 grPaint->setTexture(texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000424
425 // since our texture coords will be in local space, we wack the texture
426 // matrix to map them back into 0...1 before we load it
427 SkMatrix localM;
428 if (shader->getLocalMatrix(&localM)) {
429 SkMatrix inverse;
430 if (localM.invert(&inverse)) {
431 matrix.preConcat(inverse);
432 }
433 }
434 if (SkShader::kDefault_BitmapType == bmptype) {
435 GrScalar sx = (GR_Scalar1 * texture->contentWidth()) /
436 (bitmap.width() * texture->allocWidth());
437 GrScalar sy = (GR_Scalar1 * texture->contentHeight()) /
438 (bitmap.height() * texture->allocHeight());
439 matrix.postScale(sx, sy);
440
441 } else if (SkShader::kRadial_BitmapType == bmptype) {
442 GrScalar s = (GR_Scalar1 * texture->contentWidth()) /
443 (bitmap.width() * texture->allocWidth());
444 matrix.postScale(s, s);
445 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000446
bsalomon@google.com5782d712011-01-21 21:03:59 +0000447 GrMatrix grmat;
448 SkGr::SkMatrix2GrMatrix(matrix, &grPaint->fTextureMatrix);
449
450 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000451}
452
453///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com5782d712011-01-21 21:03:59 +0000454
455class SkPositionSource {
456public:
457 SkPositionSource(const SkPoint* points, int count)
458 : fPoints(points), fCount(count) {}
459
460 int count() const { return fCount; }
461
462 void writeValue(int i, GrPoint* dstPosition) const {
463 SkASSERT(i < fCount);
464 dstPosition->fX = SkScalarToGrScalar(fPoints[i].fX);
465 dstPosition->fY = SkScalarToGrScalar(fPoints[i].fY);
466 }
467private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000468 const SkPoint* fPoints;
bsalomon@google.com19628322011-02-03 21:30:17 +0000469 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000470};
471
472class SkTexCoordSource {
473public:
474 SkTexCoordSource(const SkPoint* coords)
475 : fCoords(coords) {}
476
477 void writeValue(int i, GrPoint* dstCoord) const {
478 dstCoord->fX = SkScalarToGrScalar(fCoords[i].fX);
479 dstCoord->fY = SkScalarToGrScalar(fCoords[i].fY);
480 }
481private:
482 const SkPoint* fCoords;
483};
484
485class SkColorSource {
486public:
487 SkColorSource(const SkColor* colors) : fColors(colors) {}
488
489 void writeValue(int i, GrColor* dstColor) const {
490 *dstColor = SkGr::SkColor2GrColor(fColors[i]);
491 }
492private:
493 const SkColor* fColors;
494};
495
496class SkIndexSource {
497public:
498 SkIndexSource(const uint16_t* indices, int count)
499 : fIndices(indices), fCount(count) {
500 }
501
502 int count() const { return fCount; }
503
504 void writeValue(int i, uint16_t* dstIndex) const {
505 *dstIndex = fIndices[i];
506 }
507
508private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000509 const uint16_t* fIndices;
bsalomon@google.com19628322011-02-03 21:30:17 +0000510 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000511};
512
513///////////////////////////////////////////////////////////////////////////////
514
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000515#if 0 // not currently being used so don't compile,
516
bsalomon@google.com5782d712011-01-21 21:03:59 +0000517// can be used for positions or texture coordinates
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000518
bsalomon@google.com5782d712011-01-21 21:03:59 +0000519class SkRectFanSource {
520public:
521 SkRectFanSource(const SkRect& rect) : fRect(rect) {}
522
523 int count() const { return 4; }
524
525 void writeValue(int i, GrPoint* dstPoint) const {
526 SkASSERT(i < 4);
527 dstPoint->fX = SkScalarToGrScalar((i % 3) ? fRect.fRight :
528 fRect.fLeft);
529 dstPoint->fY = SkScalarToGrScalar((i < 2) ? fRect.fTop :
530 fRect.fBottom);
531 }
532private:
533 const SkRect& fRect;
534};
535
536class SkIRectFanSource {
537public:
538 SkIRectFanSource(const SkIRect& rect) : fRect(rect) {}
539
540 int count() const { return 4; }
541
542 void writeValue(int i, GrPoint* dstPoint) const {
543 SkASSERT(i < 4);
544 dstPoint->fX = (i % 3) ? GrIntToScalar(fRect.fRight) :
545 GrIntToScalar(fRect.fLeft);
546 dstPoint->fY = (i < 2) ? GrIntToScalar(fRect.fTop) :
547 GrIntToScalar(fRect.fBottom);
548 }
549private:
550 const SkIRect& fRect;
551};
552
553class SkMatRectFanSource {
554public:
555 SkMatRectFanSource(const SkRect& rect, const SkMatrix& matrix)
556 : fRect(rect), fMatrix(matrix) {}
557
558 int count() const { return 4; }
559
560 void writeValue(int i, GrPoint* dstPoint) const {
561 SkASSERT(i < 4);
562
563#if SK_SCALAR_IS_GR_SCALAR
564 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
565 (i < 2) ? fRect.fTop : fRect.fBottom,
566 (SkPoint*)dstPoint);
567#else
568 SkPoint dst;
569 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
570 (i < 2) ? fRect.fTop : fRect.fBottom,
571 &dst);
572 dstPoint->fX = SkScalarToGrScalar(dst.fX);
573 dstPoint->fY = SkScalarToGrScalar(dst.fY);
574#endif
575 }
576private:
577 const SkRect& fRect;
578 const SkMatrix& fMatrix;
579};
580
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000581#endif
582
reed@google.comac10a2d2010-12-22 21:39:39 +0000583///////////////////////////////////////////////////////////////////////////////
584
585void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
586 CHECK_SHOULD_DRAW(draw);
587
bsalomon@google.com5782d712011-01-21 21:03:59 +0000588 GrPaint grPaint;
589 SkAutoCachedTexture act;
590 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000591 return;
592 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000593
594 fContext->drawPaint(grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000595}
596
597// must be in SkCanvas::PointMode order
bsalomon@google.com5782d712011-01-21 21:03:59 +0000598static const GrDrawTarget::PrimitiveType gPointMode2PrimtiveType[] = {
599 GrDrawTarget::kPoints_PrimitiveType,
600 GrDrawTarget::kLines_PrimitiveType,
601 GrDrawTarget::kLineStrip_PrimitiveType
reed@google.comac10a2d2010-12-22 21:39:39 +0000602};
603
604void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000605 size_t count, const SkPoint pts[], const SkPaint& paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000606 CHECK_SHOULD_DRAW(draw);
607
608 SkScalar width = paint.getStrokeWidth();
609 if (width < 0) {
610 return;
611 }
612
613 // we only handle hairlines here, else we let the SkDraw call our drawPath()
614 if (width > 0) {
615 draw.drawPoints(mode, count, pts, paint, true);
616 return;
617 }
618
bsalomon@google.com5782d712011-01-21 21:03:59 +0000619 GrPaint grPaint;
620 SkAutoCachedTexture act;
621 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000622 return;
623 }
624
reed@google.comac10a2d2010-12-22 21:39:39 +0000625#if SK_SCALAR_IS_GR_SCALAR
bsalomon@google.com5782d712011-01-21 21:03:59 +0000626 fContext->drawVertices(grPaint,
627 gPointMode2PrimtiveType[mode],
628 count,
629 (GrPoint*)pts,
630 NULL,
631 NULL,
632 NULL,
633 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000634#else
bsalomon@google.com5782d712011-01-21 21:03:59 +0000635 fContext->drawCustomVertices(grPaint,
636 gPointMode2PrimtiveType[mode],
637 SkPositionSource(pts, count));
reed@google.comac10a2d2010-12-22 21:39:39 +0000638#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000639}
640
641void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
642 const SkPaint& paint) {
643 CHECK_SHOULD_DRAW(draw);
644
645 bool doStroke = paint.getStyle() == SkPaint::kStroke_Style;
646 SkScalar width = paint.getStrokeWidth();
647
648 /*
649 We have special code for hairline strokes, miter-strokes, and fills.
reed@google.com69302852011-02-16 18:08:07 +0000650 Anything else we just call our path code.
reed@google.comac10a2d2010-12-22 21:39:39 +0000651 */
reed@google.com69302852011-02-16 18:08:07 +0000652 bool usePath = doStroke && width > 0 &&
653 paint.getStrokeJoin() != SkPaint::kMiter_Join;
654 // another reason we might need to call drawPath...
655 if (paint.getMaskFilter()) {
656 usePath = true;
657 }
658
659 if (usePath) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000660 SkPath path;
661 path.addRect(rect);
662 this->drawPath(draw, path, paint, NULL, true);
663 return;
664 }
665
bsalomon@google.com5782d712011-01-21 21:03:59 +0000666 GrPaint grPaint;
667 SkAutoCachedTexture act;
668 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000669 return;
670 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000671 fContext->drawRect(grPaint, Sk2Gr(rect), doStroke ? width : -1);
reed@google.comac10a2d2010-12-22 21:39:39 +0000672}
673
reed@google.com69302852011-02-16 18:08:07 +0000674#include "SkMaskFilter.h"
675#include "SkBounder.h"
676
reed@google.com69302852011-02-16 18:08:07 +0000677static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
678 SkMaskFilter* filter, const SkMatrix& matrix,
679 const SkRegion& clip, SkBounder* bounder,
680 GrPaint* grp) {
681 SkMask srcM, dstM;
682
683 if (!SkDraw::DrawToMask(path, &clip.getBounds(), filter, &matrix, &srcM,
684 SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
685 return false;
686 }
687
688 SkAutoMaskImage autoSrc(&srcM, false);
689
690 if (!filter->filterMask(&dstM, srcM, matrix, NULL)) {
691 return false;
692 }
693 // this will free-up dstM when we're done (allocated in filterMask())
694 SkAutoMaskImage autoDst(&dstM, false);
695
696 if (clip.quickReject(dstM.fBounds)) {
697 return false;
698 }
699 if (bounder && !bounder->doIRect(dstM.fBounds)) {
700 return false;
701 }
702
703 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
704 // the current clip (and identity matrix) and grpaint settings
705
reed@google.com0c219b62011-02-16 21:31:18 +0000706 GrAutoMatrix avm(context, GrMatrix::I());
reed@google.com69302852011-02-16 18:08:07 +0000707
708 const GrGpu::TextureDesc desc = {
709 0,
710 GrGpu::kNone_AALevel,
711 dstM.fBounds.width(),
712 dstM.fBounds.height(),
713 GrTexture::kAlpha_8_PixelConfig
714 };
715
716 GrTexture* texture = context->createUncachedTexture(desc, dstM.fImage,
717 dstM.fRowBytes);
718 if (NULL == texture) {
719 return false;
720 }
721
reed@google.com0c219b62011-02-16 21:31:18 +0000722 grp->setTexture(texture);
723 texture->unref();
724 grp->fSampler.setClampNoFilter();
725 grp->fTextureMatrix.setIdentity();
reed@google.com69302852011-02-16 18:08:07 +0000726
727 SkPoint max;
728 max.set(SkFixedToScalar((texture->contentWidth() << 16) /
729 texture->allocWidth()),
730 SkFixedToScalar((texture->contentHeight() << 16) /
731 texture->allocHeight()));
732
reed@google.com0c219b62011-02-16 21:31:18 +0000733 GrRect r;
734 r.setLTRB(GrIntToScalar(dstM.fBounds.fLeft),
735 GrIntToScalar(dstM.fBounds.fTop),
736 GrIntToScalar(dstM.fBounds.fRight),
737 GrIntToScalar(dstM.fBounds.fBottom));
738 context->drawRectToRect(*grp, r, GrRect(0, 0, max.fX, max.fY));
reed@google.com69302852011-02-16 18:08:07 +0000739 return true;
740}
reed@google.com69302852011-02-16 18:08:07 +0000741
reed@google.com0c219b62011-02-16 21:31:18 +0000742void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
reed@google.comac10a2d2010-12-22 21:39:39 +0000743 const SkPaint& paint, const SkMatrix* prePathMatrix,
744 bool pathIsMutable) {
745 CHECK_SHOULD_DRAW(draw);
746
bsalomon@google.com5782d712011-01-21 21:03:59 +0000747 GrPaint grPaint;
748 SkAutoCachedTexture act;
749 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000750 return;
751 }
752
reed@google.com0c219b62011-02-16 21:31:18 +0000753 // BEGIN lift from SkDraw::drawPath()
754
755 SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
756 bool doFill = true;
757 SkPath tmpPath;
758 SkMatrix tmpMatrix;
759 const SkMatrix* matrix = draw.fMatrix;
reed@google.comac10a2d2010-12-22 21:39:39 +0000760
761 if (prePathMatrix) {
reed@google.com0c219b62011-02-16 21:31:18 +0000762 if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style ||
763 paint.getRasterizer()) {
764 SkPath* result = pathPtr;
765
766 if (!pathIsMutable) {
767 result = &tmpPath;
768 pathIsMutable = true;
769 }
770 pathPtr->transform(*prePathMatrix, result);
771 pathPtr = result;
reed@google.comac10a2d2010-12-22 21:39:39 +0000772 } else {
reed@google.com0c219b62011-02-16 21:31:18 +0000773 if (!tmpMatrix.setConcat(*matrix, *prePathMatrix)) {
774 // overflow
775 return;
776 }
777 matrix = &tmpMatrix;
reed@google.comac10a2d2010-12-22 21:39:39 +0000778 }
779 }
reed@google.com0c219b62011-02-16 21:31:18 +0000780 // at this point we're done with prePathMatrix
781 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
reed@google.comac10a2d2010-12-22 21:39:39 +0000782
reed@google.com0c219b62011-02-16 21:31:18 +0000783 if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) {
784 doFill = paint.getFillPath(*pathPtr, &tmpPath);
785 pathPtr = &tmpPath;
786 }
787
788 // END lift from SkDraw::drawPath()
789
reed@google.com69302852011-02-16 18:08:07 +0000790 if (paint.getMaskFilter()) {
reed@google.com0c219b62011-02-16 21:31:18 +0000791 // avoid possibly allocating a new path in transform if we can
792 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
793
794 // transform the path into device space
795 pathPtr->transform(*matrix, devPathPtr);
796
797 drawWithMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
reed@google.com69302852011-02-16 18:08:07 +0000798 *draw.fMatrix, *draw.fClip, draw.fBounder, &grPaint);
799 return;
800 }
reed@google.com69302852011-02-16 18:08:07 +0000801
reed@google.comac10a2d2010-12-22 21:39:39 +0000802 GrContext::PathFills fill = GrContext::kHairLine_PathFill;
803
reed@google.com0c219b62011-02-16 21:31:18 +0000804 if (doFill) {
805 switch (pathPtr->getFillType()) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000806 case SkPath::kWinding_FillType:
807 fill = GrContext::kWinding_PathFill;
808 break;
809 case SkPath::kEvenOdd_FillType:
810 fill = GrContext::kEvenOdd_PathFill;
811 break;
812 case SkPath::kInverseWinding_FillType:
813 fill = GrContext::kInverseWinding_PathFill;
814 break;
815 case SkPath::kInverseEvenOdd_FillType:
816 fill = GrContext::kInverseEvenOdd_PathFill;
817 break;
818 default:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000819 SkDebugf("Unsupported path fill type\n");
reed@google.comac10a2d2010-12-22 21:39:39 +0000820 return;
821 }
822 }
823
reed@google.com0c219b62011-02-16 21:31:18 +0000824 SkGrPathIter iter(*pathPtr);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000825 fContext->drawPath(grPaint, &iter, fill);
reed@google.comac10a2d2010-12-22 21:39:39 +0000826}
827
reed@google.comac10a2d2010-12-22 21:39:39 +0000828void SkGpuDevice::drawBitmap(const SkDraw& draw,
829 const SkBitmap& bitmap,
830 const SkIRect* srcRectPtr,
831 const SkMatrix& m,
832 const SkPaint& paint) {
833 CHECK_SHOULD_DRAW(draw);
834
835 SkIRect srcRect;
836 if (NULL == srcRectPtr) {
837 srcRect.set(0, 0, bitmap.width(), bitmap.height());
838 } else {
839 srcRect = *srcRectPtr;
840 }
841
bsalomon@google.com5782d712011-01-21 21:03:59 +0000842 GrPaint grPaint;
843 if (!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
844 return;
845 }
846 grPaint.fSampler.setFilter(paint.isFilterBitmap());
847
reed@google.com02a7e6c2011-01-28 21:21:49 +0000848 const int maxTextureDim = fContext->getMaxTextureDimension();
849 if (bitmap.getTexture() || (bitmap.width() <= maxTextureDim &&
850 bitmap.height() <= maxTextureDim)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000851 // take the fast case
bsalomon@google.com5782d712011-01-21 21:03:59 +0000852 this->internalDrawBitmap(draw, bitmap, srcRect, m, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000853 return;
854 }
855
856 // undo the translate done by SkCanvas
857 int DX = SkMax32(0, srcRect.fLeft);
858 int DY = SkMax32(0, srcRect.fTop);
859 // compute clip bounds in local coordinates
860 SkIRect clipRect;
861 {
862 SkRect r;
863 r.set(draw.fClip->getBounds());
864 SkMatrix matrix, inverse;
865 matrix.setConcat(*draw.fMatrix, m);
866 if (!matrix.invert(&inverse)) {
867 return;
868 }
869 inverse.mapRect(&r);
870 r.roundOut(&clipRect);
871 // apply the canvas' translate to our local clip
872 clipRect.offset(DX, DY);
873 }
874
reed@google.com02a7e6c2011-01-28 21:21:49 +0000875 int nx = bitmap.width() / maxTextureDim;
876 int ny = bitmap.height() / maxTextureDim;
reed@google.comac10a2d2010-12-22 21:39:39 +0000877 for (int x = 0; x <= nx; x++) {
878 for (int y = 0; y <= ny; y++) {
879 SkIRect tileR;
reed@google.com02a7e6c2011-01-28 21:21:49 +0000880 tileR.set(x * maxTextureDim, y * maxTextureDim,
881 (x + 1) * maxTextureDim, (y + 1) * maxTextureDim);
reed@google.comac10a2d2010-12-22 21:39:39 +0000882 if (!SkIRect::Intersects(tileR, clipRect)) {
883 continue;
884 }
885
886 SkIRect srcR = tileR;
887 if (!srcR.intersect(srcRect)) {
888 continue;
889 }
890
891 SkBitmap tmpB;
892 if (bitmap.extractSubset(&tmpB, tileR)) {
893 // now offset it to make it "local" to our tmp bitmap
894 srcR.offset(-tileR.fLeft, -tileR.fTop);
895
896 SkMatrix tmpM(m);
897 {
898 int dx = tileR.fLeft - DX + SkMax32(0, srcR.fLeft);
899 int dy = tileR.fTop - DY + SkMax32(0, srcR.fTop);
900 tmpM.preTranslate(SkIntToScalar(dx), SkIntToScalar(dy));
901 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000902 this->internalDrawBitmap(draw, tmpB, srcR, tmpM, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000903 }
904 }
905 }
906}
907
908/*
909 * This is called by drawBitmap(), which has to handle images that may be too
910 * large to be represented by a single texture.
911 *
bsalomon@google.com5782d712011-01-21 21:03:59 +0000912 * internalDrawBitmap assumes that the specified bitmap will fit in a texture
913 * and that non-texture portion of the GrPaint has already been setup.
reed@google.comac10a2d2010-12-22 21:39:39 +0000914 */
915void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
916 const SkBitmap& bitmap,
917 const SkIRect& srcRect,
918 const SkMatrix& m,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000919 GrPaint* grPaint) {
reed@google.com02a7e6c2011-01-28 21:21:49 +0000920 SkASSERT(bitmap.width() <= fContext->getMaxTextureDimension() &&
921 bitmap.height() <= fContext->getMaxTextureDimension());
reed@google.comac10a2d2010-12-22 21:39:39 +0000922
923 SkAutoLockPixels alp(bitmap);
924 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
925 return;
926 }
927
bsalomon@google.com5782d712011-01-21 21:03:59 +0000928 grPaint->fSampler.setWrapX(GrSamplerState::kClamp_WrapMode);
929 grPaint->fSampler.setWrapY(GrSamplerState::kClamp_WrapMode);
930 grPaint->fSampler.setSampleMode(GrSamplerState::kNormal_SampleMode);
reed@google.comac10a2d2010-12-22 21:39:39 +0000931
932 GrTexture* texture;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000933 SkAutoCachedTexture act(this, bitmap, grPaint->fSampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000934 if (NULL == texture) {
935 return;
936 }
937
bsalomon@google.com5782d712011-01-21 21:03:59 +0000938 grPaint->setTexture(texture);
939 grPaint->fTextureMatrix.setIdentity();
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000940 GrRect dstRect(0, 0, GrIntToScalar(srcRect.width()), GrIntToScalar(srcRect.height()));
941 GrRect paintRect(GrIntToScalar(srcRect.fLeft) / texture->allocWidth(),
942 GrIntToScalar(srcRect.fTop) / texture->allocHeight(),
943 GrIntToScalar(srcRect.fRight) / texture->allocWidth(),
944 GrIntToScalar(srcRect.fBottom) / texture->allocHeight());
reed@google.comac10a2d2010-12-22 21:39:39 +0000945
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000946 GrMatrix grMat;
947 SkGr::SkMatrix2GrMatrix(m, &grMat);
reed@google.comac10a2d2010-12-22 21:39:39 +0000948
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000949 fContext->drawRectToRect(*grPaint, dstRect, paintRect, &grMat);
reed@google.comac10a2d2010-12-22 21:39:39 +0000950}
951
952void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
953 int left, int top, const SkPaint& paint) {
954 CHECK_SHOULD_DRAW(draw);
955
956 SkAutoLockPixels alp(bitmap);
957 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
958 return;
959 }
960
bsalomon@google.com5782d712011-01-21 21:03:59 +0000961 GrPaint grPaint;
962 if(!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
963 return;
964 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000965
bsalomon@google.com5782d712011-01-21 21:03:59 +0000966 GrAutoMatrix avm(fContext, GrMatrix::I());
967
968 GrTexture* texture;
969 grPaint.fSampler.setClampNoFilter();
970 SkAutoCachedTexture act(this, bitmap, grPaint.fSampler, &texture);
971
972 grPaint.fTextureMatrix.setIdentity();
973 grPaint.setTexture(texture);
974
975 SkPoint max;
reed@google.comac10a2d2010-12-22 21:39:39 +0000976 max.set(SkFixedToScalar((texture->contentWidth() << 16) /
977 texture->allocWidth()),
978 SkFixedToScalar((texture->contentHeight() << 16) /
979 texture->allocHeight()));
bsalomon@google.com5782d712011-01-21 21:03:59 +0000980
981 fContext->drawRectToRect(grPaint,
982 GrRect(GrIntToScalar(left), GrIntToScalar(top),
983 GrIntToScalar(left + bitmap.width()),
984 GrIntToScalar(top + bitmap.height())),
985 GrRect(0, 0, max.fX, max.fY));
reed@google.comac10a2d2010-12-22 21:39:39 +0000986}
987
988void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
989 int x, int y, const SkPaint& paint) {
990 CHECK_SHOULD_DRAW(draw);
991
992 SkPoint max;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000993 GrPaint grPaint;
994 if (!((SkGpuDevice*)dev)->bindDeviceAsTexture(&grPaint, &max) ||
995 !this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
996 return;
reed@google.comac10a2d2010-12-22 21:39:39 +0000997 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000998
999 SkASSERT(NULL != grPaint.getTexture());
1000
1001 const SkBitmap& bm = dev->accessBitmap(false);
1002 int w = bm.width();
1003 int h = bm.height();
1004
1005 GrAutoMatrix avm(fContext, GrMatrix::I());
1006
1007 grPaint.fSampler.setClampNoFilter();
1008 grPaint.fTextureMatrix.setIdentity();
1009
1010 fContext->drawRectToRect(grPaint,
reed@google.com1a2e8d22011-01-21 22:08:29 +00001011 GrRect(GrIntToScalar(x),
1012 GrIntToScalar(y),
1013 GrIntToScalar(x + w),
bsalomon@google.com5782d712011-01-21 21:03:59 +00001014 GrIntToScalar(y + h)),
reed@google.com1a2e8d22011-01-21 22:08:29 +00001015 GrRect(0,
1016 0,
1017 GrIntToScalar(max.fX),
bsalomon@google.com5782d712011-01-21 21:03:59 +00001018 GrIntToScalar(max.fY)));
reed@google.comac10a2d2010-12-22 21:39:39 +00001019}
1020
1021///////////////////////////////////////////////////////////////////////////////
1022
1023// must be in SkCanvas::VertexMode order
bsalomon@google.com5782d712011-01-21 21:03:59 +00001024static const GrDrawTarget::PrimitiveType gVertexMode2PrimitiveType[] = {
1025 GrDrawTarget::kTriangles_PrimitiveType,
1026 GrDrawTarget::kTriangleStrip_PrimitiveType,
1027 GrDrawTarget::kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +00001028};
1029
1030void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
1031 int vertexCount, const SkPoint vertices[],
1032 const SkPoint texs[], const SkColor colors[],
1033 SkXfermode* xmode,
1034 const uint16_t indices[], int indexCount,
1035 const SkPaint& paint) {
1036 CHECK_SHOULD_DRAW(draw);
1037
bsalomon@google.com5782d712011-01-21 21:03:59 +00001038 GrPaint grPaint;
1039 SkAutoCachedTexture act;
1040 // we ignore the shader if texs is null.
1041 if (NULL == texs) {
1042 if (!this->skPaint2GrPaintNoShader(paint, false, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001043 return;
1044 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001045 } else {
reed@google.com1a2e8d22011-01-21 22:08:29 +00001046 if (!this->skPaint2GrPaintShader(paint, &act,
1047 *draw.fMatrix,
bsalomon@google.com5782d712011-01-21 21:03:59 +00001048 &grPaint)) {
1049 return;
1050 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001051 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001052
1053 if (NULL != xmode && NULL != texs && NULL != colors) {
1054 SkXfermode::Mode mode;
1055 if (!SkXfermode::IsMode(xmode, &mode) ||
1056 SkXfermode::kMultiply_Mode != mode) {
1057 SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
1058#if 0
1059 return
1060#endif
1061 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001062 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001063
1064#if SK_SCALAR_IS_GR_SCALAR
1065 // even if GrColor and SkColor byte offsets match we need
1066 // to perform pre-multiply.
1067 if (NULL == colors) {
1068 fContext->drawVertices(grPaint,
1069 gVertexMode2PrimitiveType[vmode],
1070 vertexCount,
1071 (GrPoint*) vertices,
1072 (GrPoint*) texs,
1073 NULL,
1074 indices,
1075 indexCount);
1076 } else
1077#endif
1078 {
1079 SkTexCoordSource texSrc(texs);
1080 SkColorSource colSrc(colors);
1081 SkIndexSource idxSrc(indices, indexCount);
1082
1083 fContext->drawCustomVertices(grPaint,
1084 gVertexMode2PrimitiveType[vmode],
1085 SkPositionSource(vertices, vertexCount),
1086 (NULL == texs) ? NULL : &texSrc,
1087 (NULL == colors) ? NULL : &colSrc,
1088 (NULL == indices) ? NULL : &idxSrc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001089 }
1090}
1091
1092///////////////////////////////////////////////////////////////////////////////
1093
1094static void GlyphCacheAuxProc(void* data) {
1095 delete (GrFontScaler*)data;
1096}
1097
1098static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) {
1099 void* auxData;
1100 GrFontScaler* scaler = NULL;
1101 if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
1102 scaler = (GrFontScaler*)auxData;
1103 }
1104 if (NULL == scaler) {
1105 scaler = new SkGrFontScaler(cache);
1106 cache->setAuxProc(GlyphCacheAuxProc, scaler);
1107 }
1108 return scaler;
1109}
1110
1111static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
1112 SkFixed fx, SkFixed fy,
1113 const SkGlyph& glyph) {
1114 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1115
1116 GrSkDrawProcs* procs = (GrSkDrawProcs*)state.fDraw->fProcs;
1117
1118 if (NULL == procs->fFontScaler) {
1119 procs->fFontScaler = get_gr_font_scaler(state.fCache);
1120 }
1121 procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0),
1122 SkIntToFixed(SkFixedFloor(fx)), fy,
1123 procs->fFontScaler);
1124}
1125
bsalomon@google.com5782d712011-01-21 21:03:59 +00001126SkDrawProcs* SkGpuDevice::initDrawForText(GrTextContext* context) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001127
1128 // deferred allocation
1129 if (NULL == fDrawProcs) {
1130 fDrawProcs = new GrSkDrawProcs;
1131 fDrawProcs->fD1GProc = SkGPU_Draw1Glyph;
1132 fDrawProcs->fContext = fContext;
1133 }
1134
1135 // init our (and GL's) state
1136 fDrawProcs->fTextContext = context;
1137 fDrawProcs->fFontScaler = NULL;
1138 return fDrawProcs;
1139}
1140
1141void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
1142 size_t byteLength, SkScalar x, SkScalar y,
1143 const SkPaint& paint) {
1144 CHECK_SHOULD_DRAW(draw);
1145
1146 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1147 // this guy will just call our drawPath()
1148 draw.drawText((const char*)text, byteLength, x, y, paint);
1149 } else {
1150 SkAutoExtMatrix aem(draw.fExtMatrix);
1151 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001152
1153 GrPaint grPaint;
1154 SkAutoCachedTexture act;
1155
1156 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1157 return;
1158 }
1159 GrTextContext context(fContext, grPaint, aem.extMatrix());
1160 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001161 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
1162 }
1163}
1164
1165void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
1166 size_t byteLength, const SkScalar pos[],
1167 SkScalar constY, int scalarsPerPos,
1168 const SkPaint& paint) {
1169 CHECK_SHOULD_DRAW(draw);
1170
1171 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1172 // this guy will just call our drawPath()
1173 draw.drawPosText((const char*)text, byteLength, pos, constY,
1174 scalarsPerPos, paint);
1175 } else {
1176 SkAutoExtMatrix aem(draw.fExtMatrix);
1177 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001178
1179 GrPaint grPaint;
1180 SkAutoCachedTexture act;
1181 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1182 return;
1183 }
1184
1185 GrTextContext context(fContext, grPaint, aem.extMatrix());
1186 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001187 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
1188 scalarsPerPos, paint);
1189 }
1190}
1191
1192void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
1193 size_t len, const SkPath& path,
1194 const SkMatrix* m, const SkPaint& paint) {
1195 CHECK_SHOULD_DRAW(draw);
1196
1197 SkASSERT(draw.fDevice == this);
1198 draw.drawTextOnPath((const char*)text, len, path, m, paint);
1199}
1200
1201///////////////////////////////////////////////////////////////////////////////
1202
1203SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
1204 const GrSamplerState& sampler,
1205 GrTexture** texture,
1206 bool forDeviceRenderTarget) {
1207 GrContext* ctx = this->context();
1208 uint32_t p0, p1;
1209 if (forDeviceRenderTarget) {
1210 p0 = p1 = -1;
1211 } else {
1212 p0 = bitmap.getGenerationID();
1213 p1 = bitmap.pixelRefOffset();
1214 }
1215
1216 GrTexture* newTexture = NULL;
1217 GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
1218 GrTextureEntry* entry = ctx->findAndLockTexture(&key, sampler);
1219
1220 if (NULL == entry) {
1221
1222 if (forDeviceRenderTarget) {
1223 const GrGpu::TextureDesc desc = {
1224 GrGpu::kRenderTarget_TextureFlag,
1225 GrGpu::kNone_AALevel,
1226 bitmap.width(),
1227 bitmap.height(),
1228 SkGr::Bitmap2PixelConfig(bitmap)
1229 };
1230 entry = ctx->createAndLockTexture(&key, sampler, desc, NULL, 0);
1231
1232 } else {
1233 entry = sk_gr_create_bitmap_texture(ctx, &key, sampler, bitmap);
1234 }
1235 if (NULL == entry) {
1236 GrPrintf("---- failed to create texture for cache [%d %d]\n",
1237 bitmap.width(), bitmap.height());
1238 }
1239 }
1240
1241 if (NULL != entry) {
1242 newTexture = entry->texture();
reed@google.comac10a2d2010-12-22 21:39:39 +00001243 if (texture) {
1244 *texture = newTexture;
1245 }
1246 // IMPORTANT: We can't allow another SkGpuDevice to get this
1247 // cache entry until this one is destroyed!
1248 if (forDeviceRenderTarget) {
1249 ctx->detachCachedTexture(entry);
1250 }
1251 }
1252 return (TexCache*)entry;
1253}
1254
1255void SkGpuDevice::unlockCachedTexture(TexCache* cache) {
1256 this->context()->unlockTexture((GrTextureEntry*)cache);
1257}
1258
reed@google.com7b201d22011-01-11 18:59:23 +00001259///////////////////////////////////////////////////////////////////////////////
1260
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001261SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context,
1262 GrRenderTarget* rootRenderTarget)
1263 : fContext(context) {
1264
1265 GrAssert(NULL != context);
1266 GrAssert(NULL != rootRenderTarget);
1267
1268 // check this now rather than passing this value to SkGpuDevice cons.
1269 // we want the rt that is bound *now* in the 3D API, not the one
1270 // at the time of newDevice.
1271 if (SkGpuDevice::Current3DApiRenderTarget() == rootRenderTarget) {
1272 fRootRenderTarget = context->createRenderTargetFrom3DApiState();
1273 } else {
1274 fRootRenderTarget = rootRenderTarget;
1275 rootRenderTarget->ref();
1276 }
reed@google.com7b201d22011-01-11 18:59:23 +00001277 context->ref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001278
reed@google.com7b201d22011-01-11 18:59:23 +00001279}
1280
1281SkGpuDeviceFactory::~SkGpuDeviceFactory() {
1282 fContext->unref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001283 fRootRenderTarget->unref();
reed@google.com7b201d22011-01-11 18:59:23 +00001284}
1285
1286SkDevice* SkGpuDeviceFactory::newDevice(SkCanvas*, SkBitmap::Config config,
1287 int width, int height,
1288 bool isOpaque, bool isLayer) {
1289 SkBitmap bm;
1290 bm.setConfig(config, width, height);
1291 bm.setIsOpaque(isOpaque);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001292 return new SkGpuDevice(fContext, bm, isLayer ? NULL : fRootRenderTarget);
reed@google.com7b201d22011-01-11 18:59:23 +00001293}
reed@google.comac10a2d2010-12-22 21:39:39 +00001294