blob: 3707b67119b349dbcfbfef8ad5654624a009b117 [file] [log] [blame]
reed@google.comac10a2d2010-12-22 21:39:39 +00001/*
bsalomon@google.com1da07462011-03-10 14:51:57 +00002 Copyright 2011 Google Inc.
reed@google.comac10a2d2010-12-22 21:39:39 +00003
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);
bsalomon@google.com1da07462011-03-10 14:51:57 +0000145 SkASSERT(NULL != fTexture->asRenderTarget());
reed@google.comac10a2d2010-12-22 21:39:39 +0000146 }
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,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000271 const SkClipStack& clipStack,
reed@google.com6f8f2922011-03-04 22:27:10 +0000272 const SkRegion& clipRegion,
273 const SkIPoint& origin) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000274 GrMatrix grmat;
275 SkGr::SkMatrix2GrMatrix(matrix, &grmat);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000276 context->setMatrix(grmat);
reed@google.comac10a2d2010-12-22 21:39:39 +0000277
278 SkGrClipIterator iter;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000279 iter.reset(clipStack);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000280 const SkIRect& skBounds = clipRegion.getBounds();
281 GrRect bounds;
282 bounds.setLTRB(GrIntToScalar(skBounds.fLeft),
283 GrIntToScalar(skBounds.fTop),
284 GrIntToScalar(skBounds.fRight),
285 GrIntToScalar(skBounds.fBottom));
reed@google.com6f8f2922011-03-04 22:27:10 +0000286 GrClip grc(&iter, GrIntToScalar(-origin.x()), GrIntToScalar(-origin.y()),
287 &bounds);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000288 context->setClip(grc);
reed@google.comac10a2d2010-12-22 21:39:39 +0000289}
290
291// call this ever each draw call, to ensure that the context reflects our state,
292// and not the state from some other canvas/device
293void SkGpuDevice::prepareRenderTarget(const SkDraw& draw) {
294 if (fNeedPrepareRenderTarget ||
bsalomon@google.com5782d712011-01-21 21:03:59 +0000295 fContext->getRenderTarget() != fRenderTarget) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000296
297 fContext->setRenderTarget(fRenderTarget);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000298 SkASSERT(draw.fClipStack);
299 convert_matrixclip(fContext, *draw.fMatrix,
reed@google.com6f8f2922011-03-04 22:27:10 +0000300 *draw.fClipStack, *draw.fClip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000301 fNeedPrepareRenderTarget = false;
302 }
303}
304
reed@google.com46799cd2011-02-22 20:56:26 +0000305void SkGpuDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& clip,
306 const SkClipStack& clipStack) {
307 this->INHERITED::setMatrixClip(matrix, clip, clipStack);
reed@google.comac10a2d2010-12-22 21:39:39 +0000308
reed@google.com6f8f2922011-03-04 22:27:10 +0000309 convert_matrixclip(fContext, matrix, clipStack, clip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000310}
311
312void SkGpuDevice::gainFocus(SkCanvas* canvas, const SkMatrix& matrix,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000313 const SkRegion& clip, const SkClipStack& clipStack) {
314
reed@google.comac10a2d2010-12-22 21:39:39 +0000315 fContext->setRenderTarget(fRenderTarget);
316
bsalomon@google.comd302f142011-03-03 13:54:13 +0000317 this->INHERITED::gainFocus(canvas, matrix, clip, clipStack);
reed@google.comac10a2d2010-12-22 21:39:39 +0000318
reed@google.com6f8f2922011-03-04 22:27:10 +0000319 convert_matrixclip(fContext, matrix, clipStack, clip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000320
321 if (fNeedClear) {
322 fContext->eraseColor(0x0);
323 fNeedClear = false;
324 }
325}
326
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000327bool SkGpuDevice::bindDeviceAsTexture(GrPaint* paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000328 if (NULL != fTexture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000329 paint->setTexture(fTexture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000330 return true;
331 }
332 return false;
333}
334
335///////////////////////////////////////////////////////////////////////////////
336
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000337SK_COMPILE_ASSERT(SkShader::kNone_BitmapType == 0, shader_type_mismatch);
338SK_COMPILE_ASSERT(SkShader::kDefault_BitmapType == 1, shader_type_mismatch);
339SK_COMPILE_ASSERT(SkShader::kRadial_BitmapType == 2, shader_type_mismatch);
340SK_COMPILE_ASSERT(SkShader::kSweep_BitmapType == 3, shader_type_mismatch);
341SK_COMPILE_ASSERT(SkShader::kTwoPointRadial_BitmapType == 4,
342 shader_type_mismatch);
343SK_COMPILE_ASSERT(SkShader::kLast_BitmapType == 4, shader_type_mismatch);
reed@google.comac10a2d2010-12-22 21:39:39 +0000344
bsalomon@google.com5782d712011-01-21 21:03:59 +0000345static const GrSamplerState::SampleMode sk_bmp_type_to_sample_mode[] = {
346 (GrSamplerState::SampleMode) -1, // kNone_BitmapType
347 GrSamplerState::kNormal_SampleMode, // kDefault_BitmapType
348 GrSamplerState::kRadial_SampleMode, // kRadial_BitmapType
349 GrSamplerState::kSweep_SampleMode, // kSweep_BitmapType
350 GrSamplerState::kRadial2_SampleMode, // kTwoPointRadial_BitmapType
351};
352
353bool SkGpuDevice::skPaint2GrPaintNoShader(const SkPaint& skPaint,
354 bool justAlpha,
355 GrPaint* grPaint) {
356
357 grPaint->fDither = skPaint.isDither();
358 grPaint->fAntiAlias = skPaint.isAntiAlias();
359
360 SkXfermode::Coeff sm = SkXfermode::kOne_Coeff;
361 SkXfermode::Coeff dm = SkXfermode::kISA_Coeff;
362
363 SkXfermode* mode = skPaint.getXfermode();
364 if (mode) {
365 if (!mode->asCoeff(&sm, &dm)) {
reed@google.com1a2e8d22011-01-21 22:08:29 +0000366 SkDEBUGCODE(SkDebugf("Unsupported xfer mode.\n");)
bsalomon@google.com5782d712011-01-21 21:03:59 +0000367#if 0
368 return false;
369#endif
370 }
371 }
372 grPaint->fSrcBlendCoeff = sk_blend_to_grblend(sm);
373 grPaint->fDstBlendCoeff = sk_blend_to_grblend(dm);
374
375 if (justAlpha) {
376 uint8_t alpha = skPaint.getAlpha();
377 grPaint->fColor = GrColorPackRGBA(alpha, alpha, alpha, alpha);
378 } else {
379 grPaint->fColor = SkGr::SkColor2GrColor(skPaint.getColor());
380 grPaint->setTexture(NULL);
381 }
382 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000383}
384
bsalomon@google.com5782d712011-01-21 21:03:59 +0000385bool SkGpuDevice::skPaint2GrPaintShader(const SkPaint& skPaint,
386 SkAutoCachedTexture* act,
387 const SkMatrix& ctm,
388 GrPaint* grPaint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000389
bsalomon@google.com5782d712011-01-21 21:03:59 +0000390 SkASSERT(NULL != act);
reed@google.comac10a2d2010-12-22 21:39:39 +0000391
bsalomon@google.com5782d712011-01-21 21:03:59 +0000392 SkShader* shader = skPaint.getShader();
reed@google.comac10a2d2010-12-22 21:39:39 +0000393 if (NULL == shader) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000394 return this->skPaint2GrPaintNoShader(skPaint, false, grPaint);
395 grPaint->setTexture(NULL);
396 return true;
397 } else if (!this->skPaint2GrPaintNoShader(skPaint, true, grPaint)) {
398 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000399 }
400
bsalomon@google.com5782d712011-01-21 21:03:59 +0000401 SkPaint noAlphaPaint(skPaint);
402 noAlphaPaint.setAlpha(255);
403 shader->setContext(this->accessBitmap(false), noAlphaPaint, ctm);
reed@google.comac10a2d2010-12-22 21:39:39 +0000404
reed@google.comac10a2d2010-12-22 21:39:39 +0000405 SkBitmap bitmap;
406 SkMatrix matrix;
407 SkShader::TileMode tileModes[2];
408 SkScalar twoPointParams[3];
409 SkShader::BitmapType bmptype = shader->asABitmap(&bitmap, &matrix,
410 tileModes, twoPointParams);
411
bsalomon@google.com5782d712011-01-21 21:03:59 +0000412 GrSamplerState::SampleMode sampleMode = sk_bmp_type_to_sample_mode[bmptype];
413 if (-1 == sampleMode) {
414 SkDebugf("shader->asABitmap() == kNone_BitmapType\n");
415 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000416 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000417 grPaint->fSampler.setSampleMode(sampleMode);
bsalomon@google.com0748f212011-02-01 22:56:16 +0000418 grPaint->fSampler.setFilter(skPaint.isFilterBitmap());
bsalomon@google.com5782d712011-01-21 21:03:59 +0000419 grPaint->fSampler.setWrapX(sk_tile_mode_to_grwrap(tileModes[0]));
420 grPaint->fSampler.setWrapY(sk_tile_mode_to_grwrap(tileModes[1]));
reed@google.comac10a2d2010-12-22 21:39:39 +0000421 if (GrSamplerState::kRadial2_SampleMode == sampleMode) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000422 grPaint->fSampler.setRadial2Params(twoPointParams[0],
423 twoPointParams[1],
424 twoPointParams[2] < 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000425 }
426
bsalomon@google.com5782d712011-01-21 21:03:59 +0000427 GrTexture* texture = act->set(this, bitmap, grPaint->fSampler);
reed@google.comac10a2d2010-12-22 21:39:39 +0000428 if (NULL == texture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000429 SkDebugf("Couldn't convert bitmap to texture.\n");
430 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000431 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000432 grPaint->setTexture(texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000433
434 // since our texture coords will be in local space, we wack the texture
435 // matrix to map them back into 0...1 before we load it
436 SkMatrix localM;
437 if (shader->getLocalMatrix(&localM)) {
438 SkMatrix inverse;
439 if (localM.invert(&inverse)) {
440 matrix.preConcat(inverse);
441 }
442 }
443 if (SkShader::kDefault_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000444 GrScalar sx = GrFixedToScalar(GR_Fixed1 / bitmap.width());
445 GrScalar sy = GrFixedToScalar(GR_Fixed1 / bitmap.height());
reed@google.comac10a2d2010-12-22 21:39:39 +0000446 matrix.postScale(sx, sy);
reed@google.comac10a2d2010-12-22 21:39:39 +0000447 } else if (SkShader::kRadial_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000448 GrScalar s = GrFixedToScalar(GR_Fixed1 / bitmap.width());
reed@google.comac10a2d2010-12-22 21:39:39 +0000449 matrix.postScale(s, s);
450 }
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000451 GrMatrix grMat;
452 SkGr::SkMatrix2GrMatrix(matrix, &grMat);
453 grPaint->fSampler.setMatrix(grMat);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000454
455 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000456}
457
458///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com5782d712011-01-21 21:03:59 +0000459
460class SkPositionSource {
461public:
462 SkPositionSource(const SkPoint* points, int count)
463 : fPoints(points), fCount(count) {}
464
465 int count() const { return fCount; }
466
467 void writeValue(int i, GrPoint* dstPosition) const {
468 SkASSERT(i < fCount);
469 dstPosition->fX = SkScalarToGrScalar(fPoints[i].fX);
470 dstPosition->fY = SkScalarToGrScalar(fPoints[i].fY);
471 }
472private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000473 const SkPoint* fPoints;
bsalomon@google.com19628322011-02-03 21:30:17 +0000474 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000475};
476
477class SkTexCoordSource {
478public:
479 SkTexCoordSource(const SkPoint* coords)
480 : fCoords(coords) {}
481
482 void writeValue(int i, GrPoint* dstCoord) const {
483 dstCoord->fX = SkScalarToGrScalar(fCoords[i].fX);
484 dstCoord->fY = SkScalarToGrScalar(fCoords[i].fY);
485 }
486private:
487 const SkPoint* fCoords;
488};
489
490class SkColorSource {
491public:
492 SkColorSource(const SkColor* colors) : fColors(colors) {}
493
494 void writeValue(int i, GrColor* dstColor) const {
495 *dstColor = SkGr::SkColor2GrColor(fColors[i]);
496 }
497private:
498 const SkColor* fColors;
499};
500
501class SkIndexSource {
502public:
503 SkIndexSource(const uint16_t* indices, int count)
504 : fIndices(indices), fCount(count) {
505 }
506
507 int count() const { return fCount; }
508
509 void writeValue(int i, uint16_t* dstIndex) const {
510 *dstIndex = fIndices[i];
511 }
512
513private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000514 const uint16_t* fIndices;
bsalomon@google.com19628322011-02-03 21:30:17 +0000515 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000516};
517
518///////////////////////////////////////////////////////////////////////////////
519
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000520#if 0 // not currently being used so don't compile,
521
bsalomon@google.com5782d712011-01-21 21:03:59 +0000522// can be used for positions or texture coordinates
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000523
bsalomon@google.com5782d712011-01-21 21:03:59 +0000524class SkRectFanSource {
525public:
526 SkRectFanSource(const SkRect& rect) : fRect(rect) {}
527
528 int count() const { return 4; }
529
530 void writeValue(int i, GrPoint* dstPoint) const {
531 SkASSERT(i < 4);
532 dstPoint->fX = SkScalarToGrScalar((i % 3) ? fRect.fRight :
533 fRect.fLeft);
534 dstPoint->fY = SkScalarToGrScalar((i < 2) ? fRect.fTop :
535 fRect.fBottom);
536 }
537private:
538 const SkRect& fRect;
539};
540
541class SkIRectFanSource {
542public:
543 SkIRectFanSource(const SkIRect& rect) : fRect(rect) {}
544
545 int count() const { return 4; }
546
547 void writeValue(int i, GrPoint* dstPoint) const {
548 SkASSERT(i < 4);
549 dstPoint->fX = (i % 3) ? GrIntToScalar(fRect.fRight) :
550 GrIntToScalar(fRect.fLeft);
551 dstPoint->fY = (i < 2) ? GrIntToScalar(fRect.fTop) :
552 GrIntToScalar(fRect.fBottom);
553 }
554private:
555 const SkIRect& fRect;
556};
557
558class SkMatRectFanSource {
559public:
560 SkMatRectFanSource(const SkRect& rect, const SkMatrix& matrix)
561 : fRect(rect), fMatrix(matrix) {}
562
563 int count() const { return 4; }
564
565 void writeValue(int i, GrPoint* dstPoint) const {
566 SkASSERT(i < 4);
567
568#if SK_SCALAR_IS_GR_SCALAR
569 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
570 (i < 2) ? fRect.fTop : fRect.fBottom,
571 (SkPoint*)dstPoint);
572#else
573 SkPoint dst;
574 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
575 (i < 2) ? fRect.fTop : fRect.fBottom,
576 &dst);
577 dstPoint->fX = SkScalarToGrScalar(dst.fX);
578 dstPoint->fY = SkScalarToGrScalar(dst.fY);
579#endif
580 }
581private:
582 const SkRect& fRect;
583 const SkMatrix& fMatrix;
584};
585
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000586#endif
587
reed@google.comac10a2d2010-12-22 21:39:39 +0000588///////////////////////////////////////////////////////////////////////////////
589
590void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
591 CHECK_SHOULD_DRAW(draw);
592
bsalomon@google.com5782d712011-01-21 21:03:59 +0000593 GrPaint grPaint;
594 SkAutoCachedTexture act;
595 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000596 return;
597 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000598
599 fContext->drawPaint(grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000600}
601
602// must be in SkCanvas::PointMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +0000603static const GrPrimitiveType gPointMode2PrimtiveType[] = {
604 kPoints_PrimitiveType,
605 kLines_PrimitiveType,
606 kLineStrip_PrimitiveType
reed@google.comac10a2d2010-12-22 21:39:39 +0000607};
608
609void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000610 size_t count, const SkPoint pts[], const SkPaint& paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000611 CHECK_SHOULD_DRAW(draw);
612
613 SkScalar width = paint.getStrokeWidth();
614 if (width < 0) {
615 return;
616 }
617
618 // we only handle hairlines here, else we let the SkDraw call our drawPath()
619 if (width > 0) {
620 draw.drawPoints(mode, count, pts, paint, true);
621 return;
622 }
623
bsalomon@google.com5782d712011-01-21 21:03:59 +0000624 GrPaint grPaint;
625 SkAutoCachedTexture act;
626 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000627 return;
628 }
629
reed@google.comac10a2d2010-12-22 21:39:39 +0000630#if SK_SCALAR_IS_GR_SCALAR
bsalomon@google.com5782d712011-01-21 21:03:59 +0000631 fContext->drawVertices(grPaint,
632 gPointMode2PrimtiveType[mode],
633 count,
634 (GrPoint*)pts,
635 NULL,
636 NULL,
637 NULL,
638 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000639#else
bsalomon@google.com5782d712011-01-21 21:03:59 +0000640 fContext->drawCustomVertices(grPaint,
641 gPointMode2PrimtiveType[mode],
642 SkPositionSource(pts, count));
reed@google.comac10a2d2010-12-22 21:39:39 +0000643#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000644}
645
646void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
647 const SkPaint& paint) {
648 CHECK_SHOULD_DRAW(draw);
649
650 bool doStroke = paint.getStyle() == SkPaint::kStroke_Style;
651 SkScalar width = paint.getStrokeWidth();
652
653 /*
654 We have special code for hairline strokes, miter-strokes, and fills.
reed@google.com69302852011-02-16 18:08:07 +0000655 Anything else we just call our path code.
reed@google.comac10a2d2010-12-22 21:39:39 +0000656 */
reed@google.com69302852011-02-16 18:08:07 +0000657 bool usePath = doStroke && width > 0 &&
658 paint.getStrokeJoin() != SkPaint::kMiter_Join;
659 // another reason we might need to call drawPath...
660 if (paint.getMaskFilter()) {
661 usePath = true;
662 }
663
664 if (usePath) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000665 SkPath path;
666 path.addRect(rect);
667 this->drawPath(draw, path, paint, NULL, true);
668 return;
669 }
670
bsalomon@google.com5782d712011-01-21 21:03:59 +0000671 GrPaint grPaint;
672 SkAutoCachedTexture act;
673 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000674 return;
675 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000676 fContext->drawRect(grPaint, Sk2Gr(rect), doStroke ? width : -1);
reed@google.comac10a2d2010-12-22 21:39:39 +0000677}
678
reed@google.com69302852011-02-16 18:08:07 +0000679#include "SkMaskFilter.h"
680#include "SkBounder.h"
681
reed@google.com69302852011-02-16 18:08:07 +0000682static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
683 SkMaskFilter* filter, const SkMatrix& matrix,
684 const SkRegion& clip, SkBounder* bounder,
685 GrPaint* grp) {
686 SkMask srcM, dstM;
687
688 if (!SkDraw::DrawToMask(path, &clip.getBounds(), filter, &matrix, &srcM,
689 SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
690 return false;
691 }
692
693 SkAutoMaskImage autoSrc(&srcM, false);
694
695 if (!filter->filterMask(&dstM, srcM, matrix, NULL)) {
696 return false;
697 }
698 // this will free-up dstM when we're done (allocated in filterMask())
699 SkAutoMaskImage autoDst(&dstM, false);
700
701 if (clip.quickReject(dstM.fBounds)) {
702 return false;
703 }
704 if (bounder && !bounder->doIRect(dstM.fBounds)) {
705 return false;
706 }
707
708 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
709 // the current clip (and identity matrix) and grpaint settings
710
reed@google.com0c219b62011-02-16 21:31:18 +0000711 GrAutoMatrix avm(context, GrMatrix::I());
reed@google.com69302852011-02-16 18:08:07 +0000712
713 const GrGpu::TextureDesc desc = {
714 0,
715 GrGpu::kNone_AALevel,
716 dstM.fBounds.width(),
717 dstM.fBounds.height(),
718 GrTexture::kAlpha_8_PixelConfig
719 };
720
721 GrTexture* texture = context->createUncachedTexture(desc, dstM.fImage,
722 dstM.fRowBytes);
723 if (NULL == texture) {
724 return false;
725 }
726
reed@google.com0c219b62011-02-16 21:31:18 +0000727 grp->setTexture(texture);
728 texture->unref();
729 grp->fSampler.setClampNoFilter();
reed@google.com69302852011-02-16 18:08:07 +0000730
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000731 GrRect d;
732 d.setLTRB(GrIntToScalar(dstM.fBounds.fLeft),
reed@google.com0c219b62011-02-16 21:31:18 +0000733 GrIntToScalar(dstM.fBounds.fTop),
734 GrIntToScalar(dstM.fBounds.fRight),
735 GrIntToScalar(dstM.fBounds.fBottom));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000736 GrRect s;
737 s.setLTRB(0, 0, GR_Scalar1, GR_Scalar1);
738 context->drawRectToRect(*grp, d, s);
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
bsalomon@google.comffca4002011-02-22 20:34:01 +0000793 GrPathFill fill = kHairLine_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000794
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:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000798 fill = kWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000799 break;
800 case SkPath::kEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000801 fill = kEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000802 break;
803 case SkPath::kInverseWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000804 fill = kInverseWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000805 break;
806 case SkPath::kInverseEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000807 fill = kInverseEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000808 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);
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000922 grPaint->fSampler.setMatrix(GrMatrix::I());
reed@google.comac10a2d2010-12-22 21:39:39 +0000923
924 GrTexture* texture;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000925 SkAutoCachedTexture act(this, bitmap, grPaint->fSampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000926 if (NULL == texture) {
927 return;
928 }
929
bsalomon@google.com5782d712011-01-21 21:03:59 +0000930 grPaint->setTexture(texture);
reed@google.com46799cd2011-02-22 20:56:26 +0000931
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000932 GrRect dstRect(0, 0, GrIntToScalar(srcRect.width()), GrIntToScalar(srcRect.height()));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000933 GrRect paintRect;
934 paintRect.setLTRB(GrFixedToScalar((srcRect.fLeft << 16) / bitmap.width()),
935 GrFixedToScalar((srcRect.fTop << 16) / bitmap.height()),
936 GrFixedToScalar((srcRect.fRight << 16) / bitmap.width()),
937 GrFixedToScalar((srcRect.fBottom << 16) / bitmap.height()));
reed@google.comac10a2d2010-12-22 21:39:39 +0000938
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000939 GrMatrix grMat;
940 SkGr::SkMatrix2GrMatrix(m, &grMat);
reed@google.comac10a2d2010-12-22 21:39:39 +0000941
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000942 fContext->drawRectToRect(*grPaint, dstRect, paintRect, &grMat);
reed@google.comac10a2d2010-12-22 21:39:39 +0000943}
944
945void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
946 int left, int top, const SkPaint& paint) {
947 CHECK_SHOULD_DRAW(draw);
948
949 SkAutoLockPixels alp(bitmap);
950 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
951 return;
952 }
953
bsalomon@google.com5782d712011-01-21 21:03:59 +0000954 GrPaint grPaint;
955 if(!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
956 return;
957 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000958
bsalomon@google.com5782d712011-01-21 21:03:59 +0000959 GrAutoMatrix avm(fContext, GrMatrix::I());
960
961 GrTexture* texture;
962 grPaint.fSampler.setClampNoFilter();
963 SkAutoCachedTexture act(this, bitmap, grPaint.fSampler, &texture);
964
bsalomon@google.com5782d712011-01-21 21:03:59 +0000965 grPaint.setTexture(texture);
966
bsalomon@google.com5782d712011-01-21 21:03:59 +0000967 fContext->drawRectToRect(grPaint,
968 GrRect(GrIntToScalar(left), GrIntToScalar(top),
969 GrIntToScalar(left + bitmap.width()),
970 GrIntToScalar(top + bitmap.height())),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000971 GrRect(0, 0, GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +0000972}
973
974void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
975 int x, int y, const SkPaint& paint) {
976 CHECK_SHOULD_DRAW(draw);
977
bsalomon@google.com5782d712011-01-21 21:03:59 +0000978 GrPaint grPaint;
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000979 if (!((SkGpuDevice*)dev)->bindDeviceAsTexture(&grPaint) ||
bsalomon@google.com5782d712011-01-21 21:03:59 +0000980 !this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
981 return;
reed@google.comac10a2d2010-12-22 21:39:39 +0000982 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000983
984 SkASSERT(NULL != grPaint.getTexture());
985
986 const SkBitmap& bm = dev->accessBitmap(false);
987 int w = bm.width();
988 int h = bm.height();
989
990 GrAutoMatrix avm(fContext, GrMatrix::I());
991
992 grPaint.fSampler.setClampNoFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +0000993
994 fContext->drawRectToRect(grPaint,
reed@google.com1a2e8d22011-01-21 22:08:29 +0000995 GrRect(GrIntToScalar(x),
996 GrIntToScalar(y),
997 GrIntToScalar(x + w),
bsalomon@google.com5782d712011-01-21 21:03:59 +0000998 GrIntToScalar(y + h)),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000999 GrRect(0, 0, GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001000}
1001
1002///////////////////////////////////////////////////////////////////////////////
1003
1004// must be in SkCanvas::VertexMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +00001005static const GrPrimitiveType gVertexMode2PrimitiveType[] = {
1006 kTriangles_PrimitiveType,
1007 kTriangleStrip_PrimitiveType,
1008 kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +00001009};
1010
1011void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
1012 int vertexCount, const SkPoint vertices[],
1013 const SkPoint texs[], const SkColor colors[],
1014 SkXfermode* xmode,
1015 const uint16_t indices[], int indexCount,
1016 const SkPaint& paint) {
1017 CHECK_SHOULD_DRAW(draw);
1018
bsalomon@google.com5782d712011-01-21 21:03:59 +00001019 GrPaint grPaint;
1020 SkAutoCachedTexture act;
1021 // we ignore the shader if texs is null.
1022 if (NULL == texs) {
1023 if (!this->skPaint2GrPaintNoShader(paint, false, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001024 return;
1025 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001026 } else {
reed@google.com1a2e8d22011-01-21 22:08:29 +00001027 if (!this->skPaint2GrPaintShader(paint, &act,
1028 *draw.fMatrix,
bsalomon@google.com5782d712011-01-21 21:03:59 +00001029 &grPaint)) {
1030 return;
1031 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001032 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001033
1034 if (NULL != xmode && NULL != texs && NULL != colors) {
1035 SkXfermode::Mode mode;
1036 if (!SkXfermode::IsMode(xmode, &mode) ||
1037 SkXfermode::kMultiply_Mode != mode) {
1038 SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
1039#if 0
1040 return
1041#endif
1042 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001043 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001044
1045#if SK_SCALAR_IS_GR_SCALAR
1046 // even if GrColor and SkColor byte offsets match we need
1047 // to perform pre-multiply.
1048 if (NULL == colors) {
1049 fContext->drawVertices(grPaint,
1050 gVertexMode2PrimitiveType[vmode],
1051 vertexCount,
1052 (GrPoint*) vertices,
1053 (GrPoint*) texs,
1054 NULL,
1055 indices,
1056 indexCount);
1057 } else
1058#endif
1059 {
1060 SkTexCoordSource texSrc(texs);
1061 SkColorSource colSrc(colors);
1062 SkIndexSource idxSrc(indices, indexCount);
1063
1064 fContext->drawCustomVertices(grPaint,
1065 gVertexMode2PrimitiveType[vmode],
1066 SkPositionSource(vertices, vertexCount),
1067 (NULL == texs) ? NULL : &texSrc,
1068 (NULL == colors) ? NULL : &colSrc,
1069 (NULL == indices) ? NULL : &idxSrc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001070 }
1071}
1072
1073///////////////////////////////////////////////////////////////////////////////
1074
1075static void GlyphCacheAuxProc(void* data) {
1076 delete (GrFontScaler*)data;
1077}
1078
1079static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) {
1080 void* auxData;
1081 GrFontScaler* scaler = NULL;
1082 if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
1083 scaler = (GrFontScaler*)auxData;
1084 }
1085 if (NULL == scaler) {
1086 scaler = new SkGrFontScaler(cache);
1087 cache->setAuxProc(GlyphCacheAuxProc, scaler);
1088 }
1089 return scaler;
1090}
1091
1092static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
1093 SkFixed fx, SkFixed fy,
1094 const SkGlyph& glyph) {
1095 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1096
1097 GrSkDrawProcs* procs = (GrSkDrawProcs*)state.fDraw->fProcs;
1098
1099 if (NULL == procs->fFontScaler) {
1100 procs->fFontScaler = get_gr_font_scaler(state.fCache);
1101 }
1102 procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0),
1103 SkIntToFixed(SkFixedFloor(fx)), fy,
1104 procs->fFontScaler);
1105}
1106
bsalomon@google.com5782d712011-01-21 21:03:59 +00001107SkDrawProcs* SkGpuDevice::initDrawForText(GrTextContext* context) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001108
1109 // deferred allocation
1110 if (NULL == fDrawProcs) {
1111 fDrawProcs = new GrSkDrawProcs;
1112 fDrawProcs->fD1GProc = SkGPU_Draw1Glyph;
1113 fDrawProcs->fContext = fContext;
1114 }
1115
1116 // init our (and GL's) state
1117 fDrawProcs->fTextContext = context;
1118 fDrawProcs->fFontScaler = NULL;
1119 return fDrawProcs;
1120}
1121
1122void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
1123 size_t byteLength, SkScalar x, SkScalar y,
1124 const SkPaint& paint) {
1125 CHECK_SHOULD_DRAW(draw);
1126
1127 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1128 // this guy will just call our drawPath()
1129 draw.drawText((const char*)text, byteLength, x, y, paint);
1130 } else {
1131 SkAutoExtMatrix aem(draw.fExtMatrix);
1132 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001133
1134 GrPaint grPaint;
1135 SkAutoCachedTexture act;
1136
1137 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1138 return;
1139 }
1140 GrTextContext context(fContext, grPaint, aem.extMatrix());
1141 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001142 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
1143 }
1144}
1145
1146void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
1147 size_t byteLength, const SkScalar pos[],
1148 SkScalar constY, int scalarsPerPos,
1149 const SkPaint& paint) {
1150 CHECK_SHOULD_DRAW(draw);
1151
1152 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1153 // this guy will just call our drawPath()
1154 draw.drawPosText((const char*)text, byteLength, pos, constY,
1155 scalarsPerPos, paint);
1156 } else {
1157 SkAutoExtMatrix aem(draw.fExtMatrix);
1158 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001159
1160 GrPaint grPaint;
1161 SkAutoCachedTexture act;
1162 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1163 return;
1164 }
1165
1166 GrTextContext context(fContext, grPaint, aem.extMatrix());
1167 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001168 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
1169 scalarsPerPos, paint);
1170 }
1171}
1172
1173void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
1174 size_t len, const SkPath& path,
1175 const SkMatrix* m, const SkPaint& paint) {
1176 CHECK_SHOULD_DRAW(draw);
1177
1178 SkASSERT(draw.fDevice == this);
1179 draw.drawTextOnPath((const char*)text, len, path, m, paint);
1180}
1181
1182///////////////////////////////////////////////////////////////////////////////
1183
reed@google.comf67e4cf2011-03-15 20:56:58 +00001184bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
1185 if (!paint.isLCDRenderText()) {
1186 // we're cool with the paint as is
1187 return false;
1188 }
1189
1190 if (paint.getShader() ||
1191 paint.getXfermode() || // unless its srcover
1192 paint.getMaskFilter() ||
1193 paint.getRasterizer() ||
1194 paint.getColorFilter() ||
1195 paint.getPathEffect() ||
1196 paint.isFakeBoldText() ||
1197 paint.getStyle() != SkPaint::kFill_Style) {
1198 // turn off lcd
1199 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
1200 flags->fHinting = paint.getHinting();
1201 return true;
1202 }
1203 // we're cool with the paint as is
1204 return false;
1205}
1206
1207///////////////////////////////////////////////////////////////////////////////
1208
reed@google.comac10a2d2010-12-22 21:39:39 +00001209SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
1210 const GrSamplerState& sampler,
1211 GrTexture** texture,
1212 bool forDeviceRenderTarget) {
1213 GrContext* ctx = this->context();
1214 uint32_t p0, p1;
1215 if (forDeviceRenderTarget) {
1216 p0 = p1 = -1;
1217 } else {
1218 p0 = bitmap.getGenerationID();
1219 p1 = bitmap.pixelRefOffset();
1220 }
1221
1222 GrTexture* newTexture = NULL;
1223 GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
1224 GrTextureEntry* entry = ctx->findAndLockTexture(&key, sampler);
1225
1226 if (NULL == entry) {
1227
1228 if (forDeviceRenderTarget) {
1229 const GrGpu::TextureDesc desc = {
1230 GrGpu::kRenderTarget_TextureFlag,
1231 GrGpu::kNone_AALevel,
1232 bitmap.width(),
1233 bitmap.height(),
1234 SkGr::Bitmap2PixelConfig(bitmap)
1235 };
1236 entry = ctx->createAndLockTexture(&key, sampler, desc, NULL, 0);
1237
1238 } else {
1239 entry = sk_gr_create_bitmap_texture(ctx, &key, sampler, bitmap);
1240 }
1241 if (NULL == entry) {
1242 GrPrintf("---- failed to create texture for cache [%d %d]\n",
1243 bitmap.width(), bitmap.height());
1244 }
1245 }
1246
1247 if (NULL != entry) {
1248 newTexture = entry->texture();
reed@google.comac10a2d2010-12-22 21:39:39 +00001249 if (texture) {
1250 *texture = newTexture;
1251 }
1252 // IMPORTANT: We can't allow another SkGpuDevice to get this
1253 // cache entry until this one is destroyed!
1254 if (forDeviceRenderTarget) {
1255 ctx->detachCachedTexture(entry);
1256 }
1257 }
1258 return (TexCache*)entry;
1259}
1260
1261void SkGpuDevice::unlockCachedTexture(TexCache* cache) {
1262 this->context()->unlockTexture((GrTextureEntry*)cache);
1263}
1264
reed@google.com7b201d22011-01-11 18:59:23 +00001265///////////////////////////////////////////////////////////////////////////////
1266
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001267SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context,
1268 GrRenderTarget* rootRenderTarget)
1269 : fContext(context) {
1270
1271 GrAssert(NULL != context);
1272 GrAssert(NULL != rootRenderTarget);
1273
1274 // check this now rather than passing this value to SkGpuDevice cons.
1275 // we want the rt that is bound *now* in the 3D API, not the one
1276 // at the time of newDevice.
1277 if (SkGpuDevice::Current3DApiRenderTarget() == rootRenderTarget) {
1278 fRootRenderTarget = context->createRenderTargetFrom3DApiState();
1279 } else {
1280 fRootRenderTarget = rootRenderTarget;
1281 rootRenderTarget->ref();
1282 }
reed@google.com7b201d22011-01-11 18:59:23 +00001283 context->ref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001284
reed@google.com7b201d22011-01-11 18:59:23 +00001285}
1286
1287SkGpuDeviceFactory::~SkGpuDeviceFactory() {
1288 fContext->unref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001289 fRootRenderTarget->unref();
reed@google.com7b201d22011-01-11 18:59:23 +00001290}
1291
1292SkDevice* SkGpuDeviceFactory::newDevice(SkCanvas*, SkBitmap::Config config,
1293 int width, int height,
1294 bool isOpaque, bool isLayer) {
1295 SkBitmap bm;
1296 bm.setConfig(config, width, height);
1297 bm.setIsOpaque(isOpaque);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001298 return new SkGpuDevice(fContext, bm, isLayer ? NULL : fRootRenderTarget);
reed@google.com7b201d22011-01-11 18:59:23 +00001299}
reed@google.comac10a2d2010-12-22 21:39:39 +00001300