blob: 11f030eaac40a3a4ac97a91d82ff1b5cd79d65f0 [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)) {
356 SkDebugf("Unsupported xfer mode.\n");
357#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);
reed@google.comac10a2d2010-12-22 21:39:39 +0000408
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:
468 int fCount;
469 const SkPoint* fPoints;
470};
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:
509 int fCount;
510 const uint16_t* fIndices;
511};
512
513///////////////////////////////////////////////////////////////////////////////
514
515// can be used for positions or texture coordinates
516class SkRectFanSource {
517public:
518 SkRectFanSource(const SkRect& rect) : fRect(rect) {}
519
520 int count() const { return 4; }
521
522 void writeValue(int i, GrPoint* dstPoint) const {
523 SkASSERT(i < 4);
524 dstPoint->fX = SkScalarToGrScalar((i % 3) ? fRect.fRight :
525 fRect.fLeft);
526 dstPoint->fY = SkScalarToGrScalar((i < 2) ? fRect.fTop :
527 fRect.fBottom);
528 }
529private:
530 const SkRect& fRect;
531};
532
533class SkIRectFanSource {
534public:
535 SkIRectFanSource(const SkIRect& rect) : fRect(rect) {}
536
537 int count() const { return 4; }
538
539 void writeValue(int i, GrPoint* dstPoint) const {
540 SkASSERT(i < 4);
541 dstPoint->fX = (i % 3) ? GrIntToScalar(fRect.fRight) :
542 GrIntToScalar(fRect.fLeft);
543 dstPoint->fY = (i < 2) ? GrIntToScalar(fRect.fTop) :
544 GrIntToScalar(fRect.fBottom);
545 }
546private:
547 const SkIRect& fRect;
548};
549
550class SkMatRectFanSource {
551public:
552 SkMatRectFanSource(const SkRect& rect, const SkMatrix& matrix)
553 : fRect(rect), fMatrix(matrix) {}
554
555 int count() const { return 4; }
556
557 void writeValue(int i, GrPoint* dstPoint) const {
558 SkASSERT(i < 4);
559
560#if SK_SCALAR_IS_GR_SCALAR
561 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
562 (i < 2) ? fRect.fTop : fRect.fBottom,
563 (SkPoint*)dstPoint);
564#else
565 SkPoint dst;
566 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
567 (i < 2) ? fRect.fTop : fRect.fBottom,
568 &dst);
569 dstPoint->fX = SkScalarToGrScalar(dst.fX);
570 dstPoint->fY = SkScalarToGrScalar(dst.fY);
571#endif
572 }
573private:
574 const SkRect& fRect;
575 const SkMatrix& fMatrix;
576};
577
reed@google.comac10a2d2010-12-22 21:39:39 +0000578///////////////////////////////////////////////////////////////////////////////
579
580void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
581 CHECK_SHOULD_DRAW(draw);
582
bsalomon@google.com5782d712011-01-21 21:03:59 +0000583 GrPaint grPaint;
584 SkAutoCachedTexture act;
585 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000586 return;
587 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000588
589 fContext->drawPaint(grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000590}
591
592// must be in SkCanvas::PointMode order
bsalomon@google.com5782d712011-01-21 21:03:59 +0000593static const GrDrawTarget::PrimitiveType gPointMode2PrimtiveType[] = {
594 GrDrawTarget::kPoints_PrimitiveType,
595 GrDrawTarget::kLines_PrimitiveType,
596 GrDrawTarget::kLineStrip_PrimitiveType
reed@google.comac10a2d2010-12-22 21:39:39 +0000597};
598
599void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000600 size_t count, const SkPoint pts[], const SkPaint& paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000601 CHECK_SHOULD_DRAW(draw);
602
603 SkScalar width = paint.getStrokeWidth();
604 if (width < 0) {
605 return;
606 }
607
608 // we only handle hairlines here, else we let the SkDraw call our drawPath()
609 if (width > 0) {
610 draw.drawPoints(mode, count, pts, paint, true);
611 return;
612 }
613
bsalomon@google.com5782d712011-01-21 21:03:59 +0000614 GrPaint grPaint;
615 SkAutoCachedTexture act;
616 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000617 return;
618 }
619
reed@google.comac10a2d2010-12-22 21:39:39 +0000620#if SK_SCALAR_IS_GR_SCALAR
bsalomon@google.com5782d712011-01-21 21:03:59 +0000621 fContext->drawVertices(grPaint,
622 gPointMode2PrimtiveType[mode],
623 count,
624 (GrPoint*)pts,
625 NULL,
626 NULL,
627 NULL,
628 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000629#else
bsalomon@google.com5782d712011-01-21 21:03:59 +0000630 fContext->drawCustomVertices(grPaint,
631 gPointMode2PrimtiveType[mode],
632 SkPositionSource(pts, count));
reed@google.comac10a2d2010-12-22 21:39:39 +0000633#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000634}
635
636void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
637 const SkPaint& paint) {
638 CHECK_SHOULD_DRAW(draw);
639
640 bool doStroke = paint.getStyle() == SkPaint::kStroke_Style;
641 SkScalar width = paint.getStrokeWidth();
642
643 /*
644 We have special code for hairline strokes, miter-strokes, and fills.
645 Anything else we just call our path code. (i.e. non-miter thick stroke)
646 */
647 if (doStroke && width > 0 && paint.getStrokeJoin() != SkPaint::kMiter_Join) {
648 SkPath path;
649 path.addRect(rect);
650 this->drawPath(draw, path, paint, NULL, true);
651 return;
652 }
653
bsalomon@google.com5782d712011-01-21 21:03:59 +0000654 GrPaint grPaint;
655 SkAutoCachedTexture act;
656 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000657 return;
658 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000659 fContext->drawRect(grPaint, Sk2Gr(rect), doStroke ? width : -1);
reed@google.comac10a2d2010-12-22 21:39:39 +0000660}
661
662void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& path,
663 const SkPaint& paint, const SkMatrix* prePathMatrix,
664 bool pathIsMutable) {
665 CHECK_SHOULD_DRAW(draw);
666
bsalomon@google.com5782d712011-01-21 21:03:59 +0000667 GrPaint grPaint;
668 SkAutoCachedTexture act;
669 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000670 return;
671 }
672
673 const SkPath* pathPtr = &path;
674 SkPath tmpPath;
675
676 if (prePathMatrix) {
677 if (pathIsMutable) {
678 const_cast<SkPath*>(pathPtr)->transform(*prePathMatrix);
679 } else {
680 path.transform(*prePathMatrix, &tmpPath);
681 pathPtr = &tmpPath;
682 }
683 }
684
685 SkPath fillPath;
686 GrContext::PathFills fill = GrContext::kHairLine_PathFill;
687
688 if (paint.getFillPath(*pathPtr, &fillPath)) {
689 switch (fillPath.getFillType()) {
690 case SkPath::kWinding_FillType:
691 fill = GrContext::kWinding_PathFill;
692 break;
693 case SkPath::kEvenOdd_FillType:
694 fill = GrContext::kEvenOdd_PathFill;
695 break;
696 case SkPath::kInverseWinding_FillType:
697 fill = GrContext::kInverseWinding_PathFill;
698 break;
699 case SkPath::kInverseEvenOdd_FillType:
700 fill = GrContext::kInverseEvenOdd_PathFill;
701 break;
702 default:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000703 SkDebugf("Unsupported path fill type\n");
reed@google.comac10a2d2010-12-22 21:39:39 +0000704 return;
705 }
706 }
707
708 SkGrPathIter iter(fillPath);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000709 fContext->drawPath(grPaint, &iter, fill);
reed@google.comac10a2d2010-12-22 21:39:39 +0000710}
711
712/*
713 * This value must not exceed the GPU's texture dimension limit, but it can
714 * be smaller, if that helps avoid very large single textures hurting the
715 * cache.
716 */
717#define MAX_TEXTURE_DIM 512
718
719void SkGpuDevice::drawBitmap(const SkDraw& draw,
720 const SkBitmap& bitmap,
721 const SkIRect* srcRectPtr,
722 const SkMatrix& m,
723 const SkPaint& paint) {
724 CHECK_SHOULD_DRAW(draw);
725
726 SkIRect srcRect;
727 if (NULL == srcRectPtr) {
728 srcRect.set(0, 0, bitmap.width(), bitmap.height());
729 } else {
730 srcRect = *srcRectPtr;
731 }
732
bsalomon@google.com5782d712011-01-21 21:03:59 +0000733 GrPaint grPaint;
734 if (!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
735 return;
736 }
737 grPaint.fSampler.setFilter(paint.isFilterBitmap());
738
reed@google.comac10a2d2010-12-22 21:39:39 +0000739 if (bitmap.getTexture() || (bitmap.width() <= MAX_TEXTURE_DIM &&
740 bitmap.height() <= MAX_TEXTURE_DIM)) {
741 // take the fast case
bsalomon@google.com5782d712011-01-21 21:03:59 +0000742 this->internalDrawBitmap(draw, bitmap, srcRect, m, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000743 return;
744 }
745
746 // undo the translate done by SkCanvas
747 int DX = SkMax32(0, srcRect.fLeft);
748 int DY = SkMax32(0, srcRect.fTop);
749 // compute clip bounds in local coordinates
750 SkIRect clipRect;
751 {
752 SkRect r;
753 r.set(draw.fClip->getBounds());
754 SkMatrix matrix, inverse;
755 matrix.setConcat(*draw.fMatrix, m);
756 if (!matrix.invert(&inverse)) {
757 return;
758 }
759 inverse.mapRect(&r);
760 r.roundOut(&clipRect);
761 // apply the canvas' translate to our local clip
762 clipRect.offset(DX, DY);
763 }
764
765 int nx = bitmap.width() / MAX_TEXTURE_DIM;
766 int ny = bitmap.height() / MAX_TEXTURE_DIM;
767 for (int x = 0; x <= nx; x++) {
768 for (int y = 0; y <= ny; y++) {
769 SkIRect tileR;
770 tileR.set(x * MAX_TEXTURE_DIM, y * MAX_TEXTURE_DIM,
771 (x + 1) * MAX_TEXTURE_DIM, (y + 1) * MAX_TEXTURE_DIM);
772 if (!SkIRect::Intersects(tileR, clipRect)) {
773 continue;
774 }
775
776 SkIRect srcR = tileR;
777 if (!srcR.intersect(srcRect)) {
778 continue;
779 }
780
781 SkBitmap tmpB;
782 if (bitmap.extractSubset(&tmpB, tileR)) {
783 // now offset it to make it "local" to our tmp bitmap
784 srcR.offset(-tileR.fLeft, -tileR.fTop);
785
786 SkMatrix tmpM(m);
787 {
788 int dx = tileR.fLeft - DX + SkMax32(0, srcR.fLeft);
789 int dy = tileR.fTop - DY + SkMax32(0, srcR.fTop);
790 tmpM.preTranslate(SkIntToScalar(dx), SkIntToScalar(dy));
791 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000792 this->internalDrawBitmap(draw, tmpB, srcR, tmpM, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000793 }
794 }
795 }
796}
797
798/*
799 * This is called by drawBitmap(), which has to handle images that may be too
800 * large to be represented by a single texture.
801 *
bsalomon@google.com5782d712011-01-21 21:03:59 +0000802 * internalDrawBitmap assumes that the specified bitmap will fit in a texture
803 * and that non-texture portion of the GrPaint has already been setup.
reed@google.comac10a2d2010-12-22 21:39:39 +0000804 */
805void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
806 const SkBitmap& bitmap,
807 const SkIRect& srcRect,
808 const SkMatrix& m,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000809 GrPaint* grPaint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000810 SkASSERT(bitmap.width() <= MAX_TEXTURE_DIM &&
811 bitmap.height() <= MAX_TEXTURE_DIM);
812
813 SkAutoLockPixels alp(bitmap);
814 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
815 return;
816 }
817
bsalomon@google.com5782d712011-01-21 21:03:59 +0000818 grPaint->fSampler.setWrapX(GrSamplerState::kClamp_WrapMode);
819 grPaint->fSampler.setWrapY(GrSamplerState::kClamp_WrapMode);
820 grPaint->fSampler.setSampleMode(GrSamplerState::kNormal_SampleMode);
reed@google.comac10a2d2010-12-22 21:39:39 +0000821
822 GrTexture* texture;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000823 SkAutoCachedTexture act(this, bitmap, grPaint->fSampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000824 if (NULL == texture) {
825 return;
826 }
827
bsalomon@google.com5782d712011-01-21 21:03:59 +0000828 grPaint->setTexture(texture);
829 grPaint->fTextureMatrix.setIdentity();
reed@google.comac10a2d2010-12-22 21:39:39 +0000830
bsalomon@google.com5782d712011-01-21 21:03:59 +0000831 SkRect paintRect;
832 paintRect.set(SkFixedToScalar((srcRect.fLeft << 16) / texture->allocWidth()),
833 SkFixedToScalar((srcRect.fTop << 16) / texture->allocHeight()),
834 SkFixedToScalar((srcRect.fRight << 16) / texture->allocWidth()),
835 SkFixedToScalar((srcRect.fBottom << 16)/ texture->allocHeight()));
reed@google.comac10a2d2010-12-22 21:39:39 +0000836
bsalomon@google.com5782d712011-01-21 21:03:59 +0000837 SkRect dstRect;
838 dstRect.set(SkIntToScalar(0),SkIntToScalar(0),
839 SkIntToScalar(srcRect.width()), SkIntToScalar(srcRect.height()));
reed@google.comac10a2d2010-12-22 21:39:39 +0000840
bsalomon@google.com5782d712011-01-21 21:03:59 +0000841 SkRectFanSource texSrc(paintRect);
842 fContext->drawCustomVertices(*grPaint,
843 GrDrawTarget::kTriangleFan_PrimitiveType,
844 SkMatRectFanSource(dstRect, m),
845 &texSrc);
reed@google.comac10a2d2010-12-22 21:39:39 +0000846
reed@google.comac10a2d2010-12-22 21:39:39 +0000847}
848
849void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
850 int left, int top, const SkPaint& paint) {
851 CHECK_SHOULD_DRAW(draw);
852
853 SkAutoLockPixels alp(bitmap);
854 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
855 return;
856 }
857
bsalomon@google.com5782d712011-01-21 21:03:59 +0000858 GrPaint grPaint;
859 if(!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
860 return;
861 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000862
bsalomon@google.com5782d712011-01-21 21:03:59 +0000863 GrAutoMatrix avm(fContext, GrMatrix::I());
864
865 GrTexture* texture;
866 grPaint.fSampler.setClampNoFilter();
867 SkAutoCachedTexture act(this, bitmap, grPaint.fSampler, &texture);
868
869 grPaint.fTextureMatrix.setIdentity();
870 grPaint.setTexture(texture);
871
872 SkPoint max;
reed@google.comac10a2d2010-12-22 21:39:39 +0000873 max.set(SkFixedToScalar((texture->contentWidth() << 16) /
874 texture->allocWidth()),
875 SkFixedToScalar((texture->contentHeight() << 16) /
876 texture->allocHeight()));
bsalomon@google.com5782d712011-01-21 21:03:59 +0000877
878 fContext->drawRectToRect(grPaint,
879 GrRect(GrIntToScalar(left), GrIntToScalar(top),
880 GrIntToScalar(left + bitmap.width()),
881 GrIntToScalar(top + bitmap.height())),
882 GrRect(0, 0, max.fX, max.fY));
reed@google.comac10a2d2010-12-22 21:39:39 +0000883}
884
885void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
886 int x, int y, const SkPaint& paint) {
887 CHECK_SHOULD_DRAW(draw);
888
889 SkPoint max;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000890 GrPaint grPaint;
891 if (!((SkGpuDevice*)dev)->bindDeviceAsTexture(&grPaint, &max) ||
892 !this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
893 return;
reed@google.comac10a2d2010-12-22 21:39:39 +0000894 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000895
896 SkASSERT(NULL != grPaint.getTexture());
897
898 const SkBitmap& bm = dev->accessBitmap(false);
899 int w = bm.width();
900 int h = bm.height();
901
902 GrAutoMatrix avm(fContext, GrMatrix::I());
903
904 grPaint.fSampler.setClampNoFilter();
905 grPaint.fTextureMatrix.setIdentity();
906
907 fContext->drawRectToRect(grPaint,
908 GrRect(GrIntToScalar(x),
909 GrIntToScalar(y),
910 GrIntToScalar(x + w),
911 GrIntToScalar(y + h)),
912 GrRect(0,
913 0,
914 GrIntToScalar(max.fX),
915 GrIntToScalar(max.fY)));
reed@google.comac10a2d2010-12-22 21:39:39 +0000916}
917
918///////////////////////////////////////////////////////////////////////////////
919
920// must be in SkCanvas::VertexMode order
bsalomon@google.com5782d712011-01-21 21:03:59 +0000921static const GrDrawTarget::PrimitiveType gVertexMode2PrimitiveType[] = {
922 GrDrawTarget::kTriangles_PrimitiveType,
923 GrDrawTarget::kTriangleStrip_PrimitiveType,
924 GrDrawTarget::kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +0000925};
926
927void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
928 int vertexCount, const SkPoint vertices[],
929 const SkPoint texs[], const SkColor colors[],
930 SkXfermode* xmode,
931 const uint16_t indices[], int indexCount,
932 const SkPaint& paint) {
933 CHECK_SHOULD_DRAW(draw);
934
bsalomon@google.com5782d712011-01-21 21:03:59 +0000935 GrPaint grPaint;
936 SkAutoCachedTexture act;
937 // we ignore the shader if texs is null.
938 if (NULL == texs) {
939 if (!this->skPaint2GrPaintNoShader(paint, false, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000940 return;
941 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000942 } else {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000943 if (!this->skPaint2GrPaintShader(paint, &act,
944 *draw.fMatrix,
945 &grPaint)) {
946 return;
947 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000948 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000949
950 if (NULL != xmode && NULL != texs && NULL != colors) {
951 SkXfermode::Mode mode;
952 if (!SkXfermode::IsMode(xmode, &mode) ||
953 SkXfermode::kMultiply_Mode != mode) {
954 SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
955#if 0
956 return
957#endif
958 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000959 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000960
961#if SK_SCALAR_IS_GR_SCALAR
962 // even if GrColor and SkColor byte offsets match we need
963 // to perform pre-multiply.
964 if (NULL == colors) {
965 fContext->drawVertices(grPaint,
966 gVertexMode2PrimitiveType[vmode],
967 vertexCount,
968 (GrPoint*) vertices,
969 (GrPoint*) texs,
970 NULL,
971 indices,
972 indexCount);
973 } else
974#endif
975 {
976 SkTexCoordSource texSrc(texs);
977 SkColorSource colSrc(colors);
978 SkIndexSource idxSrc(indices, indexCount);
979
980 fContext->drawCustomVertices(grPaint,
981 gVertexMode2PrimitiveType[vmode],
982 SkPositionSource(vertices, vertexCount),
983 (NULL == texs) ? NULL : &texSrc,
984 (NULL == colors) ? NULL : &colSrc,
985 (NULL == indices) ? NULL : &idxSrc);
reed@google.comac10a2d2010-12-22 21:39:39 +0000986 }
987}
988
989///////////////////////////////////////////////////////////////////////////////
990
991static void GlyphCacheAuxProc(void* data) {
992 delete (GrFontScaler*)data;
993}
994
995static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) {
996 void* auxData;
997 GrFontScaler* scaler = NULL;
998 if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
999 scaler = (GrFontScaler*)auxData;
1000 }
1001 if (NULL == scaler) {
1002 scaler = new SkGrFontScaler(cache);
1003 cache->setAuxProc(GlyphCacheAuxProc, scaler);
1004 }
1005 return scaler;
1006}
1007
1008static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
1009 SkFixed fx, SkFixed fy,
1010 const SkGlyph& glyph) {
1011 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1012
1013 GrSkDrawProcs* procs = (GrSkDrawProcs*)state.fDraw->fProcs;
1014
1015 if (NULL == procs->fFontScaler) {
1016 procs->fFontScaler = get_gr_font_scaler(state.fCache);
1017 }
1018 procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0),
1019 SkIntToFixed(SkFixedFloor(fx)), fy,
1020 procs->fFontScaler);
1021}
1022
bsalomon@google.com5782d712011-01-21 21:03:59 +00001023SkDrawProcs* SkGpuDevice::initDrawForText(GrTextContext* context) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001024
1025 // deferred allocation
1026 if (NULL == fDrawProcs) {
1027 fDrawProcs = new GrSkDrawProcs;
1028 fDrawProcs->fD1GProc = SkGPU_Draw1Glyph;
1029 fDrawProcs->fContext = fContext;
1030 }
1031
1032 // init our (and GL's) state
1033 fDrawProcs->fTextContext = context;
1034 fDrawProcs->fFontScaler = NULL;
1035 return fDrawProcs;
1036}
1037
1038void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
1039 size_t byteLength, SkScalar x, SkScalar y,
1040 const SkPaint& paint) {
1041 CHECK_SHOULD_DRAW(draw);
1042
1043 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1044 // this guy will just call our drawPath()
1045 draw.drawText((const char*)text, byteLength, x, y, paint);
1046 } else {
1047 SkAutoExtMatrix aem(draw.fExtMatrix);
1048 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001049
1050 GrPaint grPaint;
1051 SkAutoCachedTexture act;
1052
1053 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1054 return;
1055 }
1056 GrTextContext context(fContext, grPaint, aem.extMatrix());
1057 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001058 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
1059 }
1060}
1061
1062void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
1063 size_t byteLength, const SkScalar pos[],
1064 SkScalar constY, int scalarsPerPos,
1065 const SkPaint& paint) {
1066 CHECK_SHOULD_DRAW(draw);
1067
1068 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1069 // this guy will just call our drawPath()
1070 draw.drawPosText((const char*)text, byteLength, pos, constY,
1071 scalarsPerPos, paint);
1072 } else {
1073 SkAutoExtMatrix aem(draw.fExtMatrix);
1074 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001075
1076 GrPaint grPaint;
1077 SkAutoCachedTexture act;
1078 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1079 return;
1080 }
1081
1082 GrTextContext context(fContext, grPaint, aem.extMatrix());
1083 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001084 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
1085 scalarsPerPos, paint);
1086 }
1087}
1088
1089void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
1090 size_t len, const SkPath& path,
1091 const SkMatrix* m, const SkPaint& paint) {
1092 CHECK_SHOULD_DRAW(draw);
1093
1094 SkASSERT(draw.fDevice == this);
1095 draw.drawTextOnPath((const char*)text, len, path, m, paint);
1096}
1097
1098///////////////////////////////////////////////////////////////////////////////
1099
1100SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
1101 const GrSamplerState& sampler,
1102 GrTexture** texture,
1103 bool forDeviceRenderTarget) {
1104 GrContext* ctx = this->context();
1105 uint32_t p0, p1;
1106 if (forDeviceRenderTarget) {
1107 p0 = p1 = -1;
1108 } else {
1109 p0 = bitmap.getGenerationID();
1110 p1 = bitmap.pixelRefOffset();
1111 }
1112
1113 GrTexture* newTexture = NULL;
1114 GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
1115 GrTextureEntry* entry = ctx->findAndLockTexture(&key, sampler);
1116
1117 if (NULL == entry) {
1118
1119 if (forDeviceRenderTarget) {
1120 const GrGpu::TextureDesc desc = {
1121 GrGpu::kRenderTarget_TextureFlag,
1122 GrGpu::kNone_AALevel,
1123 bitmap.width(),
1124 bitmap.height(),
1125 SkGr::Bitmap2PixelConfig(bitmap)
1126 };
1127 entry = ctx->createAndLockTexture(&key, sampler, desc, NULL, 0);
1128
1129 } else {
1130 entry = sk_gr_create_bitmap_texture(ctx, &key, sampler, bitmap);
1131 }
1132 if (NULL == entry) {
1133 GrPrintf("---- failed to create texture for cache [%d %d]\n",
1134 bitmap.width(), bitmap.height());
1135 }
1136 }
1137
1138 if (NULL != entry) {
1139 newTexture = entry->texture();
reed@google.comac10a2d2010-12-22 21:39:39 +00001140 if (texture) {
1141 *texture = newTexture;
1142 }
1143 // IMPORTANT: We can't allow another SkGpuDevice to get this
1144 // cache entry until this one is destroyed!
1145 if (forDeviceRenderTarget) {
1146 ctx->detachCachedTexture(entry);
1147 }
1148 }
1149 return (TexCache*)entry;
1150}
1151
1152void SkGpuDevice::unlockCachedTexture(TexCache* cache) {
1153 this->context()->unlockTexture((GrTextureEntry*)cache);
1154}
1155
reed@google.com7b201d22011-01-11 18:59:23 +00001156///////////////////////////////////////////////////////////////////////////////
1157
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001158SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context,
1159 GrRenderTarget* rootRenderTarget)
1160 : fContext(context) {
1161
1162 GrAssert(NULL != context);
1163 GrAssert(NULL != rootRenderTarget);
1164
1165 // check this now rather than passing this value to SkGpuDevice cons.
1166 // we want the rt that is bound *now* in the 3D API, not the one
1167 // at the time of newDevice.
1168 if (SkGpuDevice::Current3DApiRenderTarget() == rootRenderTarget) {
1169 fRootRenderTarget = context->createRenderTargetFrom3DApiState();
1170 } else {
1171 fRootRenderTarget = rootRenderTarget;
1172 rootRenderTarget->ref();
1173 }
reed@google.com7b201d22011-01-11 18:59:23 +00001174 context->ref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001175
reed@google.com7b201d22011-01-11 18:59:23 +00001176}
1177
1178SkGpuDeviceFactory::~SkGpuDeviceFactory() {
1179 fContext->unref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001180 fRootRenderTarget->unref();
reed@google.com7b201d22011-01-11 18:59:23 +00001181}
1182
1183SkDevice* SkGpuDeviceFactory::newDevice(SkCanvas*, SkBitmap::Config config,
1184 int width, int height,
1185 bool isOpaque, bool isLayer) {
1186 SkBitmap bm;
1187 bm.setConfig(config, width, height);
1188 bm.setIsOpaque(isOpaque);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001189 return new SkGpuDevice(fContext, bm, isLayer ? NULL : fRootRenderTarget);
reed@google.com7b201d22011-01-11 18:59:23 +00001190}
reed@google.comac10a2d2010-12-22 21:39:39 +00001191