blob: d102f3f6a41f3f03f7ffb6a46f3e14280bc97aa6 [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
bsalomon@google.com04de7822011-03-25 18:04:43 +0000774 // This "if" is not part of the SkDraw::drawPath() lift.
775 // When we get a 1.0 wide stroke we hairline stroke it instead of creating
776 // a new stroked-path. This is motivated by canvas2D sites that draw
777 // lines as 1.0 wide stroked paths. We can consider doing an alpha-modulated-
778 // hairline for width < 1.0 when AA is enabled.
779 static const int gMatrixMask = ~(SkMatrix::kIdentity_Mask |
780 SkMatrix::kTranslate_Mask);
781 if (!paint.getPathEffect() &&
782 SkPaint::kStroke_Style == paint.getStyle() &&
783 !(draw.fMatrix->getType() & gMatrixMask) &&
784 SK_Scalar1 == paint.getStrokeWidth()) {
785 doFill = false;
786 }
787
788 if (doFill && (paint.getPathEffect() ||
789 paint.getStyle() != SkPaint::kFill_Style)) {
reed@google.com0c219b62011-02-16 21:31:18 +0000790 doFill = paint.getFillPath(*pathPtr, &tmpPath);
791 pathPtr = &tmpPath;
792 }
793
794 // END lift from SkDraw::drawPath()
795
reed@google.com69302852011-02-16 18:08:07 +0000796 if (paint.getMaskFilter()) {
reed@google.com0c219b62011-02-16 21:31:18 +0000797 // avoid possibly allocating a new path in transform if we can
798 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
799
800 // transform the path into device space
reed@google.come3445642011-02-16 23:20:39 +0000801 pathPtr->transform(*draw.fMatrix, devPathPtr);
reed@google.com0c219b62011-02-16 21:31:18 +0000802
803 drawWithMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
reed@google.com69302852011-02-16 18:08:07 +0000804 *draw.fMatrix, *draw.fClip, draw.fBounder, &grPaint);
805 return;
806 }
reed@google.com69302852011-02-16 18:08:07 +0000807
bsalomon@google.comffca4002011-02-22 20:34:01 +0000808 GrPathFill fill = kHairLine_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000809
reed@google.com0c219b62011-02-16 21:31:18 +0000810 if (doFill) {
811 switch (pathPtr->getFillType()) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000812 case SkPath::kWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000813 fill = kWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000814 break;
815 case SkPath::kEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000816 fill = kEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000817 break;
818 case SkPath::kInverseWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000819 fill = kInverseWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000820 break;
821 case SkPath::kInverseEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000822 fill = kInverseEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000823 break;
824 default:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000825 SkDebugf("Unsupported path fill type\n");
reed@google.comac10a2d2010-12-22 21:39:39 +0000826 return;
827 }
828 }
829
reed@google.com0c219b62011-02-16 21:31:18 +0000830 SkGrPathIter iter(*pathPtr);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000831 fContext->drawPath(grPaint, &iter, fill);
reed@google.comac10a2d2010-12-22 21:39:39 +0000832}
833
reed@google.comac10a2d2010-12-22 21:39:39 +0000834void SkGpuDevice::drawBitmap(const SkDraw& draw,
835 const SkBitmap& bitmap,
836 const SkIRect* srcRectPtr,
837 const SkMatrix& m,
838 const SkPaint& paint) {
839 CHECK_SHOULD_DRAW(draw);
840
841 SkIRect srcRect;
842 if (NULL == srcRectPtr) {
843 srcRect.set(0, 0, bitmap.width(), bitmap.height());
844 } else {
845 srcRect = *srcRectPtr;
846 }
847
bsalomon@google.com5782d712011-01-21 21:03:59 +0000848 GrPaint grPaint;
849 if (!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
850 return;
851 }
852 grPaint.fSampler.setFilter(paint.isFilterBitmap());
853
reed@google.com02a7e6c2011-01-28 21:21:49 +0000854 const int maxTextureDim = fContext->getMaxTextureDimension();
855 if (bitmap.getTexture() || (bitmap.width() <= maxTextureDim &&
856 bitmap.height() <= maxTextureDim)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000857 // take the fast case
bsalomon@google.com5782d712011-01-21 21:03:59 +0000858 this->internalDrawBitmap(draw, bitmap, srcRect, m, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000859 return;
860 }
861
862 // undo the translate done by SkCanvas
863 int DX = SkMax32(0, srcRect.fLeft);
864 int DY = SkMax32(0, srcRect.fTop);
865 // compute clip bounds in local coordinates
866 SkIRect clipRect;
867 {
868 SkRect r;
869 r.set(draw.fClip->getBounds());
870 SkMatrix matrix, inverse;
871 matrix.setConcat(*draw.fMatrix, m);
872 if (!matrix.invert(&inverse)) {
873 return;
874 }
875 inverse.mapRect(&r);
876 r.roundOut(&clipRect);
877 // apply the canvas' translate to our local clip
878 clipRect.offset(DX, DY);
879 }
880
reed@google.com02a7e6c2011-01-28 21:21:49 +0000881 int nx = bitmap.width() / maxTextureDim;
882 int ny = bitmap.height() / maxTextureDim;
reed@google.comac10a2d2010-12-22 21:39:39 +0000883 for (int x = 0; x <= nx; x++) {
884 for (int y = 0; y <= ny; y++) {
885 SkIRect tileR;
reed@google.com02a7e6c2011-01-28 21:21:49 +0000886 tileR.set(x * maxTextureDim, y * maxTextureDim,
887 (x + 1) * maxTextureDim, (y + 1) * maxTextureDim);
reed@google.comac10a2d2010-12-22 21:39:39 +0000888 if (!SkIRect::Intersects(tileR, clipRect)) {
889 continue;
890 }
891
892 SkIRect srcR = tileR;
893 if (!srcR.intersect(srcRect)) {
894 continue;
895 }
896
897 SkBitmap tmpB;
898 if (bitmap.extractSubset(&tmpB, tileR)) {
899 // now offset it to make it "local" to our tmp bitmap
900 srcR.offset(-tileR.fLeft, -tileR.fTop);
901
902 SkMatrix tmpM(m);
903 {
904 int dx = tileR.fLeft - DX + SkMax32(0, srcR.fLeft);
905 int dy = tileR.fTop - DY + SkMax32(0, srcR.fTop);
906 tmpM.preTranslate(SkIntToScalar(dx), SkIntToScalar(dy));
907 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000908 this->internalDrawBitmap(draw, tmpB, srcR, tmpM, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000909 }
910 }
911 }
912}
913
914/*
915 * This is called by drawBitmap(), which has to handle images that may be too
916 * large to be represented by a single texture.
917 *
bsalomon@google.com5782d712011-01-21 21:03:59 +0000918 * internalDrawBitmap assumes that the specified bitmap will fit in a texture
919 * and that non-texture portion of the GrPaint has already been setup.
reed@google.comac10a2d2010-12-22 21:39:39 +0000920 */
921void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
922 const SkBitmap& bitmap,
923 const SkIRect& srcRect,
924 const SkMatrix& m,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000925 GrPaint* grPaint) {
reed@google.com02a7e6c2011-01-28 21:21:49 +0000926 SkASSERT(bitmap.width() <= fContext->getMaxTextureDimension() &&
927 bitmap.height() <= fContext->getMaxTextureDimension());
reed@google.comac10a2d2010-12-22 21:39:39 +0000928
929 SkAutoLockPixels alp(bitmap);
930 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
931 return;
932 }
933
bsalomon@google.com5782d712011-01-21 21:03:59 +0000934 grPaint->fSampler.setWrapX(GrSamplerState::kClamp_WrapMode);
935 grPaint->fSampler.setWrapY(GrSamplerState::kClamp_WrapMode);
936 grPaint->fSampler.setSampleMode(GrSamplerState::kNormal_SampleMode);
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000937 grPaint->fSampler.setMatrix(GrMatrix::I());
reed@google.comac10a2d2010-12-22 21:39:39 +0000938
939 GrTexture* texture;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000940 SkAutoCachedTexture act(this, bitmap, grPaint->fSampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000941 if (NULL == texture) {
942 return;
943 }
944
bsalomon@google.com5782d712011-01-21 21:03:59 +0000945 grPaint->setTexture(texture);
reed@google.com46799cd2011-02-22 20:56:26 +0000946
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000947 GrRect dstRect(0, 0, GrIntToScalar(srcRect.width()), GrIntToScalar(srcRect.height()));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000948 GrRect paintRect;
949 paintRect.setLTRB(GrFixedToScalar((srcRect.fLeft << 16) / bitmap.width()),
950 GrFixedToScalar((srcRect.fTop << 16) / bitmap.height()),
951 GrFixedToScalar((srcRect.fRight << 16) / bitmap.width()),
952 GrFixedToScalar((srcRect.fBottom << 16) / bitmap.height()));
reed@google.comac10a2d2010-12-22 21:39:39 +0000953
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000954 GrMatrix grMat;
955 SkGr::SkMatrix2GrMatrix(m, &grMat);
reed@google.comac10a2d2010-12-22 21:39:39 +0000956
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000957 fContext->drawRectToRect(*grPaint, dstRect, paintRect, &grMat);
reed@google.comac10a2d2010-12-22 21:39:39 +0000958}
959
960void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
961 int left, int top, const SkPaint& paint) {
962 CHECK_SHOULD_DRAW(draw);
963
964 SkAutoLockPixels alp(bitmap);
965 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
966 return;
967 }
968
bsalomon@google.com5782d712011-01-21 21:03:59 +0000969 GrPaint grPaint;
970 if(!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
971 return;
972 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000973
bsalomon@google.com5782d712011-01-21 21:03:59 +0000974 GrAutoMatrix avm(fContext, GrMatrix::I());
975
976 GrTexture* texture;
977 grPaint.fSampler.setClampNoFilter();
978 SkAutoCachedTexture act(this, bitmap, grPaint.fSampler, &texture);
979
bsalomon@google.com5782d712011-01-21 21:03:59 +0000980 grPaint.setTexture(texture);
981
bsalomon@google.com5782d712011-01-21 21:03:59 +0000982 fContext->drawRectToRect(grPaint,
983 GrRect(GrIntToScalar(left), GrIntToScalar(top),
984 GrIntToScalar(left + bitmap.width()),
985 GrIntToScalar(top + bitmap.height())),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000986 GrRect(0, 0, GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +0000987}
988
989void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
990 int x, int y, const SkPaint& paint) {
991 CHECK_SHOULD_DRAW(draw);
992
bsalomon@google.com5782d712011-01-21 21:03:59 +0000993 GrPaint grPaint;
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000994 if (!((SkGpuDevice*)dev)->bindDeviceAsTexture(&grPaint) ||
bsalomon@google.com5782d712011-01-21 21:03:59 +0000995 !this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
996 return;
reed@google.comac10a2d2010-12-22 21:39:39 +0000997 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000998
999 SkASSERT(NULL != grPaint.getTexture());
1000
1001 const SkBitmap& bm = dev->accessBitmap(false);
1002 int w = bm.width();
1003 int h = bm.height();
1004
1005 GrAutoMatrix avm(fContext, GrMatrix::I());
1006
1007 grPaint.fSampler.setClampNoFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +00001008
1009 fContext->drawRectToRect(grPaint,
reed@google.com1a2e8d22011-01-21 22:08:29 +00001010 GrRect(GrIntToScalar(x),
1011 GrIntToScalar(y),
1012 GrIntToScalar(x + w),
bsalomon@google.com5782d712011-01-21 21:03:59 +00001013 GrIntToScalar(y + h)),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001014 GrRect(0, 0, GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001015}
1016
1017///////////////////////////////////////////////////////////////////////////////
1018
1019// must be in SkCanvas::VertexMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +00001020static const GrPrimitiveType gVertexMode2PrimitiveType[] = {
1021 kTriangles_PrimitiveType,
1022 kTriangleStrip_PrimitiveType,
1023 kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +00001024};
1025
1026void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
1027 int vertexCount, const SkPoint vertices[],
1028 const SkPoint texs[], const SkColor colors[],
1029 SkXfermode* xmode,
1030 const uint16_t indices[], int indexCount,
1031 const SkPaint& paint) {
1032 CHECK_SHOULD_DRAW(draw);
1033
bsalomon@google.com5782d712011-01-21 21:03:59 +00001034 GrPaint grPaint;
1035 SkAutoCachedTexture act;
1036 // we ignore the shader if texs is null.
1037 if (NULL == texs) {
1038 if (!this->skPaint2GrPaintNoShader(paint, false, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001039 return;
1040 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001041 } else {
reed@google.com1a2e8d22011-01-21 22:08:29 +00001042 if (!this->skPaint2GrPaintShader(paint, &act,
1043 *draw.fMatrix,
bsalomon@google.com5782d712011-01-21 21:03:59 +00001044 &grPaint)) {
1045 return;
1046 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001047 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001048
1049 if (NULL != xmode && NULL != texs && NULL != colors) {
1050 SkXfermode::Mode mode;
1051 if (!SkXfermode::IsMode(xmode, &mode) ||
1052 SkXfermode::kMultiply_Mode != mode) {
1053 SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
1054#if 0
1055 return
1056#endif
1057 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001058 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001059
1060#if SK_SCALAR_IS_GR_SCALAR
1061 // even if GrColor and SkColor byte offsets match we need
1062 // to perform pre-multiply.
1063 if (NULL == colors) {
1064 fContext->drawVertices(grPaint,
1065 gVertexMode2PrimitiveType[vmode],
1066 vertexCount,
1067 (GrPoint*) vertices,
1068 (GrPoint*) texs,
1069 NULL,
1070 indices,
1071 indexCount);
1072 } else
1073#endif
1074 {
1075 SkTexCoordSource texSrc(texs);
1076 SkColorSource colSrc(colors);
1077 SkIndexSource idxSrc(indices, indexCount);
1078
1079 fContext->drawCustomVertices(grPaint,
1080 gVertexMode2PrimitiveType[vmode],
1081 SkPositionSource(vertices, vertexCount),
1082 (NULL == texs) ? NULL : &texSrc,
1083 (NULL == colors) ? NULL : &colSrc,
1084 (NULL == indices) ? NULL : &idxSrc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001085 }
1086}
1087
1088///////////////////////////////////////////////////////////////////////////////
1089
1090static void GlyphCacheAuxProc(void* data) {
1091 delete (GrFontScaler*)data;
1092}
1093
1094static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) {
1095 void* auxData;
1096 GrFontScaler* scaler = NULL;
1097 if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
1098 scaler = (GrFontScaler*)auxData;
1099 }
1100 if (NULL == scaler) {
1101 scaler = new SkGrFontScaler(cache);
1102 cache->setAuxProc(GlyphCacheAuxProc, scaler);
1103 }
1104 return scaler;
1105}
1106
1107static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
1108 SkFixed fx, SkFixed fy,
1109 const SkGlyph& glyph) {
1110 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1111
1112 GrSkDrawProcs* procs = (GrSkDrawProcs*)state.fDraw->fProcs;
1113
1114 if (NULL == procs->fFontScaler) {
1115 procs->fFontScaler = get_gr_font_scaler(state.fCache);
1116 }
1117 procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0),
1118 SkIntToFixed(SkFixedFloor(fx)), fy,
1119 procs->fFontScaler);
1120}
1121
bsalomon@google.com5782d712011-01-21 21:03:59 +00001122SkDrawProcs* SkGpuDevice::initDrawForText(GrTextContext* context) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001123
1124 // deferred allocation
1125 if (NULL == fDrawProcs) {
1126 fDrawProcs = new GrSkDrawProcs;
1127 fDrawProcs->fD1GProc = SkGPU_Draw1Glyph;
1128 fDrawProcs->fContext = fContext;
1129 }
1130
1131 // init our (and GL's) state
1132 fDrawProcs->fTextContext = context;
1133 fDrawProcs->fFontScaler = NULL;
1134 return fDrawProcs;
1135}
1136
1137void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
1138 size_t byteLength, SkScalar x, SkScalar y,
1139 const SkPaint& paint) {
1140 CHECK_SHOULD_DRAW(draw);
1141
1142 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1143 // this guy will just call our drawPath()
1144 draw.drawText((const char*)text, byteLength, x, y, paint);
1145 } else {
1146 SkAutoExtMatrix aem(draw.fExtMatrix);
1147 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001148
1149 GrPaint grPaint;
1150 SkAutoCachedTexture act;
1151
1152 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1153 return;
1154 }
1155 GrTextContext context(fContext, grPaint, aem.extMatrix());
1156 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001157 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
1158 }
1159}
1160
1161void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
1162 size_t byteLength, const SkScalar pos[],
1163 SkScalar constY, int scalarsPerPos,
1164 const SkPaint& paint) {
1165 CHECK_SHOULD_DRAW(draw);
1166
1167 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1168 // this guy will just call our drawPath()
1169 draw.drawPosText((const char*)text, byteLength, pos, constY,
1170 scalarsPerPos, paint);
1171 } else {
1172 SkAutoExtMatrix aem(draw.fExtMatrix);
1173 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001174
1175 GrPaint grPaint;
1176 SkAutoCachedTexture act;
1177 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1178 return;
1179 }
1180
1181 GrTextContext context(fContext, grPaint, aem.extMatrix());
1182 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001183 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
1184 scalarsPerPos, paint);
1185 }
1186}
1187
1188void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
1189 size_t len, const SkPath& path,
1190 const SkMatrix* m, const SkPaint& paint) {
1191 CHECK_SHOULD_DRAW(draw);
1192
1193 SkASSERT(draw.fDevice == this);
1194 draw.drawTextOnPath((const char*)text, len, path, m, paint);
1195}
1196
1197///////////////////////////////////////////////////////////////////////////////
1198
reed@google.comf67e4cf2011-03-15 20:56:58 +00001199bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
1200 if (!paint.isLCDRenderText()) {
1201 // we're cool with the paint as is
1202 return false;
1203 }
1204
1205 if (paint.getShader() ||
1206 paint.getXfermode() || // unless its srcover
1207 paint.getMaskFilter() ||
1208 paint.getRasterizer() ||
1209 paint.getColorFilter() ||
1210 paint.getPathEffect() ||
1211 paint.isFakeBoldText() ||
1212 paint.getStyle() != SkPaint::kFill_Style) {
1213 // turn off lcd
1214 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
1215 flags->fHinting = paint.getHinting();
1216 return true;
1217 }
1218 // we're cool with the paint as is
1219 return false;
1220}
1221
1222///////////////////////////////////////////////////////////////////////////////
1223
reed@google.comac10a2d2010-12-22 21:39:39 +00001224SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
1225 const GrSamplerState& sampler,
1226 GrTexture** texture,
1227 bool forDeviceRenderTarget) {
1228 GrContext* ctx = this->context();
1229 uint32_t p0, p1;
1230 if (forDeviceRenderTarget) {
1231 p0 = p1 = -1;
1232 } else {
1233 p0 = bitmap.getGenerationID();
1234 p1 = bitmap.pixelRefOffset();
1235 }
1236
1237 GrTexture* newTexture = NULL;
1238 GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
1239 GrTextureEntry* entry = ctx->findAndLockTexture(&key, sampler);
1240
1241 if (NULL == entry) {
1242
1243 if (forDeviceRenderTarget) {
1244 const GrGpu::TextureDesc desc = {
1245 GrGpu::kRenderTarget_TextureFlag,
1246 GrGpu::kNone_AALevel,
1247 bitmap.width(),
1248 bitmap.height(),
1249 SkGr::Bitmap2PixelConfig(bitmap)
1250 };
1251 entry = ctx->createAndLockTexture(&key, sampler, desc, NULL, 0);
1252
1253 } else {
1254 entry = sk_gr_create_bitmap_texture(ctx, &key, sampler, bitmap);
1255 }
1256 if (NULL == entry) {
1257 GrPrintf("---- failed to create texture for cache [%d %d]\n",
1258 bitmap.width(), bitmap.height());
1259 }
1260 }
1261
1262 if (NULL != entry) {
1263 newTexture = entry->texture();
reed@google.comac10a2d2010-12-22 21:39:39 +00001264 if (texture) {
1265 *texture = newTexture;
1266 }
1267 // IMPORTANT: We can't allow another SkGpuDevice to get this
1268 // cache entry until this one is destroyed!
1269 if (forDeviceRenderTarget) {
1270 ctx->detachCachedTexture(entry);
1271 }
1272 }
1273 return (TexCache*)entry;
1274}
1275
1276void SkGpuDevice::unlockCachedTexture(TexCache* cache) {
1277 this->context()->unlockTexture((GrTextureEntry*)cache);
1278}
1279
reed@google.com7b201d22011-01-11 18:59:23 +00001280///////////////////////////////////////////////////////////////////////////////
1281
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001282SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context,
1283 GrRenderTarget* rootRenderTarget)
1284 : fContext(context) {
1285
1286 GrAssert(NULL != context);
1287 GrAssert(NULL != rootRenderTarget);
1288
1289 // check this now rather than passing this value to SkGpuDevice cons.
1290 // we want the rt that is bound *now* in the 3D API, not the one
1291 // at the time of newDevice.
1292 if (SkGpuDevice::Current3DApiRenderTarget() == rootRenderTarget) {
1293 fRootRenderTarget = context->createRenderTargetFrom3DApiState();
1294 } else {
1295 fRootRenderTarget = rootRenderTarget;
1296 rootRenderTarget->ref();
1297 }
reed@google.com7b201d22011-01-11 18:59:23 +00001298 context->ref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001299
reed@google.com7b201d22011-01-11 18:59:23 +00001300}
1301
1302SkGpuDeviceFactory::~SkGpuDeviceFactory() {
1303 fContext->unref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001304 fRootRenderTarget->unref();
reed@google.com7b201d22011-01-11 18:59:23 +00001305}
1306
1307SkDevice* SkGpuDeviceFactory::newDevice(SkCanvas*, SkBitmap::Config config,
1308 int width, int height,
1309 bool isOpaque, bool isLayer) {
1310 SkBitmap bm;
1311 bm.setConfig(config, width, height);
1312 bm.setIsOpaque(isOpaque);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001313 return new SkGpuDevice(fContext, bm, isLayer ? NULL : fRootRenderTarget);
reed@google.com7b201d22011-01-11 18:59:23 +00001314}
reed@google.comac10a2d2010-12-22 21:39:39 +00001315