blob: e925e530741369c71881e6f819e5eb6a5372724d [file] [log] [blame]
reed@google.comac10a2d2010-12-22 21:39:39 +00001/*
2 Copyright 2010 Google Inc.
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17
18#include "GrContext.h"
19#include "GrTextContext.h"
20
reed@google.comac10a2d2010-12-22 21:39:39 +000021#include "SkGpuDevice.h"
reed@google.com7b201d22011-01-11 18:59:23 +000022#include "SkGpuDeviceFactory.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000023#include "SkGrTexturePixelRef.h"
24
25#include "SkDrawProcs.h"
26#include "SkGlyphCache.h"
27
28#define CACHE_LAYER_TEXTURES 1
29
30#if 0
31 extern bool (*gShouldDrawProc)();
32 #define CHECK_SHOULD_DRAW(draw) \
33 do { \
34 if (gShouldDrawProc && !gShouldDrawProc()) return; \
35 this->prepareRenderTarget(draw); \
36 } while (0)
37#else
38 #define CHECK_SHOULD_DRAW(draw) this->prepareRenderTarget(draw)
39#endif
40
41class SkAutoExtMatrix {
42public:
43 SkAutoExtMatrix(const SkMatrix* extMatrix) {
44 if (extMatrix) {
45 SkGr::SkMatrix2GrMatrix(*extMatrix, &fMatrix);
46 fExtMatrix = &fMatrix;
47 } else {
48 fExtMatrix = NULL;
49 }
50 }
51 const GrMatrix* extMatrix() const { return fExtMatrix; }
52
53private:
54 GrMatrix fMatrix;
55 GrMatrix* fExtMatrix; // NULL or &fMatrix
56};
57
58///////////////////////////////////////////////////////////////////////////////
59
60SkGpuDevice::SkAutoCachedTexture::
61 SkAutoCachedTexture(SkGpuDevice* device,
62 const SkBitmap& bitmap,
63 const GrSamplerState& sampler,
64 GrTexture** texture) {
65 GrAssert(texture);
66 fTex = NULL;
67 *texture = this->set(device, bitmap, sampler);
68}
69
70SkGpuDevice::SkAutoCachedTexture::SkAutoCachedTexture() {
71 fTex = NULL;
72}
73
74GrTexture* SkGpuDevice::SkAutoCachedTexture::set(SkGpuDevice* device,
75 const SkBitmap& bitmap,
76 const GrSamplerState& sampler) {
77 if (fTex) {
78 fDevice->unlockCachedTexture(fTex);
79 }
80 fDevice = device;
81 GrTexture* texture = (GrTexture*)bitmap.getTexture();
82 if (texture) {
83 // return the native texture
84 fTex = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +000085 } else {
86 // look it up in our cache
87 fTex = device->lockCachedTexture(bitmap, sampler, &texture, false);
88 }
89 return texture;
90}
91
92SkGpuDevice::SkAutoCachedTexture::~SkAutoCachedTexture() {
93 if (fTex) {
94 fDevice->unlockCachedTexture(fTex);
95 }
96}
97
98///////////////////////////////////////////////////////////////////////////////
99
100bool gDoTraceDraw;
101
102struct GrSkDrawProcs : public SkDrawProcs {
103public:
104 GrContext* fContext;
105 GrTextContext* fTextContext;
106 GrFontScaler* fFontScaler; // cached in the skia glyphcache
107};
108
109///////////////////////////////////////////////////////////////////////////////
110
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000111GrRenderTarget* SkGpuDevice::Current3DApiRenderTarget() {
112 return (GrRenderTarget*) -1;
113}
114
115SkGpuDevice::SkGpuDevice(GrContext* context,
116 const SkBitmap& bitmap,
117 GrRenderTarget* renderTargetOrNull)
118 : SkDevice(NULL, bitmap, (NULL == renderTargetOrNull)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000119
120 fNeedPrepareRenderTarget = false;
121 fDrawProcs = NULL;
122
reed@google.com7b201d22011-01-11 18:59:23 +0000123 fContext = context;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000124 fContext->ref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000125
126 fCache = NULL;
127 fTexture = NULL;
128 fRenderTarget = NULL;
129 fNeedClear = false;
130
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000131 if (NULL == renderTargetOrNull) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000132 SkBitmap::Config c = bitmap.config();
133 if (c != SkBitmap::kRGB_565_Config) {
134 c = SkBitmap::kARGB_8888_Config;
135 }
136 SkBitmap bm;
137 bm.setConfig(c, this->width(), this->height());
138
139#if CACHE_LAYER_TEXTURES
140
141 fCache = this->lockCachedTexture(bm, GrSamplerState::ClampNoFilter(),
142 &fTexture, true);
143 if (fCache) {
144 SkASSERT(NULL != fTexture);
145 SkASSERT(fTexture->isRenderTarget());
146 }
147#else
148 const GrGpu::TextureDesc desc = {
149 GrGpu::kRenderTarget_TextureFlag,
150 GrGpu::kNone_AALevel,
151 this->width(),
152 this->height(),
153 SkGr::Bitmap2PixelConfig(bm)
154 };
155
156 fTexture = fContext->createUncachedTexture(desc, NULL, 0);
157#endif
158 if (NULL != fTexture) {
159 fRenderTarget = fTexture->asRenderTarget();
160
161 GrAssert(NULL != fRenderTarget);
162
163 // we defer the actual clear until our gainFocus()
164 fNeedClear = true;
165
166 // wrap the bitmap with a pixelref to expose our texture
167 SkGrTexturePixelRef* pr = new SkGrTexturePixelRef(fTexture);
168 this->setPixelRef(pr, 0)->unref();
169 } else {
170 GrPrintf("--- failed to create gpu-offscreen [%d %d]\n",
171 this->width(), this->height());
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000172 GrAssert(false);
reed@google.comac10a2d2010-12-22 21:39:39 +0000173 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000174 } else if (Current3DApiRenderTarget() == renderTargetOrNull) {
175 fRenderTarget = fContext->createRenderTargetFrom3DApiState();
176 } else {
177 fRenderTarget = renderTargetOrNull;
reed@google.comac10a2d2010-12-22 21:39:39 +0000178 fRenderTarget->ref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000179 }
180}
181
182SkGpuDevice::~SkGpuDevice() {
183 if (fDrawProcs) {
184 delete fDrawProcs;
185 }
186
187 if (fCache) {
188 GrAssert(NULL != fTexture);
189 GrAssert(fRenderTarget == fTexture->asRenderTarget());
190 // IMPORTANT: reattach the rendertarget/tex back to the cache.
191 fContext->reattachAndUnlockCachedTexture((GrTextureEntry*)fCache);
192 } else if (NULL != fTexture) {
193 GrAssert(!CACHE_LAYER_TEXTURES);
194 GrAssert(fRenderTarget == fTexture->asRenderTarget());
195 fTexture->unref();
196 } else if (NULL != fRenderTarget) {
197 fRenderTarget->unref();
198 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000199 fContext->unref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000200}
201
reed@google.comac10a2d2010-12-22 21:39:39 +0000202intptr_t SkGpuDevice::getLayerTextureHandle() const {
203 if (fTexture) {
204 return fTexture->getTextureHandle();
205 } else {
206 return 0;
207 }
208}
209///////////////////////////////////////////////////////////////////////////////
210
211void SkGpuDevice::makeRenderTargetCurrent() {
212 fContext->setRenderTarget(fRenderTarget);
213 fContext->flush(true);
214 fNeedPrepareRenderTarget = true;
215}
216
217///////////////////////////////////////////////////////////////////////////////
218
219bool SkGpuDevice::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
220 SkIRect bounds;
221 bounds.set(0, 0, this->width(), this->height());
222 if (!bounds.intersect(srcRect)) {
223 return false;
224 }
225
226 const int w = bounds.width();
227 const int h = bounds.height();
228 SkBitmap tmp;
229 // note we explicitly specify our rowBytes to be snug (no gap between rows)
230 tmp.setConfig(SkBitmap::kARGB_8888_Config, w, h, w * 4);
231 if (!tmp.allocPixels()) {
232 return false;
233 }
234
235 SkAutoLockPixels alp(tmp);
236 fContext->setRenderTarget(fRenderTarget);
237 // we aren't setting the clip or matrix, so mark as dirty
238 // we don't need to set them for this call and don't have them anyway
239 fNeedPrepareRenderTarget = true;
240
241 if (!fContext->readPixels(bounds.fLeft, bounds.fTop,
242 bounds.width(), bounds.height(),
243 GrTexture::kRGBA_8888_PixelConfig,
244 tmp.getPixels())) {
245 return false;
246 }
247
248 tmp.swap(*bitmap);
249 return true;
250}
251
252void SkGpuDevice::writePixels(const SkBitmap& bitmap, int x, int y) {
253 SkAutoLockPixels alp(bitmap);
254 if (!bitmap.readyToDraw()) {
255 return;
256 }
257 GrTexture::PixelConfig config = SkGr::BitmapConfig2PixelConfig(bitmap.config(),
258 bitmap.isOpaque());
259 fContext->setRenderTarget(fRenderTarget);
260 // we aren't setting the clip or matrix, so mark as dirty
261 // we don't need to set them for this call and don't have them anyway
262 fNeedPrepareRenderTarget = true;
263
264 fContext->writePixels(x, y, bitmap.width(), bitmap.height(),
265 config, bitmap.getPixels(), bitmap.rowBytes());
266}
267
268///////////////////////////////////////////////////////////////////////////////
269
bsalomon@google.comd302f142011-03-03 13:54:13 +0000270#define USE_CLIP_STACK 0
271
reed@google.comac10a2d2010-12-22 21:39:39 +0000272static void convert_matrixclip(GrContext* context, const SkMatrix& matrix,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000273 const SkClipStack& clipStack,
274 const SkRegion& clipRegion) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000275 GrMatrix grmat;
276 SkGr::SkMatrix2GrMatrix(matrix, &grmat);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000277 context->setMatrix(grmat);
reed@google.comac10a2d2010-12-22 21:39:39 +0000278
bsalomon@google.comd302f142011-03-03 13:54:13 +0000279#if USE_CLIP_STACK
reed@google.comac10a2d2010-12-22 21:39:39 +0000280 SkGrClipIterator iter;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000281 iter.reset(clipStack);
282#else
283 SkGrRegionIterator iter;
284 iter.reset(clipRegion);
285#endif
286 const SkIRect& skBounds = clipRegion.getBounds();
287 GrRect bounds;
288 bounds.setLTRB(GrIntToScalar(skBounds.fLeft),
289 GrIntToScalar(skBounds.fTop),
290 GrIntToScalar(skBounds.fRight),
291 GrIntToScalar(skBounds.fBottom));
292 GrClip grc(&iter, NULL);
293 context->setClip(grc);
reed@google.comac10a2d2010-12-22 21:39:39 +0000294}
295
296// call this ever each draw call, to ensure that the context reflects our state,
297// and not the state from some other canvas/device
298void SkGpuDevice::prepareRenderTarget(const SkDraw& draw) {
299 if (fNeedPrepareRenderTarget ||
bsalomon@google.com5782d712011-01-21 21:03:59 +0000300 fContext->getRenderTarget() != fRenderTarget) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000301
302 fContext->setRenderTarget(fRenderTarget);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000303 SkASSERT(draw.fClipStack);
304 convert_matrixclip(fContext, *draw.fMatrix,
305 *draw.fClipStack, *draw.fClip);
reed@google.comac10a2d2010-12-22 21:39:39 +0000306 fNeedPrepareRenderTarget = false;
307 }
308}
309
reed@google.com46799cd2011-02-22 20:56:26 +0000310void SkGpuDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& clip,
311 const SkClipStack& clipStack) {
312 this->INHERITED::setMatrixClip(matrix, clip, clipStack);
reed@google.comac10a2d2010-12-22 21:39:39 +0000313
bsalomon@google.comd302f142011-03-03 13:54:13 +0000314 convert_matrixclip(fContext, matrix, clipStack, clip);
reed@google.comac10a2d2010-12-22 21:39:39 +0000315}
316
317void SkGpuDevice::gainFocus(SkCanvas* canvas, const SkMatrix& matrix,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000318 const SkRegion& clip, const SkClipStack& clipStack) {
319
reed@google.comac10a2d2010-12-22 21:39:39 +0000320 fContext->setRenderTarget(fRenderTarget);
321
bsalomon@google.comd302f142011-03-03 13:54:13 +0000322 this->INHERITED::gainFocus(canvas, matrix, clip, clipStack);
reed@google.comac10a2d2010-12-22 21:39:39 +0000323
bsalomon@google.comd302f142011-03-03 13:54:13 +0000324 convert_matrixclip(fContext, matrix, clipStack, clip);
reed@google.comac10a2d2010-12-22 21:39:39 +0000325
326 if (fNeedClear) {
327 fContext->eraseColor(0x0);
328 fNeedClear = false;
329 }
330}
331
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000332bool SkGpuDevice::bindDeviceAsTexture(GrPaint* paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000333 if (NULL != fTexture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000334 paint->setTexture(fTexture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000335 return true;
336 }
337 return false;
338}
339
340///////////////////////////////////////////////////////////////////////////////
341
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000342SK_COMPILE_ASSERT(SkShader::kNone_BitmapType == 0, shader_type_mismatch);
343SK_COMPILE_ASSERT(SkShader::kDefault_BitmapType == 1, shader_type_mismatch);
344SK_COMPILE_ASSERT(SkShader::kRadial_BitmapType == 2, shader_type_mismatch);
345SK_COMPILE_ASSERT(SkShader::kSweep_BitmapType == 3, shader_type_mismatch);
346SK_COMPILE_ASSERT(SkShader::kTwoPointRadial_BitmapType == 4,
347 shader_type_mismatch);
348SK_COMPILE_ASSERT(SkShader::kLast_BitmapType == 4, shader_type_mismatch);
reed@google.comac10a2d2010-12-22 21:39:39 +0000349
bsalomon@google.com5782d712011-01-21 21:03:59 +0000350static const GrSamplerState::SampleMode sk_bmp_type_to_sample_mode[] = {
351 (GrSamplerState::SampleMode) -1, // kNone_BitmapType
352 GrSamplerState::kNormal_SampleMode, // kDefault_BitmapType
353 GrSamplerState::kRadial_SampleMode, // kRadial_BitmapType
354 GrSamplerState::kSweep_SampleMode, // kSweep_BitmapType
355 GrSamplerState::kRadial2_SampleMode, // kTwoPointRadial_BitmapType
356};
357
358bool SkGpuDevice::skPaint2GrPaintNoShader(const SkPaint& skPaint,
359 bool justAlpha,
360 GrPaint* grPaint) {
361
362 grPaint->fDither = skPaint.isDither();
363 grPaint->fAntiAlias = skPaint.isAntiAlias();
364
365 SkXfermode::Coeff sm = SkXfermode::kOne_Coeff;
366 SkXfermode::Coeff dm = SkXfermode::kISA_Coeff;
367
368 SkXfermode* mode = skPaint.getXfermode();
369 if (mode) {
370 if (!mode->asCoeff(&sm, &dm)) {
reed@google.com1a2e8d22011-01-21 22:08:29 +0000371 SkDEBUGCODE(SkDebugf("Unsupported xfer mode.\n");)
bsalomon@google.com5782d712011-01-21 21:03:59 +0000372#if 0
373 return false;
374#endif
375 }
376 }
377 grPaint->fSrcBlendCoeff = sk_blend_to_grblend(sm);
378 grPaint->fDstBlendCoeff = sk_blend_to_grblend(dm);
379
380 if (justAlpha) {
381 uint8_t alpha = skPaint.getAlpha();
382 grPaint->fColor = GrColorPackRGBA(alpha, alpha, alpha, alpha);
383 } else {
384 grPaint->fColor = SkGr::SkColor2GrColor(skPaint.getColor());
385 grPaint->setTexture(NULL);
386 }
387 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000388}
389
bsalomon@google.com5782d712011-01-21 21:03:59 +0000390bool SkGpuDevice::skPaint2GrPaintShader(const SkPaint& skPaint,
391 SkAutoCachedTexture* act,
392 const SkMatrix& ctm,
393 GrPaint* grPaint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000394
bsalomon@google.com5782d712011-01-21 21:03:59 +0000395 SkASSERT(NULL != act);
reed@google.comac10a2d2010-12-22 21:39:39 +0000396
bsalomon@google.com5782d712011-01-21 21:03:59 +0000397 SkShader* shader = skPaint.getShader();
reed@google.comac10a2d2010-12-22 21:39:39 +0000398 if (NULL == shader) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000399 return this->skPaint2GrPaintNoShader(skPaint, false, grPaint);
400 grPaint->setTexture(NULL);
401 return true;
402 } else if (!this->skPaint2GrPaintNoShader(skPaint, true, grPaint)) {
403 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000404 }
405
bsalomon@google.com5782d712011-01-21 21:03:59 +0000406 SkPaint noAlphaPaint(skPaint);
407 noAlphaPaint.setAlpha(255);
408 shader->setContext(this->accessBitmap(false), noAlphaPaint, ctm);
reed@google.comac10a2d2010-12-22 21:39:39 +0000409
reed@google.comac10a2d2010-12-22 21:39:39 +0000410 SkBitmap bitmap;
411 SkMatrix matrix;
412 SkShader::TileMode tileModes[2];
413 SkScalar twoPointParams[3];
414 SkShader::BitmapType bmptype = shader->asABitmap(&bitmap, &matrix,
415 tileModes, twoPointParams);
416
bsalomon@google.com5782d712011-01-21 21:03:59 +0000417 GrSamplerState::SampleMode sampleMode = sk_bmp_type_to_sample_mode[bmptype];
418 if (-1 == sampleMode) {
419 SkDebugf("shader->asABitmap() == kNone_BitmapType\n");
420 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000421 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000422 grPaint->fSampler.setSampleMode(sampleMode);
bsalomon@google.com0748f212011-02-01 22:56:16 +0000423 grPaint->fSampler.setFilter(skPaint.isFilterBitmap());
bsalomon@google.com5782d712011-01-21 21:03:59 +0000424 grPaint->fSampler.setWrapX(sk_tile_mode_to_grwrap(tileModes[0]));
425 grPaint->fSampler.setWrapY(sk_tile_mode_to_grwrap(tileModes[1]));
reed@google.comac10a2d2010-12-22 21:39:39 +0000426 if (GrSamplerState::kRadial2_SampleMode == sampleMode) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000427 grPaint->fSampler.setRadial2Params(twoPointParams[0],
428 twoPointParams[1],
429 twoPointParams[2] < 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000430 }
431
bsalomon@google.com5782d712011-01-21 21:03:59 +0000432 GrTexture* texture = act->set(this, bitmap, grPaint->fSampler);
reed@google.comac10a2d2010-12-22 21:39:39 +0000433 if (NULL == texture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000434 SkDebugf("Couldn't convert bitmap to texture.\n");
435 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000436 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000437 grPaint->setTexture(texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000438
439 // since our texture coords will be in local space, we wack the texture
440 // matrix to map them back into 0...1 before we load it
441 SkMatrix localM;
442 if (shader->getLocalMatrix(&localM)) {
443 SkMatrix inverse;
444 if (localM.invert(&inverse)) {
445 matrix.preConcat(inverse);
446 }
447 }
448 if (SkShader::kDefault_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000449 GrScalar sx = GrFixedToScalar(GR_Fixed1 / bitmap.width());
450 GrScalar sy = GrFixedToScalar(GR_Fixed1 / bitmap.height());
reed@google.comac10a2d2010-12-22 21:39:39 +0000451 matrix.postScale(sx, sy);
reed@google.comac10a2d2010-12-22 21:39:39 +0000452 } else if (SkShader::kRadial_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000453 GrScalar s = GrFixedToScalar(GR_Fixed1 / bitmap.width());
reed@google.comac10a2d2010-12-22 21:39:39 +0000454 matrix.postScale(s, s);
455 }
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000456 GrMatrix grMat;
457 SkGr::SkMatrix2GrMatrix(matrix, &grMat);
458 grPaint->fSampler.setMatrix(grMat);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000459
460 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000461}
462
463///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com5782d712011-01-21 21:03:59 +0000464
465class SkPositionSource {
466public:
467 SkPositionSource(const SkPoint* points, int count)
468 : fPoints(points), fCount(count) {}
469
470 int count() const { return fCount; }
471
472 void writeValue(int i, GrPoint* dstPosition) const {
473 SkASSERT(i < fCount);
474 dstPosition->fX = SkScalarToGrScalar(fPoints[i].fX);
475 dstPosition->fY = SkScalarToGrScalar(fPoints[i].fY);
476 }
477private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000478 const SkPoint* fPoints;
bsalomon@google.com19628322011-02-03 21:30:17 +0000479 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000480};
481
482class SkTexCoordSource {
483public:
484 SkTexCoordSource(const SkPoint* coords)
485 : fCoords(coords) {}
486
487 void writeValue(int i, GrPoint* dstCoord) const {
488 dstCoord->fX = SkScalarToGrScalar(fCoords[i].fX);
489 dstCoord->fY = SkScalarToGrScalar(fCoords[i].fY);
490 }
491private:
492 const SkPoint* fCoords;
493};
494
495class SkColorSource {
496public:
497 SkColorSource(const SkColor* colors) : fColors(colors) {}
498
499 void writeValue(int i, GrColor* dstColor) const {
500 *dstColor = SkGr::SkColor2GrColor(fColors[i]);
501 }
502private:
503 const SkColor* fColors;
504};
505
506class SkIndexSource {
507public:
508 SkIndexSource(const uint16_t* indices, int count)
509 : fIndices(indices), fCount(count) {
510 }
511
512 int count() const { return fCount; }
513
514 void writeValue(int i, uint16_t* dstIndex) const {
515 *dstIndex = fIndices[i];
516 }
517
518private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000519 const uint16_t* fIndices;
bsalomon@google.com19628322011-02-03 21:30:17 +0000520 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000521};
522
523///////////////////////////////////////////////////////////////////////////////
524
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000525#if 0 // not currently being used so don't compile,
526
bsalomon@google.com5782d712011-01-21 21:03:59 +0000527// can be used for positions or texture coordinates
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000528
bsalomon@google.com5782d712011-01-21 21:03:59 +0000529class SkRectFanSource {
530public:
531 SkRectFanSource(const SkRect& rect) : fRect(rect) {}
532
533 int count() const { return 4; }
534
535 void writeValue(int i, GrPoint* dstPoint) const {
536 SkASSERT(i < 4);
537 dstPoint->fX = SkScalarToGrScalar((i % 3) ? fRect.fRight :
538 fRect.fLeft);
539 dstPoint->fY = SkScalarToGrScalar((i < 2) ? fRect.fTop :
540 fRect.fBottom);
541 }
542private:
543 const SkRect& fRect;
544};
545
546class SkIRectFanSource {
547public:
548 SkIRectFanSource(const SkIRect& rect) : fRect(rect) {}
549
550 int count() const { return 4; }
551
552 void writeValue(int i, GrPoint* dstPoint) const {
553 SkASSERT(i < 4);
554 dstPoint->fX = (i % 3) ? GrIntToScalar(fRect.fRight) :
555 GrIntToScalar(fRect.fLeft);
556 dstPoint->fY = (i < 2) ? GrIntToScalar(fRect.fTop) :
557 GrIntToScalar(fRect.fBottom);
558 }
559private:
560 const SkIRect& fRect;
561};
562
563class SkMatRectFanSource {
564public:
565 SkMatRectFanSource(const SkRect& rect, const SkMatrix& matrix)
566 : fRect(rect), fMatrix(matrix) {}
567
568 int count() const { return 4; }
569
570 void writeValue(int i, GrPoint* dstPoint) const {
571 SkASSERT(i < 4);
572
573#if SK_SCALAR_IS_GR_SCALAR
574 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
575 (i < 2) ? fRect.fTop : fRect.fBottom,
576 (SkPoint*)dstPoint);
577#else
578 SkPoint dst;
579 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
580 (i < 2) ? fRect.fTop : fRect.fBottom,
581 &dst);
582 dstPoint->fX = SkScalarToGrScalar(dst.fX);
583 dstPoint->fY = SkScalarToGrScalar(dst.fY);
584#endif
585 }
586private:
587 const SkRect& fRect;
588 const SkMatrix& fMatrix;
589};
590
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000591#endif
592
reed@google.comac10a2d2010-12-22 21:39:39 +0000593///////////////////////////////////////////////////////////////////////////////
594
595void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
596 CHECK_SHOULD_DRAW(draw);
597
bsalomon@google.com5782d712011-01-21 21:03:59 +0000598 GrPaint grPaint;
599 SkAutoCachedTexture act;
600 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000601 return;
602 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000603
604 fContext->drawPaint(grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000605}
606
607// must be in SkCanvas::PointMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +0000608static const GrPrimitiveType gPointMode2PrimtiveType[] = {
609 kPoints_PrimitiveType,
610 kLines_PrimitiveType,
611 kLineStrip_PrimitiveType
reed@google.comac10a2d2010-12-22 21:39:39 +0000612};
613
614void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000615 size_t count, const SkPoint pts[], const SkPaint& paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000616 CHECK_SHOULD_DRAW(draw);
617
618 SkScalar width = paint.getStrokeWidth();
619 if (width < 0) {
620 return;
621 }
622
623 // we only handle hairlines here, else we let the SkDraw call our drawPath()
624 if (width > 0) {
625 draw.drawPoints(mode, count, pts, paint, true);
626 return;
627 }
628
bsalomon@google.com5782d712011-01-21 21:03:59 +0000629 GrPaint grPaint;
630 SkAutoCachedTexture act;
631 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000632 return;
633 }
634
reed@google.comac10a2d2010-12-22 21:39:39 +0000635#if SK_SCALAR_IS_GR_SCALAR
bsalomon@google.com5782d712011-01-21 21:03:59 +0000636 fContext->drawVertices(grPaint,
637 gPointMode2PrimtiveType[mode],
638 count,
639 (GrPoint*)pts,
640 NULL,
641 NULL,
642 NULL,
643 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000644#else
bsalomon@google.com5782d712011-01-21 21:03:59 +0000645 fContext->drawCustomVertices(grPaint,
646 gPointMode2PrimtiveType[mode],
647 SkPositionSource(pts, count));
reed@google.comac10a2d2010-12-22 21:39:39 +0000648#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000649}
650
651void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
652 const SkPaint& paint) {
653 CHECK_SHOULD_DRAW(draw);
654
655 bool doStroke = paint.getStyle() == SkPaint::kStroke_Style;
656 SkScalar width = paint.getStrokeWidth();
657
658 /*
659 We have special code for hairline strokes, miter-strokes, and fills.
reed@google.com69302852011-02-16 18:08:07 +0000660 Anything else we just call our path code.
reed@google.comac10a2d2010-12-22 21:39:39 +0000661 */
reed@google.com69302852011-02-16 18:08:07 +0000662 bool usePath = doStroke && width > 0 &&
663 paint.getStrokeJoin() != SkPaint::kMiter_Join;
664 // another reason we might need to call drawPath...
665 if (paint.getMaskFilter()) {
666 usePath = true;
667 }
668
669 if (usePath) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000670 SkPath path;
671 path.addRect(rect);
672 this->drawPath(draw, path, paint, NULL, true);
673 return;
674 }
675
bsalomon@google.com5782d712011-01-21 21:03:59 +0000676 GrPaint grPaint;
677 SkAutoCachedTexture act;
678 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000679 return;
680 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000681 fContext->drawRect(grPaint, Sk2Gr(rect), doStroke ? width : -1);
reed@google.comac10a2d2010-12-22 21:39:39 +0000682}
683
reed@google.com69302852011-02-16 18:08:07 +0000684#include "SkMaskFilter.h"
685#include "SkBounder.h"
686
reed@google.com69302852011-02-16 18:08:07 +0000687static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
688 SkMaskFilter* filter, const SkMatrix& matrix,
689 const SkRegion& clip, SkBounder* bounder,
690 GrPaint* grp) {
691 SkMask srcM, dstM;
692
693 if (!SkDraw::DrawToMask(path, &clip.getBounds(), filter, &matrix, &srcM,
694 SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
695 return false;
696 }
697
698 SkAutoMaskImage autoSrc(&srcM, false);
699
700 if (!filter->filterMask(&dstM, srcM, matrix, NULL)) {
701 return false;
702 }
703 // this will free-up dstM when we're done (allocated in filterMask())
704 SkAutoMaskImage autoDst(&dstM, false);
705
706 if (clip.quickReject(dstM.fBounds)) {
707 return false;
708 }
709 if (bounder && !bounder->doIRect(dstM.fBounds)) {
710 return false;
711 }
712
713 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
714 // the current clip (and identity matrix) and grpaint settings
715
reed@google.com0c219b62011-02-16 21:31:18 +0000716 GrAutoMatrix avm(context, GrMatrix::I());
reed@google.com69302852011-02-16 18:08:07 +0000717
718 const GrGpu::TextureDesc desc = {
719 0,
720 GrGpu::kNone_AALevel,
721 dstM.fBounds.width(),
722 dstM.fBounds.height(),
723 GrTexture::kAlpha_8_PixelConfig
724 };
725
726 GrTexture* texture = context->createUncachedTexture(desc, dstM.fImage,
727 dstM.fRowBytes);
728 if (NULL == texture) {
729 return false;
730 }
731
reed@google.com0c219b62011-02-16 21:31:18 +0000732 grp->setTexture(texture);
733 texture->unref();
734 grp->fSampler.setClampNoFilter();
reed@google.com69302852011-02-16 18:08:07 +0000735
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000736 GrRect d;
737 d.setLTRB(GrIntToScalar(dstM.fBounds.fLeft),
reed@google.com0c219b62011-02-16 21:31:18 +0000738 GrIntToScalar(dstM.fBounds.fTop),
739 GrIntToScalar(dstM.fBounds.fRight),
740 GrIntToScalar(dstM.fBounds.fBottom));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000741 GrRect s;
742 s.setLTRB(0, 0, GR_Scalar1, GR_Scalar1);
743 context->drawRectToRect(*grp, d, s);
reed@google.com69302852011-02-16 18:08:07 +0000744 return true;
745}
reed@google.com69302852011-02-16 18:08:07 +0000746
reed@google.com0c219b62011-02-16 21:31:18 +0000747void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
reed@google.comac10a2d2010-12-22 21:39:39 +0000748 const SkPaint& paint, const SkMatrix* prePathMatrix,
749 bool pathIsMutable) {
750 CHECK_SHOULD_DRAW(draw);
751
bsalomon@google.com5782d712011-01-21 21:03:59 +0000752 GrPaint grPaint;
753 SkAutoCachedTexture act;
754 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000755 return;
756 }
757
reed@google.com0c219b62011-02-16 21:31:18 +0000758 // BEGIN lift from SkDraw::drawPath()
759
760 SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
761 bool doFill = true;
762 SkPath tmpPath;
reed@google.comac10a2d2010-12-22 21:39:39 +0000763
764 if (prePathMatrix) {
reed@google.come3445642011-02-16 23:20:39 +0000765 SkPath* result = pathPtr;
reed@google.com0c219b62011-02-16 21:31:18 +0000766
reed@google.come3445642011-02-16 23:20:39 +0000767 if (!pathIsMutable) {
768 result = &tmpPath;
769 pathIsMutable = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000770 }
reed@google.come3445642011-02-16 23:20:39 +0000771 // should I push prePathMatrix on our MV stack temporarily, instead
772 // of applying it here? See SkDraw.cpp
773 pathPtr->transform(*prePathMatrix, result);
774 pathPtr = result;
reed@google.comac10a2d2010-12-22 21:39:39 +0000775 }
reed@google.com0c219b62011-02-16 21:31:18 +0000776 // at this point we're done with prePathMatrix
777 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
reed@google.comac10a2d2010-12-22 21:39:39 +0000778
reed@google.com0c219b62011-02-16 21:31:18 +0000779 if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) {
780 doFill = paint.getFillPath(*pathPtr, &tmpPath);
781 pathPtr = &tmpPath;
782 }
783
784 // END lift from SkDraw::drawPath()
785
reed@google.com69302852011-02-16 18:08:07 +0000786 if (paint.getMaskFilter()) {
reed@google.com0c219b62011-02-16 21:31:18 +0000787 // avoid possibly allocating a new path in transform if we can
788 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
789
790 // transform the path into device space
reed@google.come3445642011-02-16 23:20:39 +0000791 pathPtr->transform(*draw.fMatrix, devPathPtr);
reed@google.com0c219b62011-02-16 21:31:18 +0000792
793 drawWithMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
reed@google.com69302852011-02-16 18:08:07 +0000794 *draw.fMatrix, *draw.fClip, draw.fBounder, &grPaint);
795 return;
796 }
reed@google.com69302852011-02-16 18:08:07 +0000797
bsalomon@google.comffca4002011-02-22 20:34:01 +0000798 GrPathFill fill = kHairLine_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000799
reed@google.com0c219b62011-02-16 21:31:18 +0000800 if (doFill) {
801 switch (pathPtr->getFillType()) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000802 case SkPath::kWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000803 fill = kWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000804 break;
805 case SkPath::kEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000806 fill = kEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000807 break;
808 case SkPath::kInverseWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000809 fill = kInverseWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000810 break;
811 case SkPath::kInverseEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000812 fill = kInverseEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000813 break;
814 default:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000815 SkDebugf("Unsupported path fill type\n");
reed@google.comac10a2d2010-12-22 21:39:39 +0000816 return;
817 }
818 }
819
reed@google.com0c219b62011-02-16 21:31:18 +0000820 SkGrPathIter iter(*pathPtr);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000821 fContext->drawPath(grPaint, &iter, fill);
reed@google.comac10a2d2010-12-22 21:39:39 +0000822}
823
reed@google.comac10a2d2010-12-22 21:39:39 +0000824void SkGpuDevice::drawBitmap(const SkDraw& draw,
825 const SkBitmap& bitmap,
826 const SkIRect* srcRectPtr,
827 const SkMatrix& m,
828 const SkPaint& paint) {
829 CHECK_SHOULD_DRAW(draw);
830
831 SkIRect srcRect;
832 if (NULL == srcRectPtr) {
833 srcRect.set(0, 0, bitmap.width(), bitmap.height());
834 } else {
835 srcRect = *srcRectPtr;
836 }
837
bsalomon@google.com5782d712011-01-21 21:03:59 +0000838 GrPaint grPaint;
839 if (!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
840 return;
841 }
842 grPaint.fSampler.setFilter(paint.isFilterBitmap());
843
reed@google.com02a7e6c2011-01-28 21:21:49 +0000844 const int maxTextureDim = fContext->getMaxTextureDimension();
845 if (bitmap.getTexture() || (bitmap.width() <= maxTextureDim &&
846 bitmap.height() <= maxTextureDim)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000847 // take the fast case
bsalomon@google.com5782d712011-01-21 21:03:59 +0000848 this->internalDrawBitmap(draw, bitmap, srcRect, m, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000849 return;
850 }
851
852 // undo the translate done by SkCanvas
853 int DX = SkMax32(0, srcRect.fLeft);
854 int DY = SkMax32(0, srcRect.fTop);
855 // compute clip bounds in local coordinates
856 SkIRect clipRect;
857 {
858 SkRect r;
859 r.set(draw.fClip->getBounds());
860 SkMatrix matrix, inverse;
861 matrix.setConcat(*draw.fMatrix, m);
862 if (!matrix.invert(&inverse)) {
863 return;
864 }
865 inverse.mapRect(&r);
866 r.roundOut(&clipRect);
867 // apply the canvas' translate to our local clip
868 clipRect.offset(DX, DY);
869 }
870
reed@google.com02a7e6c2011-01-28 21:21:49 +0000871 int nx = bitmap.width() / maxTextureDim;
872 int ny = bitmap.height() / maxTextureDim;
reed@google.comac10a2d2010-12-22 21:39:39 +0000873 for (int x = 0; x <= nx; x++) {
874 for (int y = 0; y <= ny; y++) {
875 SkIRect tileR;
reed@google.com02a7e6c2011-01-28 21:21:49 +0000876 tileR.set(x * maxTextureDim, y * maxTextureDim,
877 (x + 1) * maxTextureDim, (y + 1) * maxTextureDim);
reed@google.comac10a2d2010-12-22 21:39:39 +0000878 if (!SkIRect::Intersects(tileR, clipRect)) {
879 continue;
880 }
881
882 SkIRect srcR = tileR;
883 if (!srcR.intersect(srcRect)) {
884 continue;
885 }
886
887 SkBitmap tmpB;
888 if (bitmap.extractSubset(&tmpB, tileR)) {
889 // now offset it to make it "local" to our tmp bitmap
890 srcR.offset(-tileR.fLeft, -tileR.fTop);
891
892 SkMatrix tmpM(m);
893 {
894 int dx = tileR.fLeft - DX + SkMax32(0, srcR.fLeft);
895 int dy = tileR.fTop - DY + SkMax32(0, srcR.fTop);
896 tmpM.preTranslate(SkIntToScalar(dx), SkIntToScalar(dy));
897 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000898 this->internalDrawBitmap(draw, tmpB, srcR, tmpM, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000899 }
900 }
901 }
902}
903
904/*
905 * This is called by drawBitmap(), which has to handle images that may be too
906 * large to be represented by a single texture.
907 *
bsalomon@google.com5782d712011-01-21 21:03:59 +0000908 * internalDrawBitmap assumes that the specified bitmap will fit in a texture
909 * and that non-texture portion of the GrPaint has already been setup.
reed@google.comac10a2d2010-12-22 21:39:39 +0000910 */
911void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
912 const SkBitmap& bitmap,
913 const SkIRect& srcRect,
914 const SkMatrix& m,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000915 GrPaint* grPaint) {
reed@google.com02a7e6c2011-01-28 21:21:49 +0000916 SkASSERT(bitmap.width() <= fContext->getMaxTextureDimension() &&
917 bitmap.height() <= fContext->getMaxTextureDimension());
reed@google.comac10a2d2010-12-22 21:39:39 +0000918
919 SkAutoLockPixels alp(bitmap);
920 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
921 return;
922 }
923
bsalomon@google.com5782d712011-01-21 21:03:59 +0000924 grPaint->fSampler.setWrapX(GrSamplerState::kClamp_WrapMode);
925 grPaint->fSampler.setWrapY(GrSamplerState::kClamp_WrapMode);
926 grPaint->fSampler.setSampleMode(GrSamplerState::kNormal_SampleMode);
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000927 grPaint->fSampler.setMatrix(GrMatrix::I());
reed@google.comac10a2d2010-12-22 21:39:39 +0000928
929 GrTexture* texture;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000930 SkAutoCachedTexture act(this, bitmap, grPaint->fSampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000931 if (NULL == texture) {
932 return;
933 }
934
bsalomon@google.com5782d712011-01-21 21:03:59 +0000935 grPaint->setTexture(texture);
reed@google.com46799cd2011-02-22 20:56:26 +0000936
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000937 GrRect dstRect(0, 0, GrIntToScalar(srcRect.width()), GrIntToScalar(srcRect.height()));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000938 GrRect paintRect;
939 paintRect.setLTRB(GrFixedToScalar((srcRect.fLeft << 16) / bitmap.width()),
940 GrFixedToScalar((srcRect.fTop << 16) / bitmap.height()),
941 GrFixedToScalar((srcRect.fRight << 16) / bitmap.width()),
942 GrFixedToScalar((srcRect.fBottom << 16) / bitmap.height()));
reed@google.comac10a2d2010-12-22 21:39:39 +0000943
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000944 GrMatrix grMat;
945 SkGr::SkMatrix2GrMatrix(m, &grMat);
reed@google.comac10a2d2010-12-22 21:39:39 +0000946
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000947 fContext->drawRectToRect(*grPaint, dstRect, paintRect, &grMat);
reed@google.comac10a2d2010-12-22 21:39:39 +0000948}
949
950void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
951 int left, int top, const SkPaint& paint) {
952 CHECK_SHOULD_DRAW(draw);
953
954 SkAutoLockPixels alp(bitmap);
955 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
956 return;
957 }
958
bsalomon@google.com5782d712011-01-21 21:03:59 +0000959 GrPaint grPaint;
960 if(!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
961 return;
962 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000963
bsalomon@google.com5782d712011-01-21 21:03:59 +0000964 GrAutoMatrix avm(fContext, GrMatrix::I());
965
966 GrTexture* texture;
967 grPaint.fSampler.setClampNoFilter();
968 SkAutoCachedTexture act(this, bitmap, grPaint.fSampler, &texture);
969
bsalomon@google.com5782d712011-01-21 21:03:59 +0000970 grPaint.setTexture(texture);
971
bsalomon@google.com5782d712011-01-21 21:03:59 +0000972 fContext->drawRectToRect(grPaint,
973 GrRect(GrIntToScalar(left), GrIntToScalar(top),
974 GrIntToScalar(left + bitmap.width()),
975 GrIntToScalar(top + bitmap.height())),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000976 GrRect(0, 0, GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +0000977}
978
979void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
980 int x, int y, const SkPaint& paint) {
981 CHECK_SHOULD_DRAW(draw);
982
bsalomon@google.com5782d712011-01-21 21:03:59 +0000983 GrPaint grPaint;
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000984 if (!((SkGpuDevice*)dev)->bindDeviceAsTexture(&grPaint) ||
bsalomon@google.com5782d712011-01-21 21:03:59 +0000985 !this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
986 return;
reed@google.comac10a2d2010-12-22 21:39:39 +0000987 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000988
989 SkASSERT(NULL != grPaint.getTexture());
990
991 const SkBitmap& bm = dev->accessBitmap(false);
992 int w = bm.width();
993 int h = bm.height();
994
995 GrAutoMatrix avm(fContext, GrMatrix::I());
996
997 grPaint.fSampler.setClampNoFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +0000998
999 fContext->drawRectToRect(grPaint,
reed@google.com1a2e8d22011-01-21 22:08:29 +00001000 GrRect(GrIntToScalar(x),
1001 GrIntToScalar(y),
1002 GrIntToScalar(x + w),
bsalomon@google.com5782d712011-01-21 21:03:59 +00001003 GrIntToScalar(y + h)),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001004 GrRect(0, 0, GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001005}
1006
1007///////////////////////////////////////////////////////////////////////////////
1008
1009// must be in SkCanvas::VertexMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +00001010static const GrPrimitiveType gVertexMode2PrimitiveType[] = {
1011 kTriangles_PrimitiveType,
1012 kTriangleStrip_PrimitiveType,
1013 kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +00001014};
1015
1016void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
1017 int vertexCount, const SkPoint vertices[],
1018 const SkPoint texs[], const SkColor colors[],
1019 SkXfermode* xmode,
1020 const uint16_t indices[], int indexCount,
1021 const SkPaint& paint) {
1022 CHECK_SHOULD_DRAW(draw);
1023
bsalomon@google.com5782d712011-01-21 21:03:59 +00001024 GrPaint grPaint;
1025 SkAutoCachedTexture act;
1026 // we ignore the shader if texs is null.
1027 if (NULL == texs) {
1028 if (!this->skPaint2GrPaintNoShader(paint, false, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001029 return;
1030 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001031 } else {
reed@google.com1a2e8d22011-01-21 22:08:29 +00001032 if (!this->skPaint2GrPaintShader(paint, &act,
1033 *draw.fMatrix,
bsalomon@google.com5782d712011-01-21 21:03:59 +00001034 &grPaint)) {
1035 return;
1036 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001037 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001038
1039 if (NULL != xmode && NULL != texs && NULL != colors) {
1040 SkXfermode::Mode mode;
1041 if (!SkXfermode::IsMode(xmode, &mode) ||
1042 SkXfermode::kMultiply_Mode != mode) {
1043 SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
1044#if 0
1045 return
1046#endif
1047 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001048 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001049
1050#if SK_SCALAR_IS_GR_SCALAR
1051 // even if GrColor and SkColor byte offsets match we need
1052 // to perform pre-multiply.
1053 if (NULL == colors) {
1054 fContext->drawVertices(grPaint,
1055 gVertexMode2PrimitiveType[vmode],
1056 vertexCount,
1057 (GrPoint*) vertices,
1058 (GrPoint*) texs,
1059 NULL,
1060 indices,
1061 indexCount);
1062 } else
1063#endif
1064 {
1065 SkTexCoordSource texSrc(texs);
1066 SkColorSource colSrc(colors);
1067 SkIndexSource idxSrc(indices, indexCount);
1068
1069 fContext->drawCustomVertices(grPaint,
1070 gVertexMode2PrimitiveType[vmode],
1071 SkPositionSource(vertices, vertexCount),
1072 (NULL == texs) ? NULL : &texSrc,
1073 (NULL == colors) ? NULL : &colSrc,
1074 (NULL == indices) ? NULL : &idxSrc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001075 }
1076}
1077
1078///////////////////////////////////////////////////////////////////////////////
1079
1080static void GlyphCacheAuxProc(void* data) {
1081 delete (GrFontScaler*)data;
1082}
1083
1084static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) {
1085 void* auxData;
1086 GrFontScaler* scaler = NULL;
1087 if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
1088 scaler = (GrFontScaler*)auxData;
1089 }
1090 if (NULL == scaler) {
1091 scaler = new SkGrFontScaler(cache);
1092 cache->setAuxProc(GlyphCacheAuxProc, scaler);
1093 }
1094 return scaler;
1095}
1096
1097static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
1098 SkFixed fx, SkFixed fy,
1099 const SkGlyph& glyph) {
1100 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1101
1102 GrSkDrawProcs* procs = (GrSkDrawProcs*)state.fDraw->fProcs;
1103
1104 if (NULL == procs->fFontScaler) {
1105 procs->fFontScaler = get_gr_font_scaler(state.fCache);
1106 }
1107 procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0),
1108 SkIntToFixed(SkFixedFloor(fx)), fy,
1109 procs->fFontScaler);
1110}
1111
bsalomon@google.com5782d712011-01-21 21:03:59 +00001112SkDrawProcs* SkGpuDevice::initDrawForText(GrTextContext* context) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001113
1114 // deferred allocation
1115 if (NULL == fDrawProcs) {
1116 fDrawProcs = new GrSkDrawProcs;
1117 fDrawProcs->fD1GProc = SkGPU_Draw1Glyph;
1118 fDrawProcs->fContext = fContext;
1119 }
1120
1121 // init our (and GL's) state
1122 fDrawProcs->fTextContext = context;
1123 fDrawProcs->fFontScaler = NULL;
1124 return fDrawProcs;
1125}
1126
1127void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
1128 size_t byteLength, SkScalar x, SkScalar y,
1129 const SkPaint& paint) {
1130 CHECK_SHOULD_DRAW(draw);
1131
1132 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1133 // this guy will just call our drawPath()
1134 draw.drawText((const char*)text, byteLength, x, y, paint);
1135 } else {
1136 SkAutoExtMatrix aem(draw.fExtMatrix);
1137 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001138
1139 GrPaint grPaint;
1140 SkAutoCachedTexture act;
1141
1142 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1143 return;
1144 }
1145 GrTextContext context(fContext, grPaint, aem.extMatrix());
1146 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001147 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
1148 }
1149}
1150
1151void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
1152 size_t byteLength, const SkScalar pos[],
1153 SkScalar constY, int scalarsPerPos,
1154 const SkPaint& paint) {
1155 CHECK_SHOULD_DRAW(draw);
1156
1157 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1158 // this guy will just call our drawPath()
1159 draw.drawPosText((const char*)text, byteLength, pos, constY,
1160 scalarsPerPos, paint);
1161 } else {
1162 SkAutoExtMatrix aem(draw.fExtMatrix);
1163 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001164
1165 GrPaint grPaint;
1166 SkAutoCachedTexture act;
1167 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1168 return;
1169 }
1170
1171 GrTextContext context(fContext, grPaint, aem.extMatrix());
1172 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001173 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
1174 scalarsPerPos, paint);
1175 }
1176}
1177
1178void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
1179 size_t len, const SkPath& path,
1180 const SkMatrix* m, const SkPaint& paint) {
1181 CHECK_SHOULD_DRAW(draw);
1182
1183 SkASSERT(draw.fDevice == this);
1184 draw.drawTextOnPath((const char*)text, len, path, m, paint);
1185}
1186
1187///////////////////////////////////////////////////////////////////////////////
1188
1189SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
1190 const GrSamplerState& sampler,
1191 GrTexture** texture,
1192 bool forDeviceRenderTarget) {
1193 GrContext* ctx = this->context();
1194 uint32_t p0, p1;
1195 if (forDeviceRenderTarget) {
1196 p0 = p1 = -1;
1197 } else {
1198 p0 = bitmap.getGenerationID();
1199 p1 = bitmap.pixelRefOffset();
1200 }
1201
1202 GrTexture* newTexture = NULL;
1203 GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
1204 GrTextureEntry* entry = ctx->findAndLockTexture(&key, sampler);
1205
1206 if (NULL == entry) {
1207
1208 if (forDeviceRenderTarget) {
1209 const GrGpu::TextureDesc desc = {
1210 GrGpu::kRenderTarget_TextureFlag,
1211 GrGpu::kNone_AALevel,
1212 bitmap.width(),
1213 bitmap.height(),
1214 SkGr::Bitmap2PixelConfig(bitmap)
1215 };
1216 entry = ctx->createAndLockTexture(&key, sampler, desc, NULL, 0);
1217
1218 } else {
1219 entry = sk_gr_create_bitmap_texture(ctx, &key, sampler, bitmap);
1220 }
1221 if (NULL == entry) {
1222 GrPrintf("---- failed to create texture for cache [%d %d]\n",
1223 bitmap.width(), bitmap.height());
1224 }
1225 }
1226
1227 if (NULL != entry) {
1228 newTexture = entry->texture();
reed@google.comac10a2d2010-12-22 21:39:39 +00001229 if (texture) {
1230 *texture = newTexture;
1231 }
1232 // IMPORTANT: We can't allow another SkGpuDevice to get this
1233 // cache entry until this one is destroyed!
1234 if (forDeviceRenderTarget) {
1235 ctx->detachCachedTexture(entry);
1236 }
1237 }
1238 return (TexCache*)entry;
1239}
1240
1241void SkGpuDevice::unlockCachedTexture(TexCache* cache) {
1242 this->context()->unlockTexture((GrTextureEntry*)cache);
1243}
1244
reed@google.com7b201d22011-01-11 18:59:23 +00001245///////////////////////////////////////////////////////////////////////////////
1246
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001247SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context,
1248 GrRenderTarget* rootRenderTarget)
1249 : fContext(context) {
1250
1251 GrAssert(NULL != context);
1252 GrAssert(NULL != rootRenderTarget);
1253
1254 // check this now rather than passing this value to SkGpuDevice cons.
1255 // we want the rt that is bound *now* in the 3D API, not the one
1256 // at the time of newDevice.
1257 if (SkGpuDevice::Current3DApiRenderTarget() == rootRenderTarget) {
1258 fRootRenderTarget = context->createRenderTargetFrom3DApiState();
1259 } else {
1260 fRootRenderTarget = rootRenderTarget;
1261 rootRenderTarget->ref();
1262 }
reed@google.com7b201d22011-01-11 18:59:23 +00001263 context->ref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001264
reed@google.com7b201d22011-01-11 18:59:23 +00001265}
1266
1267SkGpuDeviceFactory::~SkGpuDeviceFactory() {
1268 fContext->unref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001269 fRootRenderTarget->unref();
reed@google.com7b201d22011-01-11 18:59:23 +00001270}
1271
1272SkDevice* SkGpuDeviceFactory::newDevice(SkCanvas*, SkBitmap::Config config,
1273 int width, int height,
1274 bool isOpaque, bool isLayer) {
1275 SkBitmap bm;
1276 bm.setConfig(config, width, height);
1277 bm.setIsOpaque(isOpaque);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001278 return new SkGpuDevice(fContext, bm, isLayer ? NULL : fRootRenderTarget);
reed@google.com7b201d22011-01-11 18:59:23 +00001279}
reed@google.comac10a2d2010-12-22 21:39:39 +00001280