blob: 22d5b20208ca6ce5809fcb2e94869e94d0bcda21 [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;
reed@google.comac10a2d2010-12-22 21:39:39 +0000758
759 if (prePathMatrix) {
reed@google.come3445642011-02-16 23:20:39 +0000760 SkPath* result = pathPtr;
reed@google.com0c219b62011-02-16 21:31:18 +0000761
reed@google.come3445642011-02-16 23:20:39 +0000762 if (!pathIsMutable) {
763 result = &tmpPath;
764 pathIsMutable = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000765 }
reed@google.come3445642011-02-16 23:20:39 +0000766 // should I push prePathMatrix on our MV stack temporarily, instead
767 // of applying it here? See SkDraw.cpp
768 pathPtr->transform(*prePathMatrix, result);
769 pathPtr = result;
reed@google.comac10a2d2010-12-22 21:39:39 +0000770 }
reed@google.com0c219b62011-02-16 21:31:18 +0000771 // at this point we're done with prePathMatrix
772 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
reed@google.comac10a2d2010-12-22 21:39:39 +0000773
reed@google.com0c219b62011-02-16 21:31:18 +0000774 if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) {
775 doFill = paint.getFillPath(*pathPtr, &tmpPath);
776 pathPtr = &tmpPath;
777 }
778
779 // END lift from SkDraw::drawPath()
780
reed@google.com69302852011-02-16 18:08:07 +0000781 if (paint.getMaskFilter()) {
reed@google.com0c219b62011-02-16 21:31:18 +0000782 // avoid possibly allocating a new path in transform if we can
783 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
784
785 // transform the path into device space
reed@google.come3445642011-02-16 23:20:39 +0000786 pathPtr->transform(*draw.fMatrix, devPathPtr);
reed@google.com0c219b62011-02-16 21:31:18 +0000787
788 drawWithMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
reed@google.com69302852011-02-16 18:08:07 +0000789 *draw.fMatrix, *draw.fClip, draw.fBounder, &grPaint);
790 return;
791 }
reed@google.com69302852011-02-16 18:08:07 +0000792
reed@google.comac10a2d2010-12-22 21:39:39 +0000793 GrContext::PathFills fill = GrContext::kHairLine_PathFill;
794
reed@google.com0c219b62011-02-16 21:31:18 +0000795 if (doFill) {
796 switch (pathPtr->getFillType()) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000797 case SkPath::kWinding_FillType:
798 fill = GrContext::kWinding_PathFill;
799 break;
800 case SkPath::kEvenOdd_FillType:
801 fill = GrContext::kEvenOdd_PathFill;
802 break;
803 case SkPath::kInverseWinding_FillType:
804 fill = GrContext::kInverseWinding_PathFill;
805 break;
806 case SkPath::kInverseEvenOdd_FillType:
807 fill = GrContext::kInverseEvenOdd_PathFill;
808 break;
809 default:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000810 SkDebugf("Unsupported path fill type\n");
reed@google.comac10a2d2010-12-22 21:39:39 +0000811 return;
812 }
813 }
814
reed@google.com0c219b62011-02-16 21:31:18 +0000815 SkGrPathIter iter(*pathPtr);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000816 fContext->drawPath(grPaint, &iter, fill);
reed@google.comac10a2d2010-12-22 21:39:39 +0000817}
818
reed@google.comac10a2d2010-12-22 21:39:39 +0000819void SkGpuDevice::drawBitmap(const SkDraw& draw,
820 const SkBitmap& bitmap,
821 const SkIRect* srcRectPtr,
822 const SkMatrix& m,
823 const SkPaint& paint) {
824 CHECK_SHOULD_DRAW(draw);
825
826 SkIRect srcRect;
827 if (NULL == srcRectPtr) {
828 srcRect.set(0, 0, bitmap.width(), bitmap.height());
829 } else {
830 srcRect = *srcRectPtr;
831 }
832
bsalomon@google.com5782d712011-01-21 21:03:59 +0000833 GrPaint grPaint;
834 if (!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
835 return;
836 }
837 grPaint.fSampler.setFilter(paint.isFilterBitmap());
838
reed@google.com02a7e6c2011-01-28 21:21:49 +0000839 const int maxTextureDim = fContext->getMaxTextureDimension();
840 if (bitmap.getTexture() || (bitmap.width() <= maxTextureDim &&
841 bitmap.height() <= maxTextureDim)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000842 // take the fast case
bsalomon@google.com5782d712011-01-21 21:03:59 +0000843 this->internalDrawBitmap(draw, bitmap, srcRect, m, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000844 return;
845 }
846
847 // undo the translate done by SkCanvas
848 int DX = SkMax32(0, srcRect.fLeft);
849 int DY = SkMax32(0, srcRect.fTop);
850 // compute clip bounds in local coordinates
851 SkIRect clipRect;
852 {
853 SkRect r;
854 r.set(draw.fClip->getBounds());
855 SkMatrix matrix, inverse;
856 matrix.setConcat(*draw.fMatrix, m);
857 if (!matrix.invert(&inverse)) {
858 return;
859 }
860 inverse.mapRect(&r);
861 r.roundOut(&clipRect);
862 // apply the canvas' translate to our local clip
863 clipRect.offset(DX, DY);
864 }
865
reed@google.com02a7e6c2011-01-28 21:21:49 +0000866 int nx = bitmap.width() / maxTextureDim;
867 int ny = bitmap.height() / maxTextureDim;
reed@google.comac10a2d2010-12-22 21:39:39 +0000868 for (int x = 0; x <= nx; x++) {
869 for (int y = 0; y <= ny; y++) {
870 SkIRect tileR;
reed@google.com02a7e6c2011-01-28 21:21:49 +0000871 tileR.set(x * maxTextureDim, y * maxTextureDim,
872 (x + 1) * maxTextureDim, (y + 1) * maxTextureDim);
reed@google.comac10a2d2010-12-22 21:39:39 +0000873 if (!SkIRect::Intersects(tileR, clipRect)) {
874 continue;
875 }
876
877 SkIRect srcR = tileR;
878 if (!srcR.intersect(srcRect)) {
879 continue;
880 }
881
882 SkBitmap tmpB;
883 if (bitmap.extractSubset(&tmpB, tileR)) {
884 // now offset it to make it "local" to our tmp bitmap
885 srcR.offset(-tileR.fLeft, -tileR.fTop);
886
887 SkMatrix tmpM(m);
888 {
889 int dx = tileR.fLeft - DX + SkMax32(0, srcR.fLeft);
890 int dy = tileR.fTop - DY + SkMax32(0, srcR.fTop);
891 tmpM.preTranslate(SkIntToScalar(dx), SkIntToScalar(dy));
892 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000893 this->internalDrawBitmap(draw, tmpB, srcR, tmpM, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000894 }
895 }
896 }
897}
898
899/*
900 * This is called by drawBitmap(), which has to handle images that may be too
901 * large to be represented by a single texture.
902 *
bsalomon@google.com5782d712011-01-21 21:03:59 +0000903 * internalDrawBitmap assumes that the specified bitmap will fit in a texture
904 * and that non-texture portion of the GrPaint has already been setup.
reed@google.comac10a2d2010-12-22 21:39:39 +0000905 */
906void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
907 const SkBitmap& bitmap,
908 const SkIRect& srcRect,
909 const SkMatrix& m,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000910 GrPaint* grPaint) {
reed@google.com02a7e6c2011-01-28 21:21:49 +0000911 SkASSERT(bitmap.width() <= fContext->getMaxTextureDimension() &&
912 bitmap.height() <= fContext->getMaxTextureDimension());
reed@google.comac10a2d2010-12-22 21:39:39 +0000913
914 SkAutoLockPixels alp(bitmap);
915 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
916 return;
917 }
918
bsalomon@google.com5782d712011-01-21 21:03:59 +0000919 grPaint->fSampler.setWrapX(GrSamplerState::kClamp_WrapMode);
920 grPaint->fSampler.setWrapY(GrSamplerState::kClamp_WrapMode);
921 grPaint->fSampler.setSampleMode(GrSamplerState::kNormal_SampleMode);
reed@google.comac10a2d2010-12-22 21:39:39 +0000922
923 GrTexture* texture;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000924 SkAutoCachedTexture act(this, bitmap, grPaint->fSampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000925 if (NULL == texture) {
926 return;
927 }
928
bsalomon@google.com5782d712011-01-21 21:03:59 +0000929 grPaint->setTexture(texture);
930 grPaint->fTextureMatrix.setIdentity();
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000931 GrRect dstRect(0, 0, GrIntToScalar(srcRect.width()), GrIntToScalar(srcRect.height()));
932 GrRect paintRect(GrIntToScalar(srcRect.fLeft) / texture->allocWidth(),
933 GrIntToScalar(srcRect.fTop) / texture->allocHeight(),
934 GrIntToScalar(srcRect.fRight) / texture->allocWidth(),
935 GrIntToScalar(srcRect.fBottom) / texture->allocHeight());
reed@google.comac10a2d2010-12-22 21:39:39 +0000936
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000937 GrMatrix grMat;
938 SkGr::SkMatrix2GrMatrix(m, &grMat);
reed@google.comac10a2d2010-12-22 21:39:39 +0000939
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000940 fContext->drawRectToRect(*grPaint, dstRect, paintRect, &grMat);
reed@google.comac10a2d2010-12-22 21:39:39 +0000941}
942
943void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
944 int left, int top, const SkPaint& paint) {
945 CHECK_SHOULD_DRAW(draw);
946
947 SkAutoLockPixels alp(bitmap);
948 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
949 return;
950 }
951
bsalomon@google.com5782d712011-01-21 21:03:59 +0000952 GrPaint grPaint;
953 if(!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
954 return;
955 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000956
bsalomon@google.com5782d712011-01-21 21:03:59 +0000957 GrAutoMatrix avm(fContext, GrMatrix::I());
958
959 GrTexture* texture;
960 grPaint.fSampler.setClampNoFilter();
961 SkAutoCachedTexture act(this, bitmap, grPaint.fSampler, &texture);
962
963 grPaint.fTextureMatrix.setIdentity();
964 grPaint.setTexture(texture);
965
966 SkPoint max;
reed@google.comac10a2d2010-12-22 21:39:39 +0000967 max.set(SkFixedToScalar((texture->contentWidth() << 16) /
968 texture->allocWidth()),
969 SkFixedToScalar((texture->contentHeight() << 16) /
970 texture->allocHeight()));
bsalomon@google.com5782d712011-01-21 21:03:59 +0000971
972 fContext->drawRectToRect(grPaint,
973 GrRect(GrIntToScalar(left), GrIntToScalar(top),
974 GrIntToScalar(left + bitmap.width()),
975 GrIntToScalar(top + bitmap.height())),
976 GrRect(0, 0, max.fX, max.fY));
reed@google.comac10a2d2010-12-22 21:39:39 +0000977}
978
979void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
980 int x, int y, const SkPaint& paint) {
981 CHECK_SHOULD_DRAW(draw);
982
983 SkPoint max;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000984 GrPaint grPaint;
985 if (!((SkGpuDevice*)dev)->bindDeviceAsTexture(&grPaint, &max) ||
986 !this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
987 return;
reed@google.comac10a2d2010-12-22 21:39:39 +0000988 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000989
990 SkASSERT(NULL != grPaint.getTexture());
991
992 const SkBitmap& bm = dev->accessBitmap(false);
993 int w = bm.width();
994 int h = bm.height();
995
996 GrAutoMatrix avm(fContext, GrMatrix::I());
997
998 grPaint.fSampler.setClampNoFilter();
999 grPaint.fTextureMatrix.setIdentity();
1000
1001 fContext->drawRectToRect(grPaint,
reed@google.com1a2e8d22011-01-21 22:08:29 +00001002 GrRect(GrIntToScalar(x),
1003 GrIntToScalar(y),
1004 GrIntToScalar(x + w),
bsalomon@google.com5782d712011-01-21 21:03:59 +00001005 GrIntToScalar(y + h)),
reed@google.com1a2e8d22011-01-21 22:08:29 +00001006 GrRect(0,
1007 0,
1008 GrIntToScalar(max.fX),
bsalomon@google.com5782d712011-01-21 21:03:59 +00001009 GrIntToScalar(max.fY)));
reed@google.comac10a2d2010-12-22 21:39:39 +00001010}
1011
1012///////////////////////////////////////////////////////////////////////////////
1013
1014// must be in SkCanvas::VertexMode order
bsalomon@google.com5782d712011-01-21 21:03:59 +00001015static const GrDrawTarget::PrimitiveType gVertexMode2PrimitiveType[] = {
1016 GrDrawTarget::kTriangles_PrimitiveType,
1017 GrDrawTarget::kTriangleStrip_PrimitiveType,
1018 GrDrawTarget::kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +00001019};
1020
1021void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
1022 int vertexCount, const SkPoint vertices[],
1023 const SkPoint texs[], const SkColor colors[],
1024 SkXfermode* xmode,
1025 const uint16_t indices[], int indexCount,
1026 const SkPaint& paint) {
1027 CHECK_SHOULD_DRAW(draw);
1028
bsalomon@google.com5782d712011-01-21 21:03:59 +00001029 GrPaint grPaint;
1030 SkAutoCachedTexture act;
1031 // we ignore the shader if texs is null.
1032 if (NULL == texs) {
1033 if (!this->skPaint2GrPaintNoShader(paint, false, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001034 return;
1035 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001036 } else {
reed@google.com1a2e8d22011-01-21 22:08:29 +00001037 if (!this->skPaint2GrPaintShader(paint, &act,
1038 *draw.fMatrix,
bsalomon@google.com5782d712011-01-21 21:03:59 +00001039 &grPaint)) {
1040 return;
1041 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001042 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001043
1044 if (NULL != xmode && NULL != texs && NULL != colors) {
1045 SkXfermode::Mode mode;
1046 if (!SkXfermode::IsMode(xmode, &mode) ||
1047 SkXfermode::kMultiply_Mode != mode) {
1048 SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
1049#if 0
1050 return
1051#endif
1052 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001053 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001054
1055#if SK_SCALAR_IS_GR_SCALAR
1056 // even if GrColor and SkColor byte offsets match we need
1057 // to perform pre-multiply.
1058 if (NULL == colors) {
1059 fContext->drawVertices(grPaint,
1060 gVertexMode2PrimitiveType[vmode],
1061 vertexCount,
1062 (GrPoint*) vertices,
1063 (GrPoint*) texs,
1064 NULL,
1065 indices,
1066 indexCount);
1067 } else
1068#endif
1069 {
1070 SkTexCoordSource texSrc(texs);
1071 SkColorSource colSrc(colors);
1072 SkIndexSource idxSrc(indices, indexCount);
1073
1074 fContext->drawCustomVertices(grPaint,
1075 gVertexMode2PrimitiveType[vmode],
1076 SkPositionSource(vertices, vertexCount),
1077 (NULL == texs) ? NULL : &texSrc,
1078 (NULL == colors) ? NULL : &colSrc,
1079 (NULL == indices) ? NULL : &idxSrc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001080 }
1081}
1082
1083///////////////////////////////////////////////////////////////////////////////
1084
1085static void GlyphCacheAuxProc(void* data) {
1086 delete (GrFontScaler*)data;
1087}
1088
1089static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) {
1090 void* auxData;
1091 GrFontScaler* scaler = NULL;
1092 if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
1093 scaler = (GrFontScaler*)auxData;
1094 }
1095 if (NULL == scaler) {
1096 scaler = new SkGrFontScaler(cache);
1097 cache->setAuxProc(GlyphCacheAuxProc, scaler);
1098 }
1099 return scaler;
1100}
1101
1102static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
1103 SkFixed fx, SkFixed fy,
1104 const SkGlyph& glyph) {
1105 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1106
1107 GrSkDrawProcs* procs = (GrSkDrawProcs*)state.fDraw->fProcs;
1108
1109 if (NULL == procs->fFontScaler) {
1110 procs->fFontScaler = get_gr_font_scaler(state.fCache);
1111 }
1112 procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0),
1113 SkIntToFixed(SkFixedFloor(fx)), fy,
1114 procs->fFontScaler);
1115}
1116
bsalomon@google.com5782d712011-01-21 21:03:59 +00001117SkDrawProcs* SkGpuDevice::initDrawForText(GrTextContext* context) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001118
1119 // deferred allocation
1120 if (NULL == fDrawProcs) {
1121 fDrawProcs = new GrSkDrawProcs;
1122 fDrawProcs->fD1GProc = SkGPU_Draw1Glyph;
1123 fDrawProcs->fContext = fContext;
1124 }
1125
1126 // init our (and GL's) state
1127 fDrawProcs->fTextContext = context;
1128 fDrawProcs->fFontScaler = NULL;
1129 return fDrawProcs;
1130}
1131
1132void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
1133 size_t byteLength, SkScalar x, SkScalar y,
1134 const SkPaint& paint) {
1135 CHECK_SHOULD_DRAW(draw);
1136
1137 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1138 // this guy will just call our drawPath()
1139 draw.drawText((const char*)text, byteLength, x, y, paint);
1140 } else {
1141 SkAutoExtMatrix aem(draw.fExtMatrix);
1142 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001143
1144 GrPaint grPaint;
1145 SkAutoCachedTexture act;
1146
1147 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1148 return;
1149 }
1150 GrTextContext context(fContext, grPaint, aem.extMatrix());
1151 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001152 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
1153 }
1154}
1155
1156void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
1157 size_t byteLength, const SkScalar pos[],
1158 SkScalar constY, int scalarsPerPos,
1159 const SkPaint& paint) {
1160 CHECK_SHOULD_DRAW(draw);
1161
1162 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1163 // this guy will just call our drawPath()
1164 draw.drawPosText((const char*)text, byteLength, pos, constY,
1165 scalarsPerPos, paint);
1166 } else {
1167 SkAutoExtMatrix aem(draw.fExtMatrix);
1168 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001169
1170 GrPaint grPaint;
1171 SkAutoCachedTexture act;
1172 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1173 return;
1174 }
1175
1176 GrTextContext context(fContext, grPaint, aem.extMatrix());
1177 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001178 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
1179 scalarsPerPos, paint);
1180 }
1181}
1182
1183void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
1184 size_t len, const SkPath& path,
1185 const SkMatrix* m, const SkPaint& paint) {
1186 CHECK_SHOULD_DRAW(draw);
1187
1188 SkASSERT(draw.fDevice == this);
1189 draw.drawTextOnPath((const char*)text, len, path, m, paint);
1190}
1191
1192///////////////////////////////////////////////////////////////////////////////
1193
1194SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
1195 const GrSamplerState& sampler,
1196 GrTexture** texture,
1197 bool forDeviceRenderTarget) {
1198 GrContext* ctx = this->context();
1199 uint32_t p0, p1;
1200 if (forDeviceRenderTarget) {
1201 p0 = p1 = -1;
1202 } else {
1203 p0 = bitmap.getGenerationID();
1204 p1 = bitmap.pixelRefOffset();
1205 }
1206
1207 GrTexture* newTexture = NULL;
1208 GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
1209 GrTextureEntry* entry = ctx->findAndLockTexture(&key, sampler);
1210
1211 if (NULL == entry) {
1212
1213 if (forDeviceRenderTarget) {
1214 const GrGpu::TextureDesc desc = {
1215 GrGpu::kRenderTarget_TextureFlag,
1216 GrGpu::kNone_AALevel,
1217 bitmap.width(),
1218 bitmap.height(),
1219 SkGr::Bitmap2PixelConfig(bitmap)
1220 };
1221 entry = ctx->createAndLockTexture(&key, sampler, desc, NULL, 0);
1222
1223 } else {
1224 entry = sk_gr_create_bitmap_texture(ctx, &key, sampler, bitmap);
1225 }
1226 if (NULL == entry) {
1227 GrPrintf("---- failed to create texture for cache [%d %d]\n",
1228 bitmap.width(), bitmap.height());
1229 }
1230 }
1231
1232 if (NULL != entry) {
1233 newTexture = entry->texture();
reed@google.comac10a2d2010-12-22 21:39:39 +00001234 if (texture) {
1235 *texture = newTexture;
1236 }
1237 // IMPORTANT: We can't allow another SkGpuDevice to get this
1238 // cache entry until this one is destroyed!
1239 if (forDeviceRenderTarget) {
1240 ctx->detachCachedTexture(entry);
1241 }
1242 }
1243 return (TexCache*)entry;
1244}
1245
1246void SkGpuDevice::unlockCachedTexture(TexCache* cache) {
1247 this->context()->unlockTexture((GrTextureEntry*)cache);
1248}
1249
reed@google.com7b201d22011-01-11 18:59:23 +00001250///////////////////////////////////////////////////////////////////////////////
1251
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001252SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context,
1253 GrRenderTarget* rootRenderTarget)
1254 : fContext(context) {
1255
1256 GrAssert(NULL != context);
1257 GrAssert(NULL != rootRenderTarget);
1258
1259 // check this now rather than passing this value to SkGpuDevice cons.
1260 // we want the rt that is bound *now* in the 3D API, not the one
1261 // at the time of newDevice.
1262 if (SkGpuDevice::Current3DApiRenderTarget() == rootRenderTarget) {
1263 fRootRenderTarget = context->createRenderTargetFrom3DApiState();
1264 } else {
1265 fRootRenderTarget = rootRenderTarget;
1266 rootRenderTarget->ref();
1267 }
reed@google.com7b201d22011-01-11 18:59:23 +00001268 context->ref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001269
reed@google.com7b201d22011-01-11 18:59:23 +00001270}
1271
1272SkGpuDeviceFactory::~SkGpuDeviceFactory() {
1273 fContext->unref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001274 fRootRenderTarget->unref();
reed@google.com7b201d22011-01-11 18:59:23 +00001275}
1276
1277SkDevice* SkGpuDeviceFactory::newDevice(SkCanvas*, SkBitmap::Config config,
1278 int width, int height,
1279 bool isOpaque, bool isLayer) {
1280 SkBitmap bm;
1281 bm.setConfig(config, width, height);
1282 bm.setIsOpaque(isOpaque);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001283 return new SkGpuDevice(fContext, bm, isLayer ? NULL : fRootRenderTarget);
reed@google.com7b201d22011-01-11 18:59:23 +00001284}
reed@google.comac10a2d2010-12-22 21:39:39 +00001285