blob: 3dfe02aa1409e5ff04fbfbfbd4b56b7434706a65 [file] [log] [blame]
reed@google.comac10a2d2010-12-22 21:39:39 +00001/*
2 Copyright 2010 Google Inc.
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17
18#include "GrContext.h"
19#include "GrTextContext.h"
20
reed@google.comac10a2d2010-12-22 21:39:39 +000021#include "SkGpuDevice.h"
reed@google.com7b201d22011-01-11 18:59:23 +000022#include "SkGpuDeviceFactory.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000023#include "SkGrTexturePixelRef.h"
24
25#include "SkDrawProcs.h"
26#include "SkGlyphCache.h"
27
28#define CACHE_LAYER_TEXTURES 1
29
30#if 0
31 extern bool (*gShouldDrawProc)();
32 #define CHECK_SHOULD_DRAW(draw) \
33 do { \
34 if (gShouldDrawProc && !gShouldDrawProc()) return; \
35 this->prepareRenderTarget(draw); \
36 } while (0)
37#else
38 #define CHECK_SHOULD_DRAW(draw) this->prepareRenderTarget(draw)
39#endif
40
41class SkAutoExtMatrix {
42public:
43 SkAutoExtMatrix(const SkMatrix* extMatrix) {
44 if (extMatrix) {
45 SkGr::SkMatrix2GrMatrix(*extMatrix, &fMatrix);
46 fExtMatrix = &fMatrix;
47 } else {
48 fExtMatrix = NULL;
49 }
50 }
51 const GrMatrix* extMatrix() const { return fExtMatrix; }
52
53private:
54 GrMatrix fMatrix;
55 GrMatrix* fExtMatrix; // NULL or &fMatrix
56};
57
58///////////////////////////////////////////////////////////////////////////////
59
60SkGpuDevice::SkAutoCachedTexture::
61 SkAutoCachedTexture(SkGpuDevice* device,
62 const SkBitmap& bitmap,
63 const GrSamplerState& sampler,
64 GrTexture** texture) {
65 GrAssert(texture);
66 fTex = NULL;
67 *texture = this->set(device, bitmap, sampler);
68}
69
70SkGpuDevice::SkAutoCachedTexture::SkAutoCachedTexture() {
71 fTex = NULL;
72}
73
74GrTexture* SkGpuDevice::SkAutoCachedTexture::set(SkGpuDevice* device,
75 const SkBitmap& bitmap,
76 const GrSamplerState& sampler) {
77 if (fTex) {
78 fDevice->unlockCachedTexture(fTex);
79 }
80 fDevice = device;
81 GrTexture* texture = (GrTexture*)bitmap.getTexture();
82 if (texture) {
83 // return the native texture
84 fTex = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +000085 } else {
86 // look it up in our cache
87 fTex = device->lockCachedTexture(bitmap, sampler, &texture, false);
88 }
89 return texture;
90}
91
92SkGpuDevice::SkAutoCachedTexture::~SkAutoCachedTexture() {
93 if (fTex) {
94 fDevice->unlockCachedTexture(fTex);
95 }
96}
97
98///////////////////////////////////////////////////////////////////////////////
99
100bool gDoTraceDraw;
101
102struct GrSkDrawProcs : public SkDrawProcs {
103public:
104 GrContext* fContext;
105 GrTextContext* fTextContext;
106 GrFontScaler* fFontScaler; // cached in the skia glyphcache
107};
108
109///////////////////////////////////////////////////////////////////////////////
110
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000111GrRenderTarget* SkGpuDevice::Current3DApiRenderTarget() {
112 return (GrRenderTarget*) -1;
113}
114
115SkGpuDevice::SkGpuDevice(GrContext* context,
116 const SkBitmap& bitmap,
117 GrRenderTarget* renderTargetOrNull)
118 : SkDevice(NULL, bitmap, (NULL == renderTargetOrNull)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000119
120 fNeedPrepareRenderTarget = false;
121 fDrawProcs = NULL;
122
reed@google.com7b201d22011-01-11 18:59:23 +0000123 fContext = context;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000124 fContext->ref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000125
126 fCache = NULL;
127 fTexture = NULL;
128 fRenderTarget = NULL;
129 fNeedClear = false;
130
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000131 if (NULL == renderTargetOrNull) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000132 SkBitmap::Config c = bitmap.config();
133 if (c != SkBitmap::kRGB_565_Config) {
134 c = SkBitmap::kARGB_8888_Config;
135 }
136 SkBitmap bm;
137 bm.setConfig(c, this->width(), this->height());
138
139#if CACHE_LAYER_TEXTURES
140
141 fCache = this->lockCachedTexture(bm, GrSamplerState::ClampNoFilter(),
142 &fTexture, true);
143 if (fCache) {
144 SkASSERT(NULL != fTexture);
145 SkASSERT(fTexture->isRenderTarget());
146 }
147#else
148 const GrGpu::TextureDesc desc = {
149 GrGpu::kRenderTarget_TextureFlag,
150 GrGpu::kNone_AALevel,
151 this->width(),
152 this->height(),
153 SkGr::Bitmap2PixelConfig(bm)
154 };
155
156 fTexture = fContext->createUncachedTexture(desc, NULL, 0);
157#endif
158 if (NULL != fTexture) {
159 fRenderTarget = fTexture->asRenderTarget();
160
161 GrAssert(NULL != fRenderTarget);
162
163 // we defer the actual clear until our gainFocus()
164 fNeedClear = true;
165
166 // wrap the bitmap with a pixelref to expose our texture
167 SkGrTexturePixelRef* pr = new SkGrTexturePixelRef(fTexture);
168 this->setPixelRef(pr, 0)->unref();
169 } else {
170 GrPrintf("--- failed to create gpu-offscreen [%d %d]\n",
171 this->width(), this->height());
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000172 GrAssert(false);
reed@google.comac10a2d2010-12-22 21:39:39 +0000173 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000174 } else if (Current3DApiRenderTarget() == renderTargetOrNull) {
175 fRenderTarget = fContext->createRenderTargetFrom3DApiState();
176 } else {
177 fRenderTarget = renderTargetOrNull;
reed@google.comac10a2d2010-12-22 21:39:39 +0000178 fRenderTarget->ref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000179 }
180}
181
182SkGpuDevice::~SkGpuDevice() {
183 if (fDrawProcs) {
184 delete fDrawProcs;
185 }
186
187 if (fCache) {
188 GrAssert(NULL != fTexture);
189 GrAssert(fRenderTarget == fTexture->asRenderTarget());
190 // IMPORTANT: reattach the rendertarget/tex back to the cache.
191 fContext->reattachAndUnlockCachedTexture((GrTextureEntry*)fCache);
192 } else if (NULL != fTexture) {
193 GrAssert(!CACHE_LAYER_TEXTURES);
194 GrAssert(fRenderTarget == fTexture->asRenderTarget());
195 fTexture->unref();
196 } else if (NULL != fRenderTarget) {
197 fRenderTarget->unref();
198 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000199 fContext->unref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000200}
201
reed@google.comac10a2d2010-12-22 21:39:39 +0000202intptr_t SkGpuDevice::getLayerTextureHandle() const {
203 if (fTexture) {
204 return fTexture->getTextureHandle();
205 } else {
206 return 0;
207 }
208}
209///////////////////////////////////////////////////////////////////////////////
210
211void SkGpuDevice::makeRenderTargetCurrent() {
212 fContext->setRenderTarget(fRenderTarget);
213 fContext->flush(true);
214 fNeedPrepareRenderTarget = true;
215}
216
217///////////////////////////////////////////////////////////////////////////////
218
219bool SkGpuDevice::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
220 SkIRect bounds;
221 bounds.set(0, 0, this->width(), this->height());
222 if (!bounds.intersect(srcRect)) {
223 return false;
224 }
225
226 const int w = bounds.width();
227 const int h = bounds.height();
228 SkBitmap tmp;
229 // note we explicitly specify our rowBytes to be snug (no gap between rows)
230 tmp.setConfig(SkBitmap::kARGB_8888_Config, w, h, w * 4);
231 if (!tmp.allocPixels()) {
232 return false;
233 }
234
235 SkAutoLockPixels alp(tmp);
236 fContext->setRenderTarget(fRenderTarget);
237 // we aren't setting the clip or matrix, so mark as dirty
238 // we don't need to set them for this call and don't have them anyway
239 fNeedPrepareRenderTarget = true;
240
241 if (!fContext->readPixels(bounds.fLeft, bounds.fTop,
242 bounds.width(), bounds.height(),
243 GrTexture::kRGBA_8888_PixelConfig,
244 tmp.getPixels())) {
245 return false;
246 }
247
248 tmp.swap(*bitmap);
249 return true;
250}
251
252void SkGpuDevice::writePixels(const SkBitmap& bitmap, int x, int y) {
253 SkAutoLockPixels alp(bitmap);
254 if (!bitmap.readyToDraw()) {
255 return;
256 }
257 GrTexture::PixelConfig config = SkGr::BitmapConfig2PixelConfig(bitmap.config(),
258 bitmap.isOpaque());
259 fContext->setRenderTarget(fRenderTarget);
260 // we aren't setting the clip or matrix, so mark as dirty
261 // we don't need to set them for this call and don't have them anyway
262 fNeedPrepareRenderTarget = true;
263
264 fContext->writePixels(x, y, bitmap.width(), bitmap.height(),
265 config, bitmap.getPixels(), bitmap.rowBytes());
266}
267
268///////////////////////////////////////////////////////////////////////////////
269
270static void convert_matrixclip(GrContext* context, const SkMatrix& matrix,
271 const SkRegion& clip) {
272 GrMatrix grmat;
273 SkGr::SkMatrix2GrMatrix(matrix, &grmat);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000274 context->setMatrix(grmat);
reed@google.comac10a2d2010-12-22 21:39:39 +0000275
276 SkGrClipIterator iter;
277 iter.reset(clip);
278 GrClip grc(&iter);
279 if (context->getClip() == grc) {
280 } else {
281 context->setClip(grc);
282 }
283}
284
285// call this ever each draw call, to ensure that the context reflects our state,
286// and not the state from some other canvas/device
287void SkGpuDevice::prepareRenderTarget(const SkDraw& draw) {
288 if (fNeedPrepareRenderTarget ||
bsalomon@google.com5782d712011-01-21 21:03:59 +0000289 fContext->getRenderTarget() != fRenderTarget) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000290
291 fContext->setRenderTarget(fRenderTarget);
292 convert_matrixclip(fContext, *draw.fMatrix, *draw.fClip);
293 fNeedPrepareRenderTarget = false;
294 }
295}
296
reed@google.com46799cd2011-02-22 20:56:26 +0000297void SkGpuDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& clip,
298 const SkClipStack& clipStack) {
299 this->INHERITED::setMatrixClip(matrix, clip, clipStack);
reed@google.comac10a2d2010-12-22 21:39:39 +0000300
301 convert_matrixclip(fContext, matrix, clip);
302}
303
304void SkGpuDevice::gainFocus(SkCanvas* canvas, const SkMatrix& matrix,
305 const SkRegion& clip) {
306 fContext->setRenderTarget(fRenderTarget);
307
308 this->INHERITED::gainFocus(canvas, matrix, clip);
309
310 convert_matrixclip(fContext, matrix, clip);
311
312 if (fNeedClear) {
313 fContext->eraseColor(0x0);
314 fNeedClear = false;
315 }
316}
317
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000318bool SkGpuDevice::bindDeviceAsTexture(GrPaint* paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000319 if (NULL != fTexture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000320 paint->setTexture(fTexture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000321 return true;
322 }
323 return false;
324}
325
326///////////////////////////////////////////////////////////////////////////////
327
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000328SK_COMPILE_ASSERT(SkShader::kNone_BitmapType == 0, shader_type_mismatch);
329SK_COMPILE_ASSERT(SkShader::kDefault_BitmapType == 1, shader_type_mismatch);
330SK_COMPILE_ASSERT(SkShader::kRadial_BitmapType == 2, shader_type_mismatch);
331SK_COMPILE_ASSERT(SkShader::kSweep_BitmapType == 3, shader_type_mismatch);
332SK_COMPILE_ASSERT(SkShader::kTwoPointRadial_BitmapType == 4,
333 shader_type_mismatch);
334SK_COMPILE_ASSERT(SkShader::kLast_BitmapType == 4, shader_type_mismatch);
reed@google.comac10a2d2010-12-22 21:39:39 +0000335
bsalomon@google.com5782d712011-01-21 21:03:59 +0000336static const GrSamplerState::SampleMode sk_bmp_type_to_sample_mode[] = {
337 (GrSamplerState::SampleMode) -1, // kNone_BitmapType
338 GrSamplerState::kNormal_SampleMode, // kDefault_BitmapType
339 GrSamplerState::kRadial_SampleMode, // kRadial_BitmapType
340 GrSamplerState::kSweep_SampleMode, // kSweep_BitmapType
341 GrSamplerState::kRadial2_SampleMode, // kTwoPointRadial_BitmapType
342};
343
344bool SkGpuDevice::skPaint2GrPaintNoShader(const SkPaint& skPaint,
345 bool justAlpha,
346 GrPaint* grPaint) {
347
348 grPaint->fDither = skPaint.isDither();
349 grPaint->fAntiAlias = skPaint.isAntiAlias();
350
351 SkXfermode::Coeff sm = SkXfermode::kOne_Coeff;
352 SkXfermode::Coeff dm = SkXfermode::kISA_Coeff;
353
354 SkXfermode* mode = skPaint.getXfermode();
355 if (mode) {
356 if (!mode->asCoeff(&sm, &dm)) {
reed@google.com1a2e8d22011-01-21 22:08:29 +0000357 SkDEBUGCODE(SkDebugf("Unsupported xfer mode.\n");)
bsalomon@google.com5782d712011-01-21 21:03:59 +0000358#if 0
359 return false;
360#endif
361 }
362 }
363 grPaint->fSrcBlendCoeff = sk_blend_to_grblend(sm);
364 grPaint->fDstBlendCoeff = sk_blend_to_grblend(dm);
365
366 if (justAlpha) {
367 uint8_t alpha = skPaint.getAlpha();
368 grPaint->fColor = GrColorPackRGBA(alpha, alpha, alpha, alpha);
369 } else {
370 grPaint->fColor = SkGr::SkColor2GrColor(skPaint.getColor());
371 grPaint->setTexture(NULL);
372 }
373 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000374}
375
bsalomon@google.com5782d712011-01-21 21:03:59 +0000376bool SkGpuDevice::skPaint2GrPaintShader(const SkPaint& skPaint,
377 SkAutoCachedTexture* act,
378 const SkMatrix& ctm,
379 GrPaint* grPaint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000380
bsalomon@google.com5782d712011-01-21 21:03:59 +0000381 SkASSERT(NULL != act);
reed@google.comac10a2d2010-12-22 21:39:39 +0000382
bsalomon@google.com5782d712011-01-21 21:03:59 +0000383 SkShader* shader = skPaint.getShader();
reed@google.comac10a2d2010-12-22 21:39:39 +0000384 if (NULL == shader) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000385 return this->skPaint2GrPaintNoShader(skPaint, false, grPaint);
386 grPaint->setTexture(NULL);
387 return true;
388 } else if (!this->skPaint2GrPaintNoShader(skPaint, true, grPaint)) {
389 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000390 }
391
bsalomon@google.com5782d712011-01-21 21:03:59 +0000392 SkPaint noAlphaPaint(skPaint);
393 noAlphaPaint.setAlpha(255);
394 shader->setContext(this->accessBitmap(false), noAlphaPaint, ctm);
reed@google.comac10a2d2010-12-22 21:39:39 +0000395
reed@google.comac10a2d2010-12-22 21:39:39 +0000396 SkBitmap bitmap;
397 SkMatrix matrix;
398 SkShader::TileMode tileModes[2];
399 SkScalar twoPointParams[3];
400 SkShader::BitmapType bmptype = shader->asABitmap(&bitmap, &matrix,
401 tileModes, twoPointParams);
402
bsalomon@google.com5782d712011-01-21 21:03:59 +0000403 GrSamplerState::SampleMode sampleMode = sk_bmp_type_to_sample_mode[bmptype];
404 if (-1 == sampleMode) {
405 SkDebugf("shader->asABitmap() == kNone_BitmapType\n");
406 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000407 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000408 grPaint->fSampler.setSampleMode(sampleMode);
bsalomon@google.com0748f212011-02-01 22:56:16 +0000409 grPaint->fSampler.setFilter(skPaint.isFilterBitmap());
bsalomon@google.com5782d712011-01-21 21:03:59 +0000410 grPaint->fSampler.setWrapX(sk_tile_mode_to_grwrap(tileModes[0]));
411 grPaint->fSampler.setWrapY(sk_tile_mode_to_grwrap(tileModes[1]));
reed@google.comac10a2d2010-12-22 21:39:39 +0000412 if (GrSamplerState::kRadial2_SampleMode == sampleMode) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000413 grPaint->fSampler.setRadial2Params(twoPointParams[0],
414 twoPointParams[1],
415 twoPointParams[2] < 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000416 }
417
bsalomon@google.com5782d712011-01-21 21:03:59 +0000418 GrTexture* texture = act->set(this, bitmap, grPaint->fSampler);
reed@google.comac10a2d2010-12-22 21:39:39 +0000419 if (NULL == texture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000420 SkDebugf("Couldn't convert bitmap to texture.\n");
421 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000422 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000423 grPaint->setTexture(texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000424
425 // since our texture coords will be in local space, we wack the texture
426 // matrix to map them back into 0...1 before we load it
427 SkMatrix localM;
428 if (shader->getLocalMatrix(&localM)) {
429 SkMatrix inverse;
430 if (localM.invert(&inverse)) {
431 matrix.preConcat(inverse);
432 }
433 }
434 if (SkShader::kDefault_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000435 GrScalar sx = GrFixedToScalar(GR_Fixed1 / bitmap.width());
436 GrScalar sy = GrFixedToScalar(GR_Fixed1 / bitmap.height());
reed@google.comac10a2d2010-12-22 21:39:39 +0000437 matrix.postScale(sx, sy);
reed@google.comac10a2d2010-12-22 21:39:39 +0000438 } else if (SkShader::kRadial_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000439 GrScalar s = GrFixedToScalar(GR_Fixed1 / bitmap.width());
reed@google.comac10a2d2010-12-22 21:39:39 +0000440 matrix.postScale(s, s);
441 }
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000442 GrMatrix grMat;
443 SkGr::SkMatrix2GrMatrix(matrix, &grMat);
444 grPaint->fSampler.setMatrix(grMat);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000445
446 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000447}
448
449///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com5782d712011-01-21 21:03:59 +0000450
451class SkPositionSource {
452public:
453 SkPositionSource(const SkPoint* points, int count)
454 : fPoints(points), fCount(count) {}
455
456 int count() const { return fCount; }
457
458 void writeValue(int i, GrPoint* dstPosition) const {
459 SkASSERT(i < fCount);
460 dstPosition->fX = SkScalarToGrScalar(fPoints[i].fX);
461 dstPosition->fY = SkScalarToGrScalar(fPoints[i].fY);
462 }
463private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000464 const SkPoint* fPoints;
bsalomon@google.com19628322011-02-03 21:30:17 +0000465 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000466};
467
468class SkTexCoordSource {
469public:
470 SkTexCoordSource(const SkPoint* coords)
471 : fCoords(coords) {}
472
473 void writeValue(int i, GrPoint* dstCoord) const {
474 dstCoord->fX = SkScalarToGrScalar(fCoords[i].fX);
475 dstCoord->fY = SkScalarToGrScalar(fCoords[i].fY);
476 }
477private:
478 const SkPoint* fCoords;
479};
480
481class SkColorSource {
482public:
483 SkColorSource(const SkColor* colors) : fColors(colors) {}
484
485 void writeValue(int i, GrColor* dstColor) const {
486 *dstColor = SkGr::SkColor2GrColor(fColors[i]);
487 }
488private:
489 const SkColor* fColors;
490};
491
492class SkIndexSource {
493public:
494 SkIndexSource(const uint16_t* indices, int count)
495 : fIndices(indices), fCount(count) {
496 }
497
498 int count() const { return fCount; }
499
500 void writeValue(int i, uint16_t* dstIndex) const {
501 *dstIndex = fIndices[i];
502 }
503
504private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000505 const uint16_t* fIndices;
bsalomon@google.com19628322011-02-03 21:30:17 +0000506 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000507};
508
509///////////////////////////////////////////////////////////////////////////////
510
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000511#if 0 // not currently being used so don't compile,
512
bsalomon@google.com5782d712011-01-21 21:03:59 +0000513// can be used for positions or texture coordinates
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000514
bsalomon@google.com5782d712011-01-21 21:03:59 +0000515class SkRectFanSource {
516public:
517 SkRectFanSource(const SkRect& rect) : fRect(rect) {}
518
519 int count() const { return 4; }
520
521 void writeValue(int i, GrPoint* dstPoint) const {
522 SkASSERT(i < 4);
523 dstPoint->fX = SkScalarToGrScalar((i % 3) ? fRect.fRight :
524 fRect.fLeft);
525 dstPoint->fY = SkScalarToGrScalar((i < 2) ? fRect.fTop :
526 fRect.fBottom);
527 }
528private:
529 const SkRect& fRect;
530};
531
532class SkIRectFanSource {
533public:
534 SkIRectFanSource(const SkIRect& rect) : fRect(rect) {}
535
536 int count() const { return 4; }
537
538 void writeValue(int i, GrPoint* dstPoint) const {
539 SkASSERT(i < 4);
540 dstPoint->fX = (i % 3) ? GrIntToScalar(fRect.fRight) :
541 GrIntToScalar(fRect.fLeft);
542 dstPoint->fY = (i < 2) ? GrIntToScalar(fRect.fTop) :
543 GrIntToScalar(fRect.fBottom);
544 }
545private:
546 const SkIRect& fRect;
547};
548
549class SkMatRectFanSource {
550public:
551 SkMatRectFanSource(const SkRect& rect, const SkMatrix& matrix)
552 : fRect(rect), fMatrix(matrix) {}
553
554 int count() const { return 4; }
555
556 void writeValue(int i, GrPoint* dstPoint) const {
557 SkASSERT(i < 4);
558
559#if SK_SCALAR_IS_GR_SCALAR
560 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
561 (i < 2) ? fRect.fTop : fRect.fBottom,
562 (SkPoint*)dstPoint);
563#else
564 SkPoint dst;
565 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
566 (i < 2) ? fRect.fTop : fRect.fBottom,
567 &dst);
568 dstPoint->fX = SkScalarToGrScalar(dst.fX);
569 dstPoint->fY = SkScalarToGrScalar(dst.fY);
570#endif
571 }
572private:
573 const SkRect& fRect;
574 const SkMatrix& fMatrix;
575};
576
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000577#endif
578
reed@google.comac10a2d2010-12-22 21:39:39 +0000579///////////////////////////////////////////////////////////////////////////////
580
581void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
582 CHECK_SHOULD_DRAW(draw);
583
bsalomon@google.com5782d712011-01-21 21:03:59 +0000584 GrPaint grPaint;
585 SkAutoCachedTexture act;
586 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000587 return;
588 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000589
590 fContext->drawPaint(grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000591}
592
593// must be in SkCanvas::PointMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +0000594static const GrPrimitiveType gPointMode2PrimtiveType[] = {
595 kPoints_PrimitiveType,
596 kLines_PrimitiveType,
597 kLineStrip_PrimitiveType
reed@google.comac10a2d2010-12-22 21:39:39 +0000598};
599
600void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000601 size_t count, const SkPoint pts[], const SkPaint& paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000602 CHECK_SHOULD_DRAW(draw);
603
604 SkScalar width = paint.getStrokeWidth();
605 if (width < 0) {
606 return;
607 }
608
609 // we only handle hairlines here, else we let the SkDraw call our drawPath()
610 if (width > 0) {
611 draw.drawPoints(mode, count, pts, paint, true);
612 return;
613 }
614
bsalomon@google.com5782d712011-01-21 21:03:59 +0000615 GrPaint grPaint;
616 SkAutoCachedTexture act;
617 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000618 return;
619 }
620
reed@google.comac10a2d2010-12-22 21:39:39 +0000621#if SK_SCALAR_IS_GR_SCALAR
bsalomon@google.com5782d712011-01-21 21:03:59 +0000622 fContext->drawVertices(grPaint,
623 gPointMode2PrimtiveType[mode],
624 count,
625 (GrPoint*)pts,
626 NULL,
627 NULL,
628 NULL,
629 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000630#else
bsalomon@google.com5782d712011-01-21 21:03:59 +0000631 fContext->drawCustomVertices(grPaint,
632 gPointMode2PrimtiveType[mode],
633 SkPositionSource(pts, count));
reed@google.comac10a2d2010-12-22 21:39:39 +0000634#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000635}
636
637void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
638 const SkPaint& paint) {
639 CHECK_SHOULD_DRAW(draw);
640
641 bool doStroke = paint.getStyle() == SkPaint::kStroke_Style;
642 SkScalar width = paint.getStrokeWidth();
643
644 /*
645 We have special code for hairline strokes, miter-strokes, and fills.
reed@google.com69302852011-02-16 18:08:07 +0000646 Anything else we just call our path code.
reed@google.comac10a2d2010-12-22 21:39:39 +0000647 */
reed@google.com69302852011-02-16 18:08:07 +0000648 bool usePath = doStroke && width > 0 &&
649 paint.getStrokeJoin() != SkPaint::kMiter_Join;
650 // another reason we might need to call drawPath...
651 if (paint.getMaskFilter()) {
652 usePath = true;
653 }
654
655 if (usePath) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000656 SkPath path;
657 path.addRect(rect);
658 this->drawPath(draw, path, paint, NULL, true);
659 return;
660 }
661
bsalomon@google.com5782d712011-01-21 21:03:59 +0000662 GrPaint grPaint;
663 SkAutoCachedTexture act;
664 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000665 return;
666 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000667 fContext->drawRect(grPaint, Sk2Gr(rect), doStroke ? width : -1);
reed@google.comac10a2d2010-12-22 21:39:39 +0000668}
669
reed@google.com69302852011-02-16 18:08:07 +0000670#include "SkMaskFilter.h"
671#include "SkBounder.h"
672
reed@google.com69302852011-02-16 18:08:07 +0000673static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
674 SkMaskFilter* filter, const SkMatrix& matrix,
675 const SkRegion& clip, SkBounder* bounder,
676 GrPaint* grp) {
677 SkMask srcM, dstM;
678
679 if (!SkDraw::DrawToMask(path, &clip.getBounds(), filter, &matrix, &srcM,
680 SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
681 return false;
682 }
683
684 SkAutoMaskImage autoSrc(&srcM, false);
685
686 if (!filter->filterMask(&dstM, srcM, matrix, NULL)) {
687 return false;
688 }
689 // this will free-up dstM when we're done (allocated in filterMask())
690 SkAutoMaskImage autoDst(&dstM, false);
691
692 if (clip.quickReject(dstM.fBounds)) {
693 return false;
694 }
695 if (bounder && !bounder->doIRect(dstM.fBounds)) {
696 return false;
697 }
698
699 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
700 // the current clip (and identity matrix) and grpaint settings
701
reed@google.com0c219b62011-02-16 21:31:18 +0000702 GrAutoMatrix avm(context, GrMatrix::I());
reed@google.com69302852011-02-16 18:08:07 +0000703
704 const GrGpu::TextureDesc desc = {
705 0,
706 GrGpu::kNone_AALevel,
707 dstM.fBounds.width(),
708 dstM.fBounds.height(),
709 GrTexture::kAlpha_8_PixelConfig
710 };
711
712 GrTexture* texture = context->createUncachedTexture(desc, dstM.fImage,
713 dstM.fRowBytes);
714 if (NULL == texture) {
715 return false;
716 }
717
reed@google.com0c219b62011-02-16 21:31:18 +0000718 grp->setTexture(texture);
719 texture->unref();
720 grp->fSampler.setClampNoFilter();
reed@google.com69302852011-02-16 18:08:07 +0000721
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000722 GrRect d;
723 d.setLTRB(GrIntToScalar(dstM.fBounds.fLeft),
reed@google.com0c219b62011-02-16 21:31:18 +0000724 GrIntToScalar(dstM.fBounds.fTop),
725 GrIntToScalar(dstM.fBounds.fRight),
726 GrIntToScalar(dstM.fBounds.fBottom));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000727 GrRect s;
728 s.setLTRB(0, 0, GR_Scalar1, GR_Scalar1);
729 context->drawRectToRect(*grp, d, s);
reed@google.com69302852011-02-16 18:08:07 +0000730 return true;
731}
reed@google.com69302852011-02-16 18:08:07 +0000732
reed@google.com0c219b62011-02-16 21:31:18 +0000733void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
reed@google.comac10a2d2010-12-22 21:39:39 +0000734 const SkPaint& paint, const SkMatrix* prePathMatrix,
735 bool pathIsMutable) {
736 CHECK_SHOULD_DRAW(draw);
737
bsalomon@google.com5782d712011-01-21 21:03:59 +0000738 GrPaint grPaint;
739 SkAutoCachedTexture act;
740 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000741 return;
742 }
743
reed@google.com0c219b62011-02-16 21:31:18 +0000744 // BEGIN lift from SkDraw::drawPath()
745
746 SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
747 bool doFill = true;
748 SkPath tmpPath;
reed@google.comac10a2d2010-12-22 21:39:39 +0000749
750 if (prePathMatrix) {
reed@google.come3445642011-02-16 23:20:39 +0000751 SkPath* result = pathPtr;
reed@google.com0c219b62011-02-16 21:31:18 +0000752
reed@google.come3445642011-02-16 23:20:39 +0000753 if (!pathIsMutable) {
754 result = &tmpPath;
755 pathIsMutable = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000756 }
reed@google.come3445642011-02-16 23:20:39 +0000757 // should I push prePathMatrix on our MV stack temporarily, instead
758 // of applying it here? See SkDraw.cpp
759 pathPtr->transform(*prePathMatrix, result);
760 pathPtr = result;
reed@google.comac10a2d2010-12-22 21:39:39 +0000761 }
reed@google.com0c219b62011-02-16 21:31:18 +0000762 // at this point we're done with prePathMatrix
763 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
reed@google.comac10a2d2010-12-22 21:39:39 +0000764
reed@google.com0c219b62011-02-16 21:31:18 +0000765 if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) {
766 doFill = paint.getFillPath(*pathPtr, &tmpPath);
767 pathPtr = &tmpPath;
768 }
769
770 // END lift from SkDraw::drawPath()
771
reed@google.com69302852011-02-16 18:08:07 +0000772 if (paint.getMaskFilter()) {
reed@google.com0c219b62011-02-16 21:31:18 +0000773 // avoid possibly allocating a new path in transform if we can
774 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
775
776 // transform the path into device space
reed@google.come3445642011-02-16 23:20:39 +0000777 pathPtr->transform(*draw.fMatrix, devPathPtr);
reed@google.com0c219b62011-02-16 21:31:18 +0000778
779 drawWithMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
reed@google.com69302852011-02-16 18:08:07 +0000780 *draw.fMatrix, *draw.fClip, draw.fBounder, &grPaint);
781 return;
782 }
reed@google.com69302852011-02-16 18:08:07 +0000783
bsalomon@google.comffca4002011-02-22 20:34:01 +0000784 GrPathFill fill = kHairLine_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000785
reed@google.com0c219b62011-02-16 21:31:18 +0000786 if (doFill) {
787 switch (pathPtr->getFillType()) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000788 case SkPath::kWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000789 fill = kWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000790 break;
791 case SkPath::kEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000792 fill = kEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000793 break;
794 case SkPath::kInverseWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000795 fill = kInverseWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000796 break;
797 case SkPath::kInverseEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000798 fill = kInverseEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000799 break;
800 default:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000801 SkDebugf("Unsupported path fill type\n");
reed@google.comac10a2d2010-12-22 21:39:39 +0000802 return;
803 }
804 }
805
reed@google.com0c219b62011-02-16 21:31:18 +0000806 SkGrPathIter iter(*pathPtr);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000807 fContext->drawPath(grPaint, &iter, fill);
reed@google.comac10a2d2010-12-22 21:39:39 +0000808}
809
reed@google.comac10a2d2010-12-22 21:39:39 +0000810void SkGpuDevice::drawBitmap(const SkDraw& draw,
811 const SkBitmap& bitmap,
812 const SkIRect* srcRectPtr,
813 const SkMatrix& m,
814 const SkPaint& paint) {
815 CHECK_SHOULD_DRAW(draw);
816
817 SkIRect srcRect;
818 if (NULL == srcRectPtr) {
819 srcRect.set(0, 0, bitmap.width(), bitmap.height());
820 } else {
821 srcRect = *srcRectPtr;
822 }
823
bsalomon@google.com5782d712011-01-21 21:03:59 +0000824 GrPaint grPaint;
825 if (!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
826 return;
827 }
828 grPaint.fSampler.setFilter(paint.isFilterBitmap());
829
reed@google.com02a7e6c2011-01-28 21:21:49 +0000830 const int maxTextureDim = fContext->getMaxTextureDimension();
831 if (bitmap.getTexture() || (bitmap.width() <= maxTextureDim &&
832 bitmap.height() <= maxTextureDim)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000833 // take the fast case
bsalomon@google.com5782d712011-01-21 21:03:59 +0000834 this->internalDrawBitmap(draw, bitmap, srcRect, m, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000835 return;
836 }
837
838 // undo the translate done by SkCanvas
839 int DX = SkMax32(0, srcRect.fLeft);
840 int DY = SkMax32(0, srcRect.fTop);
841 // compute clip bounds in local coordinates
842 SkIRect clipRect;
843 {
844 SkRect r;
845 r.set(draw.fClip->getBounds());
846 SkMatrix matrix, inverse;
847 matrix.setConcat(*draw.fMatrix, m);
848 if (!matrix.invert(&inverse)) {
849 return;
850 }
851 inverse.mapRect(&r);
852 r.roundOut(&clipRect);
853 // apply the canvas' translate to our local clip
854 clipRect.offset(DX, DY);
855 }
856
reed@google.com02a7e6c2011-01-28 21:21:49 +0000857 int nx = bitmap.width() / maxTextureDim;
858 int ny = bitmap.height() / maxTextureDim;
reed@google.comac10a2d2010-12-22 21:39:39 +0000859 for (int x = 0; x <= nx; x++) {
860 for (int y = 0; y <= ny; y++) {
861 SkIRect tileR;
reed@google.com02a7e6c2011-01-28 21:21:49 +0000862 tileR.set(x * maxTextureDim, y * maxTextureDim,
863 (x + 1) * maxTextureDim, (y + 1) * maxTextureDim);
reed@google.comac10a2d2010-12-22 21:39:39 +0000864 if (!SkIRect::Intersects(tileR, clipRect)) {
865 continue;
866 }
867
868 SkIRect srcR = tileR;
869 if (!srcR.intersect(srcRect)) {
870 continue;
871 }
872
873 SkBitmap tmpB;
874 if (bitmap.extractSubset(&tmpB, tileR)) {
875 // now offset it to make it "local" to our tmp bitmap
876 srcR.offset(-tileR.fLeft, -tileR.fTop);
877
878 SkMatrix tmpM(m);
879 {
880 int dx = tileR.fLeft - DX + SkMax32(0, srcR.fLeft);
881 int dy = tileR.fTop - DY + SkMax32(0, srcR.fTop);
882 tmpM.preTranslate(SkIntToScalar(dx), SkIntToScalar(dy));
883 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000884 this->internalDrawBitmap(draw, tmpB, srcR, tmpM, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000885 }
886 }
887 }
888}
889
890/*
891 * This is called by drawBitmap(), which has to handle images that may be too
892 * large to be represented by a single texture.
893 *
bsalomon@google.com5782d712011-01-21 21:03:59 +0000894 * internalDrawBitmap assumes that the specified bitmap will fit in a texture
895 * and that non-texture portion of the GrPaint has already been setup.
reed@google.comac10a2d2010-12-22 21:39:39 +0000896 */
897void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
898 const SkBitmap& bitmap,
899 const SkIRect& srcRect,
900 const SkMatrix& m,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000901 GrPaint* grPaint) {
reed@google.com02a7e6c2011-01-28 21:21:49 +0000902 SkASSERT(bitmap.width() <= fContext->getMaxTextureDimension() &&
903 bitmap.height() <= fContext->getMaxTextureDimension());
reed@google.comac10a2d2010-12-22 21:39:39 +0000904
905 SkAutoLockPixels alp(bitmap);
906 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
907 return;
908 }
909
bsalomon@google.com5782d712011-01-21 21:03:59 +0000910 grPaint->fSampler.setWrapX(GrSamplerState::kClamp_WrapMode);
911 grPaint->fSampler.setWrapY(GrSamplerState::kClamp_WrapMode);
912 grPaint->fSampler.setSampleMode(GrSamplerState::kNormal_SampleMode);
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000913 grPaint->fSampler.setMatrix(GrMatrix::I());
reed@google.comac10a2d2010-12-22 21:39:39 +0000914
915 GrTexture* texture;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000916 SkAutoCachedTexture act(this, bitmap, grPaint->fSampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000917 if (NULL == texture) {
918 return;
919 }
920
bsalomon@google.com5782d712011-01-21 21:03:59 +0000921 grPaint->setTexture(texture);
reed@google.com46799cd2011-02-22 20:56:26 +0000922
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000923 GrRect dstRect(0, 0, GrIntToScalar(srcRect.width()), GrIntToScalar(srcRect.height()));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000924 GrRect paintRect;
925 paintRect.setLTRB(GrFixedToScalar((srcRect.fLeft << 16) / bitmap.width()),
926 GrFixedToScalar((srcRect.fTop << 16) / bitmap.height()),
927 GrFixedToScalar((srcRect.fRight << 16) / bitmap.width()),
928 GrFixedToScalar((srcRect.fBottom << 16) / bitmap.height()));
reed@google.comac10a2d2010-12-22 21:39:39 +0000929
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000930 GrMatrix grMat;
931 SkGr::SkMatrix2GrMatrix(m, &grMat);
reed@google.comac10a2d2010-12-22 21:39:39 +0000932
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000933 fContext->drawRectToRect(*grPaint, dstRect, paintRect, &grMat);
reed@google.comac10a2d2010-12-22 21:39:39 +0000934}
935
936void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
937 int left, int top, const SkPaint& paint) {
938 CHECK_SHOULD_DRAW(draw);
939
940 SkAutoLockPixels alp(bitmap);
941 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
942 return;
943 }
944
bsalomon@google.com5782d712011-01-21 21:03:59 +0000945 GrPaint grPaint;
946 if(!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
947 return;
948 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000949
bsalomon@google.com5782d712011-01-21 21:03:59 +0000950 GrAutoMatrix avm(fContext, GrMatrix::I());
951
952 GrTexture* texture;
953 grPaint.fSampler.setClampNoFilter();
954 SkAutoCachedTexture act(this, bitmap, grPaint.fSampler, &texture);
955
bsalomon@google.com5782d712011-01-21 21:03:59 +0000956 grPaint.setTexture(texture);
957
bsalomon@google.com5782d712011-01-21 21:03:59 +0000958 fContext->drawRectToRect(grPaint,
959 GrRect(GrIntToScalar(left), GrIntToScalar(top),
960 GrIntToScalar(left + bitmap.width()),
961 GrIntToScalar(top + bitmap.height())),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000962 GrRect(0, 0, GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +0000963}
964
965void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
966 int x, int y, const SkPaint& paint) {
967 CHECK_SHOULD_DRAW(draw);
968
bsalomon@google.com5782d712011-01-21 21:03:59 +0000969 GrPaint grPaint;
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000970 if (!((SkGpuDevice*)dev)->bindDeviceAsTexture(&grPaint) ||
bsalomon@google.com5782d712011-01-21 21:03:59 +0000971 !this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
972 return;
reed@google.comac10a2d2010-12-22 21:39:39 +0000973 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000974
975 SkASSERT(NULL != grPaint.getTexture());
976
977 const SkBitmap& bm = dev->accessBitmap(false);
978 int w = bm.width();
979 int h = bm.height();
980
981 GrAutoMatrix avm(fContext, GrMatrix::I());
982
983 grPaint.fSampler.setClampNoFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +0000984
985 fContext->drawRectToRect(grPaint,
reed@google.com1a2e8d22011-01-21 22:08:29 +0000986 GrRect(GrIntToScalar(x),
987 GrIntToScalar(y),
988 GrIntToScalar(x + w),
bsalomon@google.com5782d712011-01-21 21:03:59 +0000989 GrIntToScalar(y + h)),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000990 GrRect(0, 0, GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +0000991}
992
993///////////////////////////////////////////////////////////////////////////////
994
995// must be in SkCanvas::VertexMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +0000996static const GrPrimitiveType gVertexMode2PrimitiveType[] = {
997 kTriangles_PrimitiveType,
998 kTriangleStrip_PrimitiveType,
999 kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +00001000};
1001
1002void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
1003 int vertexCount, const SkPoint vertices[],
1004 const SkPoint texs[], const SkColor colors[],
1005 SkXfermode* xmode,
1006 const uint16_t indices[], int indexCount,
1007 const SkPaint& paint) {
1008 CHECK_SHOULD_DRAW(draw);
1009
bsalomon@google.com5782d712011-01-21 21:03:59 +00001010 GrPaint grPaint;
1011 SkAutoCachedTexture act;
1012 // we ignore the shader if texs is null.
1013 if (NULL == texs) {
1014 if (!this->skPaint2GrPaintNoShader(paint, false, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001015 return;
1016 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001017 } else {
reed@google.com1a2e8d22011-01-21 22:08:29 +00001018 if (!this->skPaint2GrPaintShader(paint, &act,
1019 *draw.fMatrix,
bsalomon@google.com5782d712011-01-21 21:03:59 +00001020 &grPaint)) {
1021 return;
1022 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001023 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001024
1025 if (NULL != xmode && NULL != texs && NULL != colors) {
1026 SkXfermode::Mode mode;
1027 if (!SkXfermode::IsMode(xmode, &mode) ||
1028 SkXfermode::kMultiply_Mode != mode) {
1029 SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
1030#if 0
1031 return
1032#endif
1033 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001034 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001035
1036#if SK_SCALAR_IS_GR_SCALAR
1037 // even if GrColor and SkColor byte offsets match we need
1038 // to perform pre-multiply.
1039 if (NULL == colors) {
1040 fContext->drawVertices(grPaint,
1041 gVertexMode2PrimitiveType[vmode],
1042 vertexCount,
1043 (GrPoint*) vertices,
1044 (GrPoint*) texs,
1045 NULL,
1046 indices,
1047 indexCount);
1048 } else
1049#endif
1050 {
1051 SkTexCoordSource texSrc(texs);
1052 SkColorSource colSrc(colors);
1053 SkIndexSource idxSrc(indices, indexCount);
1054
1055 fContext->drawCustomVertices(grPaint,
1056 gVertexMode2PrimitiveType[vmode],
1057 SkPositionSource(vertices, vertexCount),
1058 (NULL == texs) ? NULL : &texSrc,
1059 (NULL == colors) ? NULL : &colSrc,
1060 (NULL == indices) ? NULL : &idxSrc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001061 }
1062}
1063
1064///////////////////////////////////////////////////////////////////////////////
1065
1066static void GlyphCacheAuxProc(void* data) {
1067 delete (GrFontScaler*)data;
1068}
1069
1070static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) {
1071 void* auxData;
1072 GrFontScaler* scaler = NULL;
1073 if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
1074 scaler = (GrFontScaler*)auxData;
1075 }
1076 if (NULL == scaler) {
1077 scaler = new SkGrFontScaler(cache);
1078 cache->setAuxProc(GlyphCacheAuxProc, scaler);
1079 }
1080 return scaler;
1081}
1082
1083static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
1084 SkFixed fx, SkFixed fy,
1085 const SkGlyph& glyph) {
1086 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1087
1088 GrSkDrawProcs* procs = (GrSkDrawProcs*)state.fDraw->fProcs;
1089
1090 if (NULL == procs->fFontScaler) {
1091 procs->fFontScaler = get_gr_font_scaler(state.fCache);
1092 }
1093 procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0),
1094 SkIntToFixed(SkFixedFloor(fx)), fy,
1095 procs->fFontScaler);
1096}
1097
bsalomon@google.com5782d712011-01-21 21:03:59 +00001098SkDrawProcs* SkGpuDevice::initDrawForText(GrTextContext* context) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001099
1100 // deferred allocation
1101 if (NULL == fDrawProcs) {
1102 fDrawProcs = new GrSkDrawProcs;
1103 fDrawProcs->fD1GProc = SkGPU_Draw1Glyph;
1104 fDrawProcs->fContext = fContext;
1105 }
1106
1107 // init our (and GL's) state
1108 fDrawProcs->fTextContext = context;
1109 fDrawProcs->fFontScaler = NULL;
1110 return fDrawProcs;
1111}
1112
1113void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
1114 size_t byteLength, SkScalar x, SkScalar y,
1115 const SkPaint& paint) {
1116 CHECK_SHOULD_DRAW(draw);
1117
1118 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1119 // this guy will just call our drawPath()
1120 draw.drawText((const char*)text, byteLength, x, y, paint);
1121 } else {
1122 SkAutoExtMatrix aem(draw.fExtMatrix);
1123 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001124
1125 GrPaint grPaint;
1126 SkAutoCachedTexture act;
1127
1128 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1129 return;
1130 }
1131 GrTextContext context(fContext, grPaint, aem.extMatrix());
1132 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001133 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
1134 }
1135}
1136
1137void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
1138 size_t byteLength, const SkScalar pos[],
1139 SkScalar constY, int scalarsPerPos,
1140 const SkPaint& paint) {
1141 CHECK_SHOULD_DRAW(draw);
1142
1143 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1144 // this guy will just call our drawPath()
1145 draw.drawPosText((const char*)text, byteLength, pos, constY,
1146 scalarsPerPos, paint);
1147 } else {
1148 SkAutoExtMatrix aem(draw.fExtMatrix);
1149 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001150
1151 GrPaint grPaint;
1152 SkAutoCachedTexture act;
1153 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1154 return;
1155 }
1156
1157 GrTextContext context(fContext, grPaint, aem.extMatrix());
1158 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001159 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
1160 scalarsPerPos, paint);
1161 }
1162}
1163
1164void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
1165 size_t len, const SkPath& path,
1166 const SkMatrix* m, const SkPaint& paint) {
1167 CHECK_SHOULD_DRAW(draw);
1168
1169 SkASSERT(draw.fDevice == this);
1170 draw.drawTextOnPath((const char*)text, len, path, m, paint);
1171}
1172
1173///////////////////////////////////////////////////////////////////////////////
1174
1175SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
1176 const GrSamplerState& sampler,
1177 GrTexture** texture,
1178 bool forDeviceRenderTarget) {
1179 GrContext* ctx = this->context();
1180 uint32_t p0, p1;
1181 if (forDeviceRenderTarget) {
1182 p0 = p1 = -1;
1183 } else {
1184 p0 = bitmap.getGenerationID();
1185 p1 = bitmap.pixelRefOffset();
1186 }
1187
1188 GrTexture* newTexture = NULL;
1189 GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
1190 GrTextureEntry* entry = ctx->findAndLockTexture(&key, sampler);
1191
1192 if (NULL == entry) {
1193
1194 if (forDeviceRenderTarget) {
1195 const GrGpu::TextureDesc desc = {
1196 GrGpu::kRenderTarget_TextureFlag,
1197 GrGpu::kNone_AALevel,
1198 bitmap.width(),
1199 bitmap.height(),
1200 SkGr::Bitmap2PixelConfig(bitmap)
1201 };
1202 entry = ctx->createAndLockTexture(&key, sampler, desc, NULL, 0);
1203
1204 } else {
1205 entry = sk_gr_create_bitmap_texture(ctx, &key, sampler, bitmap);
1206 }
1207 if (NULL == entry) {
1208 GrPrintf("---- failed to create texture for cache [%d %d]\n",
1209 bitmap.width(), bitmap.height());
1210 }
1211 }
1212
1213 if (NULL != entry) {
1214 newTexture = entry->texture();
reed@google.comac10a2d2010-12-22 21:39:39 +00001215 if (texture) {
1216 *texture = newTexture;
1217 }
1218 // IMPORTANT: We can't allow another SkGpuDevice to get this
1219 // cache entry until this one is destroyed!
1220 if (forDeviceRenderTarget) {
1221 ctx->detachCachedTexture(entry);
1222 }
1223 }
1224 return (TexCache*)entry;
1225}
1226
1227void SkGpuDevice::unlockCachedTexture(TexCache* cache) {
1228 this->context()->unlockTexture((GrTextureEntry*)cache);
1229}
1230
reed@google.com7b201d22011-01-11 18:59:23 +00001231///////////////////////////////////////////////////////////////////////////////
1232
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001233SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context,
1234 GrRenderTarget* rootRenderTarget)
1235 : fContext(context) {
1236
1237 GrAssert(NULL != context);
1238 GrAssert(NULL != rootRenderTarget);
1239
1240 // check this now rather than passing this value to SkGpuDevice cons.
1241 // we want the rt that is bound *now* in the 3D API, not the one
1242 // at the time of newDevice.
1243 if (SkGpuDevice::Current3DApiRenderTarget() == rootRenderTarget) {
1244 fRootRenderTarget = context->createRenderTargetFrom3DApiState();
1245 } else {
1246 fRootRenderTarget = rootRenderTarget;
1247 rootRenderTarget->ref();
1248 }
reed@google.com7b201d22011-01-11 18:59:23 +00001249 context->ref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001250
reed@google.com7b201d22011-01-11 18:59:23 +00001251}
1252
1253SkGpuDeviceFactory::~SkGpuDeviceFactory() {
1254 fContext->unref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001255 fRootRenderTarget->unref();
reed@google.com7b201d22011-01-11 18:59:23 +00001256}
1257
1258SkDevice* SkGpuDeviceFactory::newDevice(SkCanvas*, SkBitmap::Config config,
1259 int width, int height,
1260 bool isOpaque, bool isLayer) {
1261 SkBitmap bm;
1262 bm.setConfig(config, width, height);
1263 bm.setIsOpaque(isOpaque);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001264 return new SkGpuDevice(fContext, bm, isLayer ? NULL : fRootRenderTarget);
reed@google.com7b201d22011-01-11 18:59:23 +00001265}
reed@google.comac10a2d2010-12-22 21:39:39 +00001266