blob: b8876796218e2fd06e164fb3fd85c8493a65a9d4 [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
677#ifdef HANDLE_MASKFILTER
678// modified from SkMaskFilter::filterPath()
679static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
680 SkMaskFilter* filter, const SkMatrix& matrix,
681 const SkRegion& clip, SkBounder* bounder,
682 GrPaint* grp) {
683 SkMask srcM, dstM;
684
685 if (!SkDraw::DrawToMask(path, &clip.getBounds(), filter, &matrix, &srcM,
686 SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
687 return false;
688 }
689
690 SkAutoMaskImage autoSrc(&srcM, false);
691
692 if (!filter->filterMask(&dstM, srcM, matrix, NULL)) {
693 return false;
694 }
695 // this will free-up dstM when we're done (allocated in filterMask())
696 SkAutoMaskImage autoDst(&dstM, false);
697
698 if (clip.quickReject(dstM.fBounds)) {
699 return false;
700 }
701 if (bounder && !bounder->doIRect(dstM.fBounds)) {
702 return false;
703 }
704
705 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
706 // the current clip (and identity matrix) and grpaint settings
707
708 GrAutoMatrix avm(fContext, GrMatrix::I());
709
710 const GrGpu::TextureDesc desc = {
711 0,
712 GrGpu::kNone_AALevel,
713 dstM.fBounds.width(),
714 dstM.fBounds.height(),
715 GrTexture::kAlpha_8_PixelConfig
716 };
717
718 GrTexture* texture = context->createUncachedTexture(desc, dstM.fImage,
719 dstM.fRowBytes);
720 if (NULL == texture) {
721 return false;
722 }
723
724 grp->setMask(texture)->unref();
725 grp->fMaskSampler.setClampNoFilter();
726 grp->fMaskMatrix.setIdentity();
727
728 SkPoint max;
729 max.set(SkFixedToScalar((texture->contentWidth() << 16) /
730 texture->allocWidth()),
731 SkFixedToScalar((texture->contentHeight() << 16) /
732 texture->allocHeight()));
733
734 fContext->drawRectToRect(*grp,
735 GrRect(GrIntToScalar(left), GrIntToScalar(top),
736 GrIntToScalar(left + bitmap.width()),
737 GrIntToScalar(top + bitmap.height())),
738 GrRect(0, 0, max.fX, max.fY));
739 return true;
740}
741#endif
742
reed@google.comac10a2d2010-12-22 21:39:39 +0000743void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& path,
744 const SkPaint& paint, const SkMatrix* prePathMatrix,
745 bool pathIsMutable) {
746 CHECK_SHOULD_DRAW(draw);
747
bsalomon@google.com5782d712011-01-21 21:03:59 +0000748 GrPaint grPaint;
749 SkAutoCachedTexture act;
750 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000751 return;
752 }
753
754 const SkPath* pathPtr = &path;
755 SkPath tmpPath;
756
757 if (prePathMatrix) {
758 if (pathIsMutable) {
759 const_cast<SkPath*>(pathPtr)->transform(*prePathMatrix);
760 } else {
761 path.transform(*prePathMatrix, &tmpPath);
762 pathPtr = &tmpPath;
763 }
764 }
765
reed@google.com69302852011-02-16 18:08:07 +0000766#ifdef HANDLE_MASKFILTER
767 if (paint.getMaskFilter()) {
768 drawWithMaskFilter(fContext, *pathPtr, paint.getMaskFilter(),
769 *draw.fMatrix, *draw.fClip, draw.fBounder, &grPaint);
770 return;
771 }
772#endif
773
reed@google.comac10a2d2010-12-22 21:39:39 +0000774 SkPath fillPath;
775 GrContext::PathFills fill = GrContext::kHairLine_PathFill;
776
777 if (paint.getFillPath(*pathPtr, &fillPath)) {
778 switch (fillPath.getFillType()) {
779 case SkPath::kWinding_FillType:
780 fill = GrContext::kWinding_PathFill;
781 break;
782 case SkPath::kEvenOdd_FillType:
783 fill = GrContext::kEvenOdd_PathFill;
784 break;
785 case SkPath::kInverseWinding_FillType:
786 fill = GrContext::kInverseWinding_PathFill;
787 break;
788 case SkPath::kInverseEvenOdd_FillType:
789 fill = GrContext::kInverseEvenOdd_PathFill;
790 break;
791 default:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000792 SkDebugf("Unsupported path fill type\n");
reed@google.comac10a2d2010-12-22 21:39:39 +0000793 return;
794 }
795 }
796
797 SkGrPathIter iter(fillPath);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000798 fContext->drawPath(grPaint, &iter, fill);
reed@google.comac10a2d2010-12-22 21:39:39 +0000799}
800
reed@google.comac10a2d2010-12-22 21:39:39 +0000801void SkGpuDevice::drawBitmap(const SkDraw& draw,
802 const SkBitmap& bitmap,
803 const SkIRect* srcRectPtr,
804 const SkMatrix& m,
805 const SkPaint& paint) {
806 CHECK_SHOULD_DRAW(draw);
807
808 SkIRect srcRect;
809 if (NULL == srcRectPtr) {
810 srcRect.set(0, 0, bitmap.width(), bitmap.height());
811 } else {
812 srcRect = *srcRectPtr;
813 }
814
bsalomon@google.com5782d712011-01-21 21:03:59 +0000815 GrPaint grPaint;
816 if (!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
817 return;
818 }
819 grPaint.fSampler.setFilter(paint.isFilterBitmap());
820
reed@google.com02a7e6c2011-01-28 21:21:49 +0000821 const int maxTextureDim = fContext->getMaxTextureDimension();
822 if (bitmap.getTexture() || (bitmap.width() <= maxTextureDim &&
823 bitmap.height() <= maxTextureDim)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000824 // take the fast case
bsalomon@google.com5782d712011-01-21 21:03:59 +0000825 this->internalDrawBitmap(draw, bitmap, srcRect, m, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000826 return;
827 }
828
829 // undo the translate done by SkCanvas
830 int DX = SkMax32(0, srcRect.fLeft);
831 int DY = SkMax32(0, srcRect.fTop);
832 // compute clip bounds in local coordinates
833 SkIRect clipRect;
834 {
835 SkRect r;
836 r.set(draw.fClip->getBounds());
837 SkMatrix matrix, inverse;
838 matrix.setConcat(*draw.fMatrix, m);
839 if (!matrix.invert(&inverse)) {
840 return;
841 }
842 inverse.mapRect(&r);
843 r.roundOut(&clipRect);
844 // apply the canvas' translate to our local clip
845 clipRect.offset(DX, DY);
846 }
847
reed@google.com02a7e6c2011-01-28 21:21:49 +0000848 int nx = bitmap.width() / maxTextureDim;
849 int ny = bitmap.height() / maxTextureDim;
reed@google.comac10a2d2010-12-22 21:39:39 +0000850 for (int x = 0; x <= nx; x++) {
851 for (int y = 0; y <= ny; y++) {
852 SkIRect tileR;
reed@google.com02a7e6c2011-01-28 21:21:49 +0000853 tileR.set(x * maxTextureDim, y * maxTextureDim,
854 (x + 1) * maxTextureDim, (y + 1) * maxTextureDim);
reed@google.comac10a2d2010-12-22 21:39:39 +0000855 if (!SkIRect::Intersects(tileR, clipRect)) {
856 continue;
857 }
858
859 SkIRect srcR = tileR;
860 if (!srcR.intersect(srcRect)) {
861 continue;
862 }
863
864 SkBitmap tmpB;
865 if (bitmap.extractSubset(&tmpB, tileR)) {
866 // now offset it to make it "local" to our tmp bitmap
867 srcR.offset(-tileR.fLeft, -tileR.fTop);
868
869 SkMatrix tmpM(m);
870 {
871 int dx = tileR.fLeft - DX + SkMax32(0, srcR.fLeft);
872 int dy = tileR.fTop - DY + SkMax32(0, srcR.fTop);
873 tmpM.preTranslate(SkIntToScalar(dx), SkIntToScalar(dy));
874 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000875 this->internalDrawBitmap(draw, tmpB, srcR, tmpM, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000876 }
877 }
878 }
879}
880
881/*
882 * This is called by drawBitmap(), which has to handle images that may be too
883 * large to be represented by a single texture.
884 *
bsalomon@google.com5782d712011-01-21 21:03:59 +0000885 * internalDrawBitmap assumes that the specified bitmap will fit in a texture
886 * and that non-texture portion of the GrPaint has already been setup.
reed@google.comac10a2d2010-12-22 21:39:39 +0000887 */
888void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
889 const SkBitmap& bitmap,
890 const SkIRect& srcRect,
891 const SkMatrix& m,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000892 GrPaint* grPaint) {
reed@google.com02a7e6c2011-01-28 21:21:49 +0000893 SkASSERT(bitmap.width() <= fContext->getMaxTextureDimension() &&
894 bitmap.height() <= fContext->getMaxTextureDimension());
reed@google.comac10a2d2010-12-22 21:39:39 +0000895
896 SkAutoLockPixels alp(bitmap);
897 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
898 return;
899 }
900
bsalomon@google.com5782d712011-01-21 21:03:59 +0000901 grPaint->fSampler.setWrapX(GrSamplerState::kClamp_WrapMode);
902 grPaint->fSampler.setWrapY(GrSamplerState::kClamp_WrapMode);
903 grPaint->fSampler.setSampleMode(GrSamplerState::kNormal_SampleMode);
reed@google.comac10a2d2010-12-22 21:39:39 +0000904
905 GrTexture* texture;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000906 SkAutoCachedTexture act(this, bitmap, grPaint->fSampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000907 if (NULL == texture) {
908 return;
909 }
910
bsalomon@google.com5782d712011-01-21 21:03:59 +0000911 grPaint->setTexture(texture);
912 grPaint->fTextureMatrix.setIdentity();
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000913 GrRect dstRect(0, 0, GrIntToScalar(srcRect.width()), GrIntToScalar(srcRect.height()));
914 GrRect paintRect(GrIntToScalar(srcRect.fLeft) / texture->allocWidth(),
915 GrIntToScalar(srcRect.fTop) / texture->allocHeight(),
916 GrIntToScalar(srcRect.fRight) / texture->allocWidth(),
917 GrIntToScalar(srcRect.fBottom) / texture->allocHeight());
reed@google.comac10a2d2010-12-22 21:39:39 +0000918
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000919 GrMatrix grMat;
920 SkGr::SkMatrix2GrMatrix(m, &grMat);
reed@google.comac10a2d2010-12-22 21:39:39 +0000921
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000922 fContext->drawRectToRect(*grPaint, dstRect, paintRect, &grMat);
reed@google.comac10a2d2010-12-22 21:39:39 +0000923}
924
925void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
926 int left, int top, const SkPaint& paint) {
927 CHECK_SHOULD_DRAW(draw);
928
929 SkAutoLockPixels alp(bitmap);
930 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
931 return;
932 }
933
bsalomon@google.com5782d712011-01-21 21:03:59 +0000934 GrPaint grPaint;
935 if(!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
936 return;
937 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000938
bsalomon@google.com5782d712011-01-21 21:03:59 +0000939 GrAutoMatrix avm(fContext, GrMatrix::I());
940
941 GrTexture* texture;
942 grPaint.fSampler.setClampNoFilter();
943 SkAutoCachedTexture act(this, bitmap, grPaint.fSampler, &texture);
944
945 grPaint.fTextureMatrix.setIdentity();
946 grPaint.setTexture(texture);
947
948 SkPoint max;
reed@google.comac10a2d2010-12-22 21:39:39 +0000949 max.set(SkFixedToScalar((texture->contentWidth() << 16) /
950 texture->allocWidth()),
951 SkFixedToScalar((texture->contentHeight() << 16) /
952 texture->allocHeight()));
bsalomon@google.com5782d712011-01-21 21:03:59 +0000953
954 fContext->drawRectToRect(grPaint,
955 GrRect(GrIntToScalar(left), GrIntToScalar(top),
956 GrIntToScalar(left + bitmap.width()),
957 GrIntToScalar(top + bitmap.height())),
958 GrRect(0, 0, max.fX, max.fY));
reed@google.comac10a2d2010-12-22 21:39:39 +0000959}
960
961void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
962 int x, int y, const SkPaint& paint) {
963 CHECK_SHOULD_DRAW(draw);
964
965 SkPoint max;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000966 GrPaint grPaint;
967 if (!((SkGpuDevice*)dev)->bindDeviceAsTexture(&grPaint, &max) ||
968 !this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
969 return;
reed@google.comac10a2d2010-12-22 21:39:39 +0000970 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000971
972 SkASSERT(NULL != grPaint.getTexture());
973
974 const SkBitmap& bm = dev->accessBitmap(false);
975 int w = bm.width();
976 int h = bm.height();
977
978 GrAutoMatrix avm(fContext, GrMatrix::I());
979
980 grPaint.fSampler.setClampNoFilter();
981 grPaint.fTextureMatrix.setIdentity();
982
983 fContext->drawRectToRect(grPaint,
reed@google.com1a2e8d22011-01-21 22:08:29 +0000984 GrRect(GrIntToScalar(x),
985 GrIntToScalar(y),
986 GrIntToScalar(x + w),
bsalomon@google.com5782d712011-01-21 21:03:59 +0000987 GrIntToScalar(y + h)),
reed@google.com1a2e8d22011-01-21 22:08:29 +0000988 GrRect(0,
989 0,
990 GrIntToScalar(max.fX),
bsalomon@google.com5782d712011-01-21 21:03:59 +0000991 GrIntToScalar(max.fY)));
reed@google.comac10a2d2010-12-22 21:39:39 +0000992}
993
994///////////////////////////////////////////////////////////////////////////////
995
996// must be in SkCanvas::VertexMode order
bsalomon@google.com5782d712011-01-21 21:03:59 +0000997static const GrDrawTarget::PrimitiveType gVertexMode2PrimitiveType[] = {
998 GrDrawTarget::kTriangles_PrimitiveType,
999 GrDrawTarget::kTriangleStrip_PrimitiveType,
1000 GrDrawTarget::kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +00001001};
1002
1003void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
1004 int vertexCount, const SkPoint vertices[],
1005 const SkPoint texs[], const SkColor colors[],
1006 SkXfermode* xmode,
1007 const uint16_t indices[], int indexCount,
1008 const SkPaint& paint) {
1009 CHECK_SHOULD_DRAW(draw);
1010
bsalomon@google.com5782d712011-01-21 21:03:59 +00001011 GrPaint grPaint;
1012 SkAutoCachedTexture act;
1013 // we ignore the shader if texs is null.
1014 if (NULL == texs) {
1015 if (!this->skPaint2GrPaintNoShader(paint, false, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001016 return;
1017 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001018 } else {
reed@google.com1a2e8d22011-01-21 22:08:29 +00001019 if (!this->skPaint2GrPaintShader(paint, &act,
1020 *draw.fMatrix,
bsalomon@google.com5782d712011-01-21 21:03:59 +00001021 &grPaint)) {
1022 return;
1023 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001024 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001025
1026 if (NULL != xmode && NULL != texs && NULL != colors) {
1027 SkXfermode::Mode mode;
1028 if (!SkXfermode::IsMode(xmode, &mode) ||
1029 SkXfermode::kMultiply_Mode != mode) {
1030 SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
1031#if 0
1032 return
1033#endif
1034 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001035 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001036
1037#if SK_SCALAR_IS_GR_SCALAR
1038 // even if GrColor and SkColor byte offsets match we need
1039 // to perform pre-multiply.
1040 if (NULL == colors) {
1041 fContext->drawVertices(grPaint,
1042 gVertexMode2PrimitiveType[vmode],
1043 vertexCount,
1044 (GrPoint*) vertices,
1045 (GrPoint*) texs,
1046 NULL,
1047 indices,
1048 indexCount);
1049 } else
1050#endif
1051 {
1052 SkTexCoordSource texSrc(texs);
1053 SkColorSource colSrc(colors);
1054 SkIndexSource idxSrc(indices, indexCount);
1055
1056 fContext->drawCustomVertices(grPaint,
1057 gVertexMode2PrimitiveType[vmode],
1058 SkPositionSource(vertices, vertexCount),
1059 (NULL == texs) ? NULL : &texSrc,
1060 (NULL == colors) ? NULL : &colSrc,
1061 (NULL == indices) ? NULL : &idxSrc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001062 }
1063}
1064
1065///////////////////////////////////////////////////////////////////////////////
1066
1067static void GlyphCacheAuxProc(void* data) {
1068 delete (GrFontScaler*)data;
1069}
1070
1071static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) {
1072 void* auxData;
1073 GrFontScaler* scaler = NULL;
1074 if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
1075 scaler = (GrFontScaler*)auxData;
1076 }
1077 if (NULL == scaler) {
1078 scaler = new SkGrFontScaler(cache);
1079 cache->setAuxProc(GlyphCacheAuxProc, scaler);
1080 }
1081 return scaler;
1082}
1083
1084static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
1085 SkFixed fx, SkFixed fy,
1086 const SkGlyph& glyph) {
1087 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1088
1089 GrSkDrawProcs* procs = (GrSkDrawProcs*)state.fDraw->fProcs;
1090
1091 if (NULL == procs->fFontScaler) {
1092 procs->fFontScaler = get_gr_font_scaler(state.fCache);
1093 }
1094 procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0),
1095 SkIntToFixed(SkFixedFloor(fx)), fy,
1096 procs->fFontScaler);
1097}
1098
bsalomon@google.com5782d712011-01-21 21:03:59 +00001099SkDrawProcs* SkGpuDevice::initDrawForText(GrTextContext* context) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001100
1101 // deferred allocation
1102 if (NULL == fDrawProcs) {
1103 fDrawProcs = new GrSkDrawProcs;
1104 fDrawProcs->fD1GProc = SkGPU_Draw1Glyph;
1105 fDrawProcs->fContext = fContext;
1106 }
1107
1108 // init our (and GL's) state
1109 fDrawProcs->fTextContext = context;
1110 fDrawProcs->fFontScaler = NULL;
1111 return fDrawProcs;
1112}
1113
1114void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
1115 size_t byteLength, SkScalar x, SkScalar y,
1116 const SkPaint& paint) {
1117 CHECK_SHOULD_DRAW(draw);
1118
1119 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1120 // this guy will just call our drawPath()
1121 draw.drawText((const char*)text, byteLength, x, y, paint);
1122 } else {
1123 SkAutoExtMatrix aem(draw.fExtMatrix);
1124 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001125
1126 GrPaint grPaint;
1127 SkAutoCachedTexture act;
1128
1129 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1130 return;
1131 }
1132 GrTextContext context(fContext, grPaint, aem.extMatrix());
1133 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001134 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
1135 }
1136}
1137
1138void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
1139 size_t byteLength, const SkScalar pos[],
1140 SkScalar constY, int scalarsPerPos,
1141 const SkPaint& paint) {
1142 CHECK_SHOULD_DRAW(draw);
1143
1144 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1145 // this guy will just call our drawPath()
1146 draw.drawPosText((const char*)text, byteLength, pos, constY,
1147 scalarsPerPos, paint);
1148 } else {
1149 SkAutoExtMatrix aem(draw.fExtMatrix);
1150 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001151
1152 GrPaint grPaint;
1153 SkAutoCachedTexture act;
1154 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1155 return;
1156 }
1157
1158 GrTextContext context(fContext, grPaint, aem.extMatrix());
1159 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001160 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
1161 scalarsPerPos, paint);
1162 }
1163}
1164
1165void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
1166 size_t len, const SkPath& path,
1167 const SkMatrix* m, const SkPaint& paint) {
1168 CHECK_SHOULD_DRAW(draw);
1169
1170 SkASSERT(draw.fDevice == this);
1171 draw.drawTextOnPath((const char*)text, len, path, m, paint);
1172}
1173
1174///////////////////////////////////////////////////////////////////////////////
1175
1176SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
1177 const GrSamplerState& sampler,
1178 GrTexture** texture,
1179 bool forDeviceRenderTarget) {
1180 GrContext* ctx = this->context();
1181 uint32_t p0, p1;
1182 if (forDeviceRenderTarget) {
1183 p0 = p1 = -1;
1184 } else {
1185 p0 = bitmap.getGenerationID();
1186 p1 = bitmap.pixelRefOffset();
1187 }
1188
1189 GrTexture* newTexture = NULL;
1190 GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
1191 GrTextureEntry* entry = ctx->findAndLockTexture(&key, sampler);
1192
1193 if (NULL == entry) {
1194
1195 if (forDeviceRenderTarget) {
1196 const GrGpu::TextureDesc desc = {
1197 GrGpu::kRenderTarget_TextureFlag,
1198 GrGpu::kNone_AALevel,
1199 bitmap.width(),
1200 bitmap.height(),
1201 SkGr::Bitmap2PixelConfig(bitmap)
1202 };
1203 entry = ctx->createAndLockTexture(&key, sampler, desc, NULL, 0);
1204
1205 } else {
1206 entry = sk_gr_create_bitmap_texture(ctx, &key, sampler, bitmap);
1207 }
1208 if (NULL == entry) {
1209 GrPrintf("---- failed to create texture for cache [%d %d]\n",
1210 bitmap.width(), bitmap.height());
1211 }
1212 }
1213
1214 if (NULL != entry) {
1215 newTexture = entry->texture();
reed@google.comac10a2d2010-12-22 21:39:39 +00001216 if (texture) {
1217 *texture = newTexture;
1218 }
1219 // IMPORTANT: We can't allow another SkGpuDevice to get this
1220 // cache entry until this one is destroyed!
1221 if (forDeviceRenderTarget) {
1222 ctx->detachCachedTexture(entry);
1223 }
1224 }
1225 return (TexCache*)entry;
1226}
1227
1228void SkGpuDevice::unlockCachedTexture(TexCache* cache) {
1229 this->context()->unlockTexture((GrTextureEntry*)cache);
1230}
1231
reed@google.com7b201d22011-01-11 18:59:23 +00001232///////////////////////////////////////////////////////////////////////////////
1233
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001234SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context,
1235 GrRenderTarget* rootRenderTarget)
1236 : fContext(context) {
1237
1238 GrAssert(NULL != context);
1239 GrAssert(NULL != rootRenderTarget);
1240
1241 // check this now rather than passing this value to SkGpuDevice cons.
1242 // we want the rt that is bound *now* in the 3D API, not the one
1243 // at the time of newDevice.
1244 if (SkGpuDevice::Current3DApiRenderTarget() == rootRenderTarget) {
1245 fRootRenderTarget = context->createRenderTargetFrom3DApiState();
1246 } else {
1247 fRootRenderTarget = rootRenderTarget;
1248 rootRenderTarget->ref();
1249 }
reed@google.com7b201d22011-01-11 18:59:23 +00001250 context->ref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001251
reed@google.com7b201d22011-01-11 18:59:23 +00001252}
1253
1254SkGpuDeviceFactory::~SkGpuDeviceFactory() {
1255 fContext->unref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001256 fRootRenderTarget->unref();
reed@google.com7b201d22011-01-11 18:59:23 +00001257}
1258
1259SkDevice* SkGpuDeviceFactory::newDevice(SkCanvas*, SkBitmap::Config config,
1260 int width, int height,
1261 bool isOpaque, bool isLayer) {
1262 SkBitmap bm;
1263 bm.setConfig(config, width, height);
1264 bm.setIsOpaque(isOpaque);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001265 return new SkGpuDevice(fContext, bm, isLayer ? NULL : fRootRenderTarget);
reed@google.com7b201d22011-01-11 18:59:23 +00001266}
reed@google.comac10a2d2010-12-22 21:39:39 +00001267