blob: 0c9b6ed01687bdbea6c71e6043cdcef2b544cb5c [file] [log] [blame]
reed@google.comac10a2d2010-12-22 21:39:39 +00001/*
bsalomon@google.com1da07462011-03-10 14:51:57 +00002 Copyright 2011 Google Inc.
reed@google.comac10a2d2010-12-22 21:39:39 +00003
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17
18#include "GrContext.h"
19#include "GrTextContext.h"
20
reed@google.comac10a2d2010-12-22 21:39:39 +000021#include "SkGpuDevice.h"
reed@google.com7b201d22011-01-11 18:59:23 +000022#include "SkGpuDeviceFactory.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000023#include "SkGrTexturePixelRef.h"
24
25#include "SkDrawProcs.h"
26#include "SkGlyphCache.h"
reed@google.comc9aa5872011-04-05 21:05:37 +000027#include "SkUtils.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000028
29#define CACHE_LAYER_TEXTURES 1
30
31#if 0
32 extern bool (*gShouldDrawProc)();
33 #define CHECK_SHOULD_DRAW(draw) \
34 do { \
35 if (gShouldDrawProc && !gShouldDrawProc()) return; \
36 this->prepareRenderTarget(draw); \
37 } while (0)
38#else
39 #define CHECK_SHOULD_DRAW(draw) this->prepareRenderTarget(draw)
40#endif
41
42class SkAutoExtMatrix {
43public:
44 SkAutoExtMatrix(const SkMatrix* extMatrix) {
45 if (extMatrix) {
46 SkGr::SkMatrix2GrMatrix(*extMatrix, &fMatrix);
47 fExtMatrix = &fMatrix;
48 } else {
49 fExtMatrix = NULL;
50 }
51 }
52 const GrMatrix* extMatrix() const { return fExtMatrix; }
53
54private:
55 GrMatrix fMatrix;
56 GrMatrix* fExtMatrix; // NULL or &fMatrix
57};
58
59///////////////////////////////////////////////////////////////////////////////
60
61SkGpuDevice::SkAutoCachedTexture::
62 SkAutoCachedTexture(SkGpuDevice* device,
63 const SkBitmap& bitmap,
64 const GrSamplerState& sampler,
65 GrTexture** texture) {
66 GrAssert(texture);
67 fTex = NULL;
68 *texture = this->set(device, bitmap, sampler);
69}
70
71SkGpuDevice::SkAutoCachedTexture::SkAutoCachedTexture() {
72 fTex = NULL;
73}
74
75GrTexture* SkGpuDevice::SkAutoCachedTexture::set(SkGpuDevice* device,
76 const SkBitmap& bitmap,
77 const GrSamplerState& sampler) {
78 if (fTex) {
79 fDevice->unlockCachedTexture(fTex);
80 }
81 fDevice = device;
82 GrTexture* texture = (GrTexture*)bitmap.getTexture();
83 if (texture) {
84 // return the native texture
85 fTex = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +000086 } else {
87 // look it up in our cache
88 fTex = device->lockCachedTexture(bitmap, sampler, &texture, false);
89 }
90 return texture;
91}
92
93SkGpuDevice::SkAutoCachedTexture::~SkAutoCachedTexture() {
94 if (fTex) {
95 fDevice->unlockCachedTexture(fTex);
96 }
97}
98
99///////////////////////////////////////////////////////////////////////////////
100
101bool gDoTraceDraw;
102
103struct GrSkDrawProcs : public SkDrawProcs {
104public:
105 GrContext* fContext;
106 GrTextContext* fTextContext;
107 GrFontScaler* fFontScaler; // cached in the skia glyphcache
108};
109
110///////////////////////////////////////////////////////////////////////////////
111
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000112GrRenderTarget* SkGpuDevice::Current3DApiRenderTarget() {
113 return (GrRenderTarget*) -1;
114}
115
116SkGpuDevice::SkGpuDevice(GrContext* context,
117 const SkBitmap& bitmap,
118 GrRenderTarget* renderTargetOrNull)
119 : SkDevice(NULL, bitmap, (NULL == renderTargetOrNull)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000120
121 fNeedPrepareRenderTarget = false;
122 fDrawProcs = NULL;
123
reed@google.com7b201d22011-01-11 18:59:23 +0000124 fContext = context;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000125 fContext->ref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000126
127 fCache = NULL;
128 fTexture = NULL;
129 fRenderTarget = NULL;
130 fNeedClear = false;
131
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000132 if (NULL == renderTargetOrNull) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000133 SkBitmap::Config c = bitmap.config();
134 if (c != SkBitmap::kRGB_565_Config) {
135 c = SkBitmap::kARGB_8888_Config;
136 }
137 SkBitmap bm;
138 bm.setConfig(c, this->width(), this->height());
139
140#if CACHE_LAYER_TEXTURES
141
142 fCache = this->lockCachedTexture(bm, GrSamplerState::ClampNoFilter(),
143 &fTexture, true);
144 if (fCache) {
145 SkASSERT(NULL != fTexture);
bsalomon@google.com1da07462011-03-10 14:51:57 +0000146 SkASSERT(NULL != fTexture->asRenderTarget());
reed@google.comac10a2d2010-12-22 21:39:39 +0000147 }
148#else
149 const GrGpu::TextureDesc desc = {
150 GrGpu::kRenderTarget_TextureFlag,
151 GrGpu::kNone_AALevel,
152 this->width(),
153 this->height(),
154 SkGr::Bitmap2PixelConfig(bm)
155 };
156
157 fTexture = fContext->createUncachedTexture(desc, NULL, 0);
158#endif
159 if (NULL != fTexture) {
160 fRenderTarget = fTexture->asRenderTarget();
161
162 GrAssert(NULL != fRenderTarget);
163
164 // we defer the actual clear until our gainFocus()
165 fNeedClear = true;
166
167 // wrap the bitmap with a pixelref to expose our texture
168 SkGrTexturePixelRef* pr = new SkGrTexturePixelRef(fTexture);
169 this->setPixelRef(pr, 0)->unref();
170 } else {
171 GrPrintf("--- failed to create gpu-offscreen [%d %d]\n",
172 this->width(), this->height());
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000173 GrAssert(false);
reed@google.comac10a2d2010-12-22 21:39:39 +0000174 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000175 } else {
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000176 if (Current3DApiRenderTarget() == renderTargetOrNull) {
177 fRenderTarget = fContext->createRenderTargetFrom3DApiState();
178 } else {
179 fRenderTarget = renderTargetOrNull;
180 fRenderTarget->ref();
181 }
182 SkGrRenderTargetPixelRef* pr = new SkGrRenderTargetPixelRef(fRenderTarget);
183 this->setPixelRef(pr, 0)->unref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000184 }
185}
186
187SkGpuDevice::~SkGpuDevice() {
188 if (fDrawProcs) {
189 delete fDrawProcs;
190 }
191
192 if (fCache) {
193 GrAssert(NULL != fTexture);
194 GrAssert(fRenderTarget == fTexture->asRenderTarget());
195 // IMPORTANT: reattach the rendertarget/tex back to the cache.
196 fContext->reattachAndUnlockCachedTexture((GrTextureEntry*)fCache);
197 } else if (NULL != fTexture) {
198 GrAssert(!CACHE_LAYER_TEXTURES);
199 GrAssert(fRenderTarget == fTexture->asRenderTarget());
200 fTexture->unref();
201 } else if (NULL != fRenderTarget) {
202 fRenderTarget->unref();
203 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000204 fContext->unref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000205}
206
reed@google.comac10a2d2010-12-22 21:39:39 +0000207intptr_t SkGpuDevice::getLayerTextureHandle() const {
208 if (fTexture) {
209 return fTexture->getTextureHandle();
210 } else {
211 return 0;
212 }
213}
214///////////////////////////////////////////////////////////////////////////////
215
216void SkGpuDevice::makeRenderTargetCurrent() {
217 fContext->setRenderTarget(fRenderTarget);
218 fContext->flush(true);
219 fNeedPrepareRenderTarget = true;
220}
221
222///////////////////////////////////////////////////////////////////////////////
223
224bool SkGpuDevice::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
225 SkIRect bounds;
226 bounds.set(0, 0, this->width(), this->height());
227 if (!bounds.intersect(srcRect)) {
228 return false;
229 }
230
231 const int w = bounds.width();
232 const int h = bounds.height();
233 SkBitmap tmp;
234 // note we explicitly specify our rowBytes to be snug (no gap between rows)
235 tmp.setConfig(SkBitmap::kARGB_8888_Config, w, h, w * 4);
236 if (!tmp.allocPixels()) {
237 return false;
238 }
239
240 SkAutoLockPixels alp(tmp);
reed@google.comac10a2d2010-12-22 21:39:39 +0000241
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000242 if (!fContext->readRenderTargetPixels(fRenderTarget,
243 bounds.fLeft, bounds.fTop,
244 bounds.width(), bounds.height(),
245 kRGBA_8888_GrPixelConfig,
246 tmp.getPixels())) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000247 return false;
248 }
249
250 tmp.swap(*bitmap);
251 return true;
252}
253
254void SkGpuDevice::writePixels(const SkBitmap& bitmap, int x, int y) {
255 SkAutoLockPixels alp(bitmap);
256 if (!bitmap.readyToDraw()) {
257 return;
258 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000259 GrPixelConfig config = SkGr::BitmapConfig2PixelConfig(bitmap.config(),
260 bitmap.isOpaque());
reed@google.comac10a2d2010-12-22 21:39:39 +0000261 fContext->setRenderTarget(fRenderTarget);
262 // we aren't setting the clip or matrix, so mark as dirty
263 // we don't need to set them for this call and don't have them anyway
264 fNeedPrepareRenderTarget = true;
265
266 fContext->writePixels(x, y, bitmap.width(), bitmap.height(),
267 config, bitmap.getPixels(), bitmap.rowBytes());
268}
269
270///////////////////////////////////////////////////////////////////////////////
271
272static void convert_matrixclip(GrContext* context, const SkMatrix& matrix,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000273 const SkClipStack& clipStack,
reed@google.com6f8f2922011-03-04 22:27:10 +0000274 const SkRegion& clipRegion,
275 const SkIPoint& origin) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000276 GrMatrix grmat;
277 SkGr::SkMatrix2GrMatrix(matrix, &grmat);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000278 context->setMatrix(grmat);
reed@google.comac10a2d2010-12-22 21:39:39 +0000279
280 SkGrClipIterator iter;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000281 iter.reset(clipStack);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000282 const SkIRect& skBounds = clipRegion.getBounds();
283 GrRect bounds;
284 bounds.setLTRB(GrIntToScalar(skBounds.fLeft),
285 GrIntToScalar(skBounds.fTop),
286 GrIntToScalar(skBounds.fRight),
287 GrIntToScalar(skBounds.fBottom));
reed@google.com6f8f2922011-03-04 22:27:10 +0000288 GrClip grc(&iter, GrIntToScalar(-origin.x()), GrIntToScalar(-origin.y()),
289 &bounds);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000290 context->setClip(grc);
reed@google.comac10a2d2010-12-22 21:39:39 +0000291}
292
293// call this ever each draw call, to ensure that the context reflects our state,
294// and not the state from some other canvas/device
295void SkGpuDevice::prepareRenderTarget(const SkDraw& draw) {
296 if (fNeedPrepareRenderTarget ||
bsalomon@google.com5782d712011-01-21 21:03:59 +0000297 fContext->getRenderTarget() != fRenderTarget) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000298
299 fContext->setRenderTarget(fRenderTarget);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000300 SkASSERT(draw.fClipStack);
301 convert_matrixclip(fContext, *draw.fMatrix,
reed@google.com6f8f2922011-03-04 22:27:10 +0000302 *draw.fClipStack, *draw.fClip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000303 fNeedPrepareRenderTarget = false;
304 }
305}
306
reed@google.com46799cd2011-02-22 20:56:26 +0000307void SkGpuDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& clip,
308 const SkClipStack& clipStack) {
309 this->INHERITED::setMatrixClip(matrix, clip, clipStack);
reed@google.comac10a2d2010-12-22 21:39:39 +0000310
reed@google.com6f8f2922011-03-04 22:27:10 +0000311 convert_matrixclip(fContext, matrix, clipStack, clip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000312}
313
314void SkGpuDevice::gainFocus(SkCanvas* canvas, const SkMatrix& matrix,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000315 const SkRegion& clip, const SkClipStack& clipStack) {
316
reed@google.comac10a2d2010-12-22 21:39:39 +0000317 fContext->setRenderTarget(fRenderTarget);
318
bsalomon@google.comd302f142011-03-03 13:54:13 +0000319 this->INHERITED::gainFocus(canvas, matrix, clip, clipStack);
reed@google.comac10a2d2010-12-22 21:39:39 +0000320
reed@google.com6f8f2922011-03-04 22:27:10 +0000321 convert_matrixclip(fContext, matrix, clipStack, clip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000322
323 if (fNeedClear) {
324 fContext->eraseColor(0x0);
325 fNeedClear = false;
326 }
327}
328
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000329bool SkGpuDevice::bindDeviceAsTexture(GrPaint* paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000330 if (NULL != fTexture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000331 paint->setTexture(fTexture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000332 return true;
333 }
334 return false;
335}
336
337///////////////////////////////////////////////////////////////////////////////
338
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000339SK_COMPILE_ASSERT(SkShader::kNone_BitmapType == 0, shader_type_mismatch);
340SK_COMPILE_ASSERT(SkShader::kDefault_BitmapType == 1, shader_type_mismatch);
341SK_COMPILE_ASSERT(SkShader::kRadial_BitmapType == 2, shader_type_mismatch);
342SK_COMPILE_ASSERT(SkShader::kSweep_BitmapType == 3, shader_type_mismatch);
343SK_COMPILE_ASSERT(SkShader::kTwoPointRadial_BitmapType == 4,
344 shader_type_mismatch);
345SK_COMPILE_ASSERT(SkShader::kLast_BitmapType == 4, shader_type_mismatch);
reed@google.comac10a2d2010-12-22 21:39:39 +0000346
bsalomon@google.com5782d712011-01-21 21:03:59 +0000347static const GrSamplerState::SampleMode sk_bmp_type_to_sample_mode[] = {
348 (GrSamplerState::SampleMode) -1, // kNone_BitmapType
349 GrSamplerState::kNormal_SampleMode, // kDefault_BitmapType
350 GrSamplerState::kRadial_SampleMode, // kRadial_BitmapType
351 GrSamplerState::kSweep_SampleMode, // kSweep_BitmapType
352 GrSamplerState::kRadial2_SampleMode, // kTwoPointRadial_BitmapType
353};
354
355bool SkGpuDevice::skPaint2GrPaintNoShader(const SkPaint& skPaint,
356 bool justAlpha,
357 GrPaint* grPaint) {
358
359 grPaint->fDither = skPaint.isDither();
360 grPaint->fAntiAlias = skPaint.isAntiAlias();
361
362 SkXfermode::Coeff sm = SkXfermode::kOne_Coeff;
363 SkXfermode::Coeff dm = SkXfermode::kISA_Coeff;
364
365 SkXfermode* mode = skPaint.getXfermode();
366 if (mode) {
367 if (!mode->asCoeff(&sm, &dm)) {
reed@google.com1a2e8d22011-01-21 22:08:29 +0000368 SkDEBUGCODE(SkDebugf("Unsupported xfer mode.\n");)
bsalomon@google.com5782d712011-01-21 21:03:59 +0000369#if 0
370 return false;
371#endif
372 }
373 }
374 grPaint->fSrcBlendCoeff = sk_blend_to_grblend(sm);
375 grPaint->fDstBlendCoeff = sk_blend_to_grblend(dm);
376
377 if (justAlpha) {
378 uint8_t alpha = skPaint.getAlpha();
379 grPaint->fColor = GrColorPackRGBA(alpha, alpha, alpha, alpha);
380 } else {
381 grPaint->fColor = SkGr::SkColor2GrColor(skPaint.getColor());
382 grPaint->setTexture(NULL);
383 }
384 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000385}
386
bsalomon@google.com5782d712011-01-21 21:03:59 +0000387bool SkGpuDevice::skPaint2GrPaintShader(const SkPaint& skPaint,
388 SkAutoCachedTexture* act,
389 const SkMatrix& ctm,
390 GrPaint* grPaint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000391
bsalomon@google.com5782d712011-01-21 21:03:59 +0000392 SkASSERT(NULL != act);
reed@google.comac10a2d2010-12-22 21:39:39 +0000393
bsalomon@google.com5782d712011-01-21 21:03:59 +0000394 SkShader* shader = skPaint.getShader();
reed@google.comac10a2d2010-12-22 21:39:39 +0000395 if (NULL == shader) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000396 return this->skPaint2GrPaintNoShader(skPaint, false, grPaint);
397 grPaint->setTexture(NULL);
398 return true;
399 } else if (!this->skPaint2GrPaintNoShader(skPaint, true, grPaint)) {
400 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000401 }
402
bsalomon@google.com5782d712011-01-21 21:03:59 +0000403 SkPaint noAlphaPaint(skPaint);
404 noAlphaPaint.setAlpha(255);
405 shader->setContext(this->accessBitmap(false), noAlphaPaint, ctm);
reed@google.comac10a2d2010-12-22 21:39:39 +0000406
reed@google.comac10a2d2010-12-22 21:39:39 +0000407 SkBitmap bitmap;
408 SkMatrix matrix;
409 SkShader::TileMode tileModes[2];
410 SkScalar twoPointParams[3];
411 SkShader::BitmapType bmptype = shader->asABitmap(&bitmap, &matrix,
412 tileModes, twoPointParams);
413
bsalomon@google.com5782d712011-01-21 21:03:59 +0000414 GrSamplerState::SampleMode sampleMode = sk_bmp_type_to_sample_mode[bmptype];
415 if (-1 == sampleMode) {
416 SkDebugf("shader->asABitmap() == kNone_BitmapType\n");
417 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000418 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000419 grPaint->fSampler.setSampleMode(sampleMode);
bsalomon@google.com0748f212011-02-01 22:56:16 +0000420 grPaint->fSampler.setFilter(skPaint.isFilterBitmap());
bsalomon@google.com5782d712011-01-21 21:03:59 +0000421 grPaint->fSampler.setWrapX(sk_tile_mode_to_grwrap(tileModes[0]));
422 grPaint->fSampler.setWrapY(sk_tile_mode_to_grwrap(tileModes[1]));
reed@google.comac10a2d2010-12-22 21:39:39 +0000423 if (GrSamplerState::kRadial2_SampleMode == sampleMode) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000424 grPaint->fSampler.setRadial2Params(twoPointParams[0],
425 twoPointParams[1],
426 twoPointParams[2] < 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000427 }
428
bsalomon@google.com5782d712011-01-21 21:03:59 +0000429 GrTexture* texture = act->set(this, bitmap, grPaint->fSampler);
reed@google.comac10a2d2010-12-22 21:39:39 +0000430 if (NULL == texture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000431 SkDebugf("Couldn't convert bitmap to texture.\n");
432 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000433 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000434 grPaint->setTexture(texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000435
436 // since our texture coords will be in local space, we wack the texture
437 // matrix to map them back into 0...1 before we load it
438 SkMatrix localM;
439 if (shader->getLocalMatrix(&localM)) {
440 SkMatrix inverse;
441 if (localM.invert(&inverse)) {
442 matrix.preConcat(inverse);
443 }
444 }
445 if (SkShader::kDefault_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000446 GrScalar sx = GrFixedToScalar(GR_Fixed1 / bitmap.width());
447 GrScalar sy = GrFixedToScalar(GR_Fixed1 / bitmap.height());
reed@google.comac10a2d2010-12-22 21:39:39 +0000448 matrix.postScale(sx, sy);
reed@google.comac10a2d2010-12-22 21:39:39 +0000449 } else if (SkShader::kRadial_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000450 GrScalar s = GrFixedToScalar(GR_Fixed1 / bitmap.width());
reed@google.comac10a2d2010-12-22 21:39:39 +0000451 matrix.postScale(s, s);
452 }
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000453 GrMatrix grMat;
454 SkGr::SkMatrix2GrMatrix(matrix, &grMat);
455 grPaint->fSampler.setMatrix(grMat);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000456
457 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000458}
459
460///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com5782d712011-01-21 21:03:59 +0000461
462class SkPositionSource {
463public:
464 SkPositionSource(const SkPoint* points, int count)
465 : fPoints(points), fCount(count) {}
466
467 int count() const { return fCount; }
468
469 void writeValue(int i, GrPoint* dstPosition) const {
470 SkASSERT(i < fCount);
471 dstPosition->fX = SkScalarToGrScalar(fPoints[i].fX);
472 dstPosition->fY = SkScalarToGrScalar(fPoints[i].fY);
473 }
474private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000475 const SkPoint* fPoints;
bsalomon@google.com19628322011-02-03 21:30:17 +0000476 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000477};
478
479class SkTexCoordSource {
480public:
481 SkTexCoordSource(const SkPoint* coords)
482 : fCoords(coords) {}
483
484 void writeValue(int i, GrPoint* dstCoord) const {
485 dstCoord->fX = SkScalarToGrScalar(fCoords[i].fX);
486 dstCoord->fY = SkScalarToGrScalar(fCoords[i].fY);
487 }
488private:
489 const SkPoint* fCoords;
490};
491
492class SkColorSource {
493public:
494 SkColorSource(const SkColor* colors) : fColors(colors) {}
495
496 void writeValue(int i, GrColor* dstColor) const {
497 *dstColor = SkGr::SkColor2GrColor(fColors[i]);
498 }
499private:
500 const SkColor* fColors;
501};
502
503class SkIndexSource {
504public:
505 SkIndexSource(const uint16_t* indices, int count)
506 : fIndices(indices), fCount(count) {
507 }
508
509 int count() const { return fCount; }
510
511 void writeValue(int i, uint16_t* dstIndex) const {
512 *dstIndex = fIndices[i];
513 }
514
515private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000516 const uint16_t* fIndices;
bsalomon@google.com19628322011-02-03 21:30:17 +0000517 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000518};
519
520///////////////////////////////////////////////////////////////////////////////
521
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000522#if 0 // not currently being used so don't compile,
523
bsalomon@google.com5782d712011-01-21 21:03:59 +0000524// can be used for positions or texture coordinates
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000525
bsalomon@google.com5782d712011-01-21 21:03:59 +0000526class SkRectFanSource {
527public:
528 SkRectFanSource(const SkRect& rect) : fRect(rect) {}
529
530 int count() const { return 4; }
531
532 void writeValue(int i, GrPoint* dstPoint) const {
533 SkASSERT(i < 4);
534 dstPoint->fX = SkScalarToGrScalar((i % 3) ? fRect.fRight :
535 fRect.fLeft);
536 dstPoint->fY = SkScalarToGrScalar((i < 2) ? fRect.fTop :
537 fRect.fBottom);
538 }
539private:
540 const SkRect& fRect;
541};
542
543class SkIRectFanSource {
544public:
545 SkIRectFanSource(const SkIRect& rect) : fRect(rect) {}
546
547 int count() const { return 4; }
548
549 void writeValue(int i, GrPoint* dstPoint) const {
550 SkASSERT(i < 4);
551 dstPoint->fX = (i % 3) ? GrIntToScalar(fRect.fRight) :
552 GrIntToScalar(fRect.fLeft);
553 dstPoint->fY = (i < 2) ? GrIntToScalar(fRect.fTop) :
554 GrIntToScalar(fRect.fBottom);
555 }
556private:
557 const SkIRect& fRect;
558};
559
560class SkMatRectFanSource {
561public:
562 SkMatRectFanSource(const SkRect& rect, const SkMatrix& matrix)
563 : fRect(rect), fMatrix(matrix) {}
564
565 int count() const { return 4; }
566
567 void writeValue(int i, GrPoint* dstPoint) const {
568 SkASSERT(i < 4);
569
570#if SK_SCALAR_IS_GR_SCALAR
571 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
572 (i < 2) ? fRect.fTop : fRect.fBottom,
573 (SkPoint*)dstPoint);
574#else
575 SkPoint dst;
576 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
577 (i < 2) ? fRect.fTop : fRect.fBottom,
578 &dst);
579 dstPoint->fX = SkScalarToGrScalar(dst.fX);
580 dstPoint->fY = SkScalarToGrScalar(dst.fY);
581#endif
582 }
583private:
584 const SkRect& fRect;
585 const SkMatrix& fMatrix;
586};
587
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000588#endif
589
reed@google.comac10a2d2010-12-22 21:39:39 +0000590///////////////////////////////////////////////////////////////////////////////
591
592void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
593 CHECK_SHOULD_DRAW(draw);
594
bsalomon@google.com5782d712011-01-21 21:03:59 +0000595 GrPaint grPaint;
596 SkAutoCachedTexture act;
597 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000598 return;
599 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000600
601 fContext->drawPaint(grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000602}
603
604// must be in SkCanvas::PointMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +0000605static const GrPrimitiveType gPointMode2PrimtiveType[] = {
606 kPoints_PrimitiveType,
607 kLines_PrimitiveType,
608 kLineStrip_PrimitiveType
reed@google.comac10a2d2010-12-22 21:39:39 +0000609};
610
611void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000612 size_t count, const SkPoint pts[], const SkPaint& paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000613 CHECK_SHOULD_DRAW(draw);
614
615 SkScalar width = paint.getStrokeWidth();
616 if (width < 0) {
617 return;
618 }
619
620 // we only handle hairlines here, else we let the SkDraw call our drawPath()
621 if (width > 0) {
622 draw.drawPoints(mode, count, pts, paint, true);
623 return;
624 }
625
bsalomon@google.com5782d712011-01-21 21:03:59 +0000626 GrPaint grPaint;
627 SkAutoCachedTexture act;
628 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000629 return;
630 }
631
reed@google.comac10a2d2010-12-22 21:39:39 +0000632#if SK_SCALAR_IS_GR_SCALAR
bsalomon@google.com5782d712011-01-21 21:03:59 +0000633 fContext->drawVertices(grPaint,
634 gPointMode2PrimtiveType[mode],
635 count,
636 (GrPoint*)pts,
637 NULL,
638 NULL,
639 NULL,
640 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000641#else
bsalomon@google.com5782d712011-01-21 21:03:59 +0000642 fContext->drawCustomVertices(grPaint,
643 gPointMode2PrimtiveType[mode],
644 SkPositionSource(pts, count));
reed@google.comac10a2d2010-12-22 21:39:39 +0000645#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000646}
647
reed@google.comc9aa5872011-04-05 21:05:37 +0000648///////////////////////////////////////////////////////////////////////////////
649
650static void setInsetFan(GrPoint pts[4], const GrRect& r,
651 GrScalar dx, GrScalar dy) {
652 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy);
653}
654
655static GrColor getColorForMesh(const GrPaint& paint) {
656 if (NULL == paint.getTexture()) {
657 return paint.fColor;
658 } else {
659 unsigned a = GrColorUnpackA(paint.fColor);
660 return GrColorPackRGBA(a, a, a, a);
661 }
662}
663
664static const uint16_t gFillAARectIdx1[] = {
665 0, 1, 5, 5, 4, 0,
666 1, 2, 6, 6, 5, 1,
667 2, 3, 7, 7, 6, 2,
668 3, 0, 4, 4, 7, 3,
669 4, 5, 6, 6, 7, 4,
670};
671
672static void fillDevAARect(GrContext* ctx, const GrPaint& paint,
673 const GrRect& rect) {
674 if (rect.isEmpty()) {
675 return;
676 }
677
678 GrAutoMatrix avm(ctx, GrMatrix::I());
679
680 GrPoint verts[8];
681 GrPoint* texs = NULL;
682 GrColor colors[8];
683
684 setInsetFan(&verts[ 0], rect, -0.5f, -0.5f);
685 setInsetFan(&verts[ 4], rect, 0.5f, 0.5f);
686
687 sk_memset32(&colors[ 0], 0, 4);
688 sk_memset32(&colors[ 4], getColorForMesh(paint), 4);
689
690 ctx->drawVertices(paint, kTriangles_PrimitiveType,
691 8, verts, texs, colors,
692 gFillAARectIdx1, SK_ARRAY_COUNT(gFillAARectIdx1));
693}
694
695static const uint16_t gStrokeAARectIdx[] = {
696 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
697 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
698 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
699 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
700
701 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
702 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
703 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
704 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
705
706 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
707 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
708 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
709 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
710};
711
712static void strokeDevAARect(GrContext* ctx, const GrPaint& paint,
713 const GrRect& rect, const SkPoint& strokeSize) {
714 const GrScalar dx = SkScalarToGrScalar(strokeSize.fX);
715 const GrScalar dy = SkScalarToGrScalar(strokeSize.fY);
716 const GrScalar rx = dx * 0.5f;
717 const GrScalar ry = dy * 0.5f;
718
719 GrScalar spare;
720 {
721 GrScalar w = rect.width() - dx;
722 GrScalar h = rect.height() - dy;
723 spare = GrMin(w, h);
724 }
725
726 if (spare <= 0) {
727 GrRect r(rect);
728 r.inset(-rx, -ry);
729 fillDevAARect(ctx, paint, r);
730 return;
731 }
732
733 GrAutoMatrix avm(ctx, GrMatrix::I());
734
735 GrPoint verts[16];
736 GrPoint* texs = NULL;
737 GrColor colors[16];
738
739 setInsetFan(&verts[ 0], rect, -rx - 0.5f, -ry - 0.5f);
740 setInsetFan(&verts[ 4], rect, -rx + 0.5f, -ry + 0.5f);
741 setInsetFan(&verts[ 8], rect, rx - 0.5f, ry - 0.5f);
742 setInsetFan(&verts[12], rect, rx + 0.5f, ry + 0.5f);
743
744 sk_memset32(&colors[ 0], 0, 4);
745 sk_memset32(&colors[ 4], getColorForMesh(paint), 8);
746 sk_memset32(&colors[12], 0, 4);
747
748 ctx->drawVertices(paint, kTriangles_PrimitiveType,
749 16, verts, texs, colors,
750 gStrokeAARectIdx, SK_ARRAY_COUNT(gStrokeAARectIdx));
751}
752
reed@google.comac10a2d2010-12-22 21:39:39 +0000753void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
754 const SkPaint& paint) {
755 CHECK_SHOULD_DRAW(draw);
756
reed@google.com62ab7ad2011-04-05 14:08:25 +0000757 const SkMatrix& matrix = *draw.fMatrix;
758 SkPoint strokeSize;
759 SkDraw::RectType type = SkDraw::ComputeRectType(paint, matrix, &strokeSize);
reed@google.comac10a2d2010-12-22 21:39:39 +0000760
reed@google.com62ab7ad2011-04-05 14:08:25 +0000761 if (SkDraw::kPath_RectType == type) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000762 SkPath path;
763 path.addRect(rect);
764 this->drawPath(draw, path, paint, NULL, true);
reed@google.com62ab7ad2011-04-05 14:08:25 +0000765 } else {
766 GrPaint grPaint;
767 SkAutoCachedTexture act;
768 if (!this->skPaint2GrPaintShader(paint, &act, matrix, &grPaint)) {
769 return;
770 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000771
reed@google.comc9aa5872011-04-05 21:05:37 +0000772 bool doAA = paint.isAntiAlias();
reed@google.comf1f4a672011-04-06 13:46:04 +0000773 doAA = false;
reed@google.combf86c632011-04-06 13:42:34 +0000774
reed@google.comc9aa5872011-04-05 21:05:37 +0000775 if (SkDraw::kHair_RectType == type && doAA) {
776 strokeSize.set(SK_Scalar1, SK_Scalar1);
777 type = SkDraw::kStroke_RectType;
reed@google.com62ab7ad2011-04-05 14:08:25 +0000778 }
reed@google.comc9aa5872011-04-05 21:05:37 +0000779
780 switch (type) {
781 case SkDraw::kHair_RectType:
782 SkASSERT(!doAA);
783 fContext->drawRect(grPaint, Sk2Gr(rect), 0);
784 break;
785 case SkDraw::kFill_RectType:
786 if (doAA) {
787 SkRect devRect;
788 matrix.mapRect(&devRect, rect);
789 fillDevAARect(fContext, grPaint, Sk2Gr(devRect));
790 } else {
791 fContext->drawRect(grPaint, Sk2Gr(rect), -1);
792 }
793 break;
794 case SkDraw::kStroke_RectType:
795 if (doAA) {
796 SkRect devRect;
797 matrix.mapRect(&devRect, rect);
798 strokeDevAARect(fContext, grPaint, Sk2Gr(devRect), strokeSize);
799 } else {
800 fContext->drawRect(grPaint, Sk2Gr(rect), paint.getStrokeWidth());
801 }
802 break;
803 default:
804 SkASSERT(!"bad value for RectType");
805 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000806 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000807}
808
reed@google.com69302852011-02-16 18:08:07 +0000809#include "SkMaskFilter.h"
810#include "SkBounder.h"
811
reed@google.com69302852011-02-16 18:08:07 +0000812static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
813 SkMaskFilter* filter, const SkMatrix& matrix,
814 const SkRegion& clip, SkBounder* bounder,
815 GrPaint* grp) {
816 SkMask srcM, dstM;
817
818 if (!SkDraw::DrawToMask(path, &clip.getBounds(), filter, &matrix, &srcM,
819 SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
820 return false;
821 }
822
823 SkAutoMaskImage autoSrc(&srcM, false);
824
825 if (!filter->filterMask(&dstM, srcM, matrix, NULL)) {
826 return false;
827 }
828 // this will free-up dstM when we're done (allocated in filterMask())
829 SkAutoMaskImage autoDst(&dstM, false);
830
831 if (clip.quickReject(dstM.fBounds)) {
832 return false;
833 }
834 if (bounder && !bounder->doIRect(dstM.fBounds)) {
835 return false;
836 }
837
838 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
839 // the current clip (and identity matrix) and grpaint settings
840
reed@google.com0c219b62011-02-16 21:31:18 +0000841 GrAutoMatrix avm(context, GrMatrix::I());
reed@google.com69302852011-02-16 18:08:07 +0000842
843 const GrGpu::TextureDesc desc = {
844 0,
845 GrGpu::kNone_AALevel,
846 dstM.fBounds.width(),
847 dstM.fBounds.height(),
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000848 kAlpha_8_GrPixelConfig
reed@google.com69302852011-02-16 18:08:07 +0000849 };
850
851 GrTexture* texture = context->createUncachedTexture(desc, dstM.fImage,
852 dstM.fRowBytes);
853 if (NULL == texture) {
854 return false;
855 }
856
reed@google.com0c219b62011-02-16 21:31:18 +0000857 grp->setTexture(texture);
858 texture->unref();
859 grp->fSampler.setClampNoFilter();
reed@google.com69302852011-02-16 18:08:07 +0000860
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000861 GrRect d;
862 d.setLTRB(GrIntToScalar(dstM.fBounds.fLeft),
reed@google.com0c219b62011-02-16 21:31:18 +0000863 GrIntToScalar(dstM.fBounds.fTop),
864 GrIntToScalar(dstM.fBounds.fRight),
865 GrIntToScalar(dstM.fBounds.fBottom));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000866 GrRect s;
867 s.setLTRB(0, 0, GR_Scalar1, GR_Scalar1);
868 context->drawRectToRect(*grp, d, s);
reed@google.com69302852011-02-16 18:08:07 +0000869 return true;
870}
reed@google.com69302852011-02-16 18:08:07 +0000871
reed@google.com0c219b62011-02-16 21:31:18 +0000872void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
reed@google.comac10a2d2010-12-22 21:39:39 +0000873 const SkPaint& paint, const SkMatrix* prePathMatrix,
874 bool pathIsMutable) {
875 CHECK_SHOULD_DRAW(draw);
876
bsalomon@google.com5782d712011-01-21 21:03:59 +0000877 GrPaint grPaint;
878 SkAutoCachedTexture act;
879 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000880 return;
881 }
882
reed@google.com0c219b62011-02-16 21:31:18 +0000883 // BEGIN lift from SkDraw::drawPath()
884
885 SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
886 bool doFill = true;
887 SkPath tmpPath;
reed@google.comac10a2d2010-12-22 21:39:39 +0000888
889 if (prePathMatrix) {
reed@google.come3445642011-02-16 23:20:39 +0000890 SkPath* result = pathPtr;
reed@google.com0c219b62011-02-16 21:31:18 +0000891
reed@google.come3445642011-02-16 23:20:39 +0000892 if (!pathIsMutable) {
893 result = &tmpPath;
894 pathIsMutable = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000895 }
reed@google.come3445642011-02-16 23:20:39 +0000896 // should I push prePathMatrix on our MV stack temporarily, instead
897 // of applying it here? See SkDraw.cpp
898 pathPtr->transform(*prePathMatrix, result);
899 pathPtr = result;
reed@google.comac10a2d2010-12-22 21:39:39 +0000900 }
reed@google.com0c219b62011-02-16 21:31:18 +0000901 // at this point we're done with prePathMatrix
902 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
reed@google.comac10a2d2010-12-22 21:39:39 +0000903
bsalomon@google.com04de7822011-03-25 18:04:43 +0000904 // This "if" is not part of the SkDraw::drawPath() lift.
905 // When we get a 1.0 wide stroke we hairline stroke it instead of creating
906 // a new stroked-path. This is motivated by canvas2D sites that draw
907 // lines as 1.0 wide stroked paths. We can consider doing an alpha-modulated-
908 // hairline for width < 1.0 when AA is enabled.
909 static const int gMatrixMask = ~(SkMatrix::kIdentity_Mask |
910 SkMatrix::kTranslate_Mask);
911 if (!paint.getPathEffect() &&
912 SkPaint::kStroke_Style == paint.getStyle() &&
913 !(draw.fMatrix->getType() & gMatrixMask) &&
914 SK_Scalar1 == paint.getStrokeWidth()) {
915 doFill = false;
916 }
917
918 if (doFill && (paint.getPathEffect() ||
919 paint.getStyle() != SkPaint::kFill_Style)) {
reed@google.com0c219b62011-02-16 21:31:18 +0000920 doFill = paint.getFillPath(*pathPtr, &tmpPath);
921 pathPtr = &tmpPath;
922 }
923
924 // END lift from SkDraw::drawPath()
925
reed@google.com69302852011-02-16 18:08:07 +0000926 if (paint.getMaskFilter()) {
reed@google.com0c219b62011-02-16 21:31:18 +0000927 // avoid possibly allocating a new path in transform if we can
928 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
929
930 // transform the path into device space
reed@google.come3445642011-02-16 23:20:39 +0000931 pathPtr->transform(*draw.fMatrix, devPathPtr);
reed@google.com0c219b62011-02-16 21:31:18 +0000932
933 drawWithMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
reed@google.com69302852011-02-16 18:08:07 +0000934 *draw.fMatrix, *draw.fClip, draw.fBounder, &grPaint);
935 return;
936 }
reed@google.com69302852011-02-16 18:08:07 +0000937
bsalomon@google.comffca4002011-02-22 20:34:01 +0000938 GrPathFill fill = kHairLine_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000939
reed@google.com0c219b62011-02-16 21:31:18 +0000940 if (doFill) {
941 switch (pathPtr->getFillType()) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000942 case SkPath::kWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000943 fill = kWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000944 break;
945 case SkPath::kEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000946 fill = kEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000947 break;
948 case SkPath::kInverseWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000949 fill = kInverseWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000950 break;
951 case SkPath::kInverseEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000952 fill = kInverseEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000953 break;
954 default:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000955 SkDebugf("Unsupported path fill type\n");
reed@google.comac10a2d2010-12-22 21:39:39 +0000956 return;
957 }
958 }
959
reed@google.com0c219b62011-02-16 21:31:18 +0000960 SkGrPathIter iter(*pathPtr);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000961 fContext->drawPath(grPaint, &iter, fill);
reed@google.comac10a2d2010-12-22 21:39:39 +0000962}
963
reed@google.comac10a2d2010-12-22 21:39:39 +0000964void SkGpuDevice::drawBitmap(const SkDraw& draw,
965 const SkBitmap& bitmap,
966 const SkIRect* srcRectPtr,
967 const SkMatrix& m,
968 const SkPaint& paint) {
969 CHECK_SHOULD_DRAW(draw);
970
971 SkIRect srcRect;
972 if (NULL == srcRectPtr) {
973 srcRect.set(0, 0, bitmap.width(), bitmap.height());
974 } else {
975 srcRect = *srcRectPtr;
976 }
977
bsalomon@google.com5782d712011-01-21 21:03:59 +0000978 GrPaint grPaint;
979 if (!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
980 return;
981 }
982 grPaint.fSampler.setFilter(paint.isFilterBitmap());
983
reed@google.com02a7e6c2011-01-28 21:21:49 +0000984 const int maxTextureDim = fContext->getMaxTextureDimension();
985 if (bitmap.getTexture() || (bitmap.width() <= maxTextureDim &&
986 bitmap.height() <= maxTextureDim)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000987 // take the fast case
bsalomon@google.com5782d712011-01-21 21:03:59 +0000988 this->internalDrawBitmap(draw, bitmap, srcRect, m, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000989 return;
990 }
991
992 // undo the translate done by SkCanvas
993 int DX = SkMax32(0, srcRect.fLeft);
994 int DY = SkMax32(0, srcRect.fTop);
995 // compute clip bounds in local coordinates
996 SkIRect clipRect;
997 {
998 SkRect r;
999 r.set(draw.fClip->getBounds());
1000 SkMatrix matrix, inverse;
1001 matrix.setConcat(*draw.fMatrix, m);
1002 if (!matrix.invert(&inverse)) {
1003 return;
1004 }
1005 inverse.mapRect(&r);
1006 r.roundOut(&clipRect);
1007 // apply the canvas' translate to our local clip
1008 clipRect.offset(DX, DY);
1009 }
1010
reed@google.com02a7e6c2011-01-28 21:21:49 +00001011 int nx = bitmap.width() / maxTextureDim;
1012 int ny = bitmap.height() / maxTextureDim;
reed@google.comac10a2d2010-12-22 21:39:39 +00001013 for (int x = 0; x <= nx; x++) {
1014 for (int y = 0; y <= ny; y++) {
1015 SkIRect tileR;
reed@google.com02a7e6c2011-01-28 21:21:49 +00001016 tileR.set(x * maxTextureDim, y * maxTextureDim,
1017 (x + 1) * maxTextureDim, (y + 1) * maxTextureDim);
reed@google.comac10a2d2010-12-22 21:39:39 +00001018 if (!SkIRect::Intersects(tileR, clipRect)) {
1019 continue;
1020 }
1021
1022 SkIRect srcR = tileR;
1023 if (!srcR.intersect(srcRect)) {
1024 continue;
1025 }
1026
1027 SkBitmap tmpB;
1028 if (bitmap.extractSubset(&tmpB, tileR)) {
1029 // now offset it to make it "local" to our tmp bitmap
1030 srcR.offset(-tileR.fLeft, -tileR.fTop);
1031
1032 SkMatrix tmpM(m);
1033 {
1034 int dx = tileR.fLeft - DX + SkMax32(0, srcR.fLeft);
1035 int dy = tileR.fTop - DY + SkMax32(0, srcR.fTop);
1036 tmpM.preTranslate(SkIntToScalar(dx), SkIntToScalar(dy));
1037 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001038 this->internalDrawBitmap(draw, tmpB, srcR, tmpM, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +00001039 }
1040 }
1041 }
1042}
1043
1044/*
1045 * This is called by drawBitmap(), which has to handle images that may be too
1046 * large to be represented by a single texture.
1047 *
bsalomon@google.com5782d712011-01-21 21:03:59 +00001048 * internalDrawBitmap assumes that the specified bitmap will fit in a texture
1049 * and that non-texture portion of the GrPaint has already been setup.
reed@google.comac10a2d2010-12-22 21:39:39 +00001050 */
1051void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
1052 const SkBitmap& bitmap,
1053 const SkIRect& srcRect,
1054 const SkMatrix& m,
bsalomon@google.com5782d712011-01-21 21:03:59 +00001055 GrPaint* grPaint) {
reed@google.com02a7e6c2011-01-28 21:21:49 +00001056 SkASSERT(bitmap.width() <= fContext->getMaxTextureDimension() &&
1057 bitmap.height() <= fContext->getMaxTextureDimension());
reed@google.comac10a2d2010-12-22 21:39:39 +00001058
1059 SkAutoLockPixels alp(bitmap);
1060 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
1061 return;
1062 }
1063
bsalomon@google.com5782d712011-01-21 21:03:59 +00001064 grPaint->fSampler.setWrapX(GrSamplerState::kClamp_WrapMode);
1065 grPaint->fSampler.setWrapY(GrSamplerState::kClamp_WrapMode);
1066 grPaint->fSampler.setSampleMode(GrSamplerState::kNormal_SampleMode);
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001067 grPaint->fSampler.setMatrix(GrMatrix::I());
reed@google.comac10a2d2010-12-22 21:39:39 +00001068
1069 GrTexture* texture;
bsalomon@google.com5782d712011-01-21 21:03:59 +00001070 SkAutoCachedTexture act(this, bitmap, grPaint->fSampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +00001071 if (NULL == texture) {
1072 return;
1073 }
1074
bsalomon@google.com5782d712011-01-21 21:03:59 +00001075 grPaint->setTexture(texture);
reed@google.com46799cd2011-02-22 20:56:26 +00001076
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +00001077 GrRect dstRect(0, 0, GrIntToScalar(srcRect.width()), GrIntToScalar(srcRect.height()));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001078 GrRect paintRect;
1079 paintRect.setLTRB(GrFixedToScalar((srcRect.fLeft << 16) / bitmap.width()),
1080 GrFixedToScalar((srcRect.fTop << 16) / bitmap.height()),
1081 GrFixedToScalar((srcRect.fRight << 16) / bitmap.width()),
1082 GrFixedToScalar((srcRect.fBottom << 16) / bitmap.height()));
reed@google.comac10a2d2010-12-22 21:39:39 +00001083
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +00001084 GrMatrix grMat;
1085 SkGr::SkMatrix2GrMatrix(m, &grMat);
reed@google.comac10a2d2010-12-22 21:39:39 +00001086
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +00001087 fContext->drawRectToRect(*grPaint, dstRect, paintRect, &grMat);
reed@google.comac10a2d2010-12-22 21:39:39 +00001088}
1089
1090void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
1091 int left, int top, const SkPaint& paint) {
1092 CHECK_SHOULD_DRAW(draw);
1093
1094 SkAutoLockPixels alp(bitmap);
1095 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
1096 return;
1097 }
1098
bsalomon@google.com5782d712011-01-21 21:03:59 +00001099 GrPaint grPaint;
1100 if(!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
1101 return;
1102 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001103
bsalomon@google.com5782d712011-01-21 21:03:59 +00001104 GrAutoMatrix avm(fContext, GrMatrix::I());
1105
1106 GrTexture* texture;
1107 grPaint.fSampler.setClampNoFilter();
1108 SkAutoCachedTexture act(this, bitmap, grPaint.fSampler, &texture);
1109
bsalomon@google.com5782d712011-01-21 21:03:59 +00001110 grPaint.setTexture(texture);
1111
bsalomon@google.com5782d712011-01-21 21:03:59 +00001112 fContext->drawRectToRect(grPaint,
1113 GrRect(GrIntToScalar(left), GrIntToScalar(top),
1114 GrIntToScalar(left + bitmap.width()),
1115 GrIntToScalar(top + bitmap.height())),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001116 GrRect(0, 0, GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001117}
1118
1119void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
1120 int x, int y, const SkPaint& paint) {
1121 CHECK_SHOULD_DRAW(draw);
1122
bsalomon@google.com5782d712011-01-21 21:03:59 +00001123 GrPaint grPaint;
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001124 if (!((SkGpuDevice*)dev)->bindDeviceAsTexture(&grPaint) ||
bsalomon@google.com5782d712011-01-21 21:03:59 +00001125 !this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
1126 return;
reed@google.comac10a2d2010-12-22 21:39:39 +00001127 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001128
1129 SkASSERT(NULL != grPaint.getTexture());
1130
1131 const SkBitmap& bm = dev->accessBitmap(false);
1132 int w = bm.width();
1133 int h = bm.height();
1134
1135 GrAutoMatrix avm(fContext, GrMatrix::I());
1136
1137 grPaint.fSampler.setClampNoFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +00001138
1139 fContext->drawRectToRect(grPaint,
reed@google.com1a2e8d22011-01-21 22:08:29 +00001140 GrRect(GrIntToScalar(x),
1141 GrIntToScalar(y),
1142 GrIntToScalar(x + w),
bsalomon@google.com5782d712011-01-21 21:03:59 +00001143 GrIntToScalar(y + h)),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001144 GrRect(0, 0, GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001145}
1146
1147///////////////////////////////////////////////////////////////////////////////
1148
1149// must be in SkCanvas::VertexMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +00001150static const GrPrimitiveType gVertexMode2PrimitiveType[] = {
1151 kTriangles_PrimitiveType,
1152 kTriangleStrip_PrimitiveType,
1153 kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +00001154};
1155
1156void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
1157 int vertexCount, const SkPoint vertices[],
1158 const SkPoint texs[], const SkColor colors[],
1159 SkXfermode* xmode,
1160 const uint16_t indices[], int indexCount,
1161 const SkPaint& paint) {
1162 CHECK_SHOULD_DRAW(draw);
1163
bsalomon@google.com5782d712011-01-21 21:03:59 +00001164 GrPaint grPaint;
1165 SkAutoCachedTexture act;
1166 // we ignore the shader if texs is null.
1167 if (NULL == texs) {
1168 if (!this->skPaint2GrPaintNoShader(paint, false, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001169 return;
1170 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001171 } else {
reed@google.com1a2e8d22011-01-21 22:08:29 +00001172 if (!this->skPaint2GrPaintShader(paint, &act,
1173 *draw.fMatrix,
bsalomon@google.com5782d712011-01-21 21:03:59 +00001174 &grPaint)) {
1175 return;
1176 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001177 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001178
1179 if (NULL != xmode && NULL != texs && NULL != colors) {
1180 SkXfermode::Mode mode;
1181 if (!SkXfermode::IsMode(xmode, &mode) ||
1182 SkXfermode::kMultiply_Mode != mode) {
1183 SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
1184#if 0
1185 return
1186#endif
1187 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001188 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001189
1190#if SK_SCALAR_IS_GR_SCALAR
1191 // even if GrColor and SkColor byte offsets match we need
1192 // to perform pre-multiply.
1193 if (NULL == colors) {
1194 fContext->drawVertices(grPaint,
1195 gVertexMode2PrimitiveType[vmode],
1196 vertexCount,
1197 (GrPoint*) vertices,
1198 (GrPoint*) texs,
1199 NULL,
1200 indices,
1201 indexCount);
1202 } else
1203#endif
1204 {
1205 SkTexCoordSource texSrc(texs);
1206 SkColorSource colSrc(colors);
1207 SkIndexSource idxSrc(indices, indexCount);
1208
1209 fContext->drawCustomVertices(grPaint,
1210 gVertexMode2PrimitiveType[vmode],
1211 SkPositionSource(vertices, vertexCount),
1212 (NULL == texs) ? NULL : &texSrc,
1213 (NULL == colors) ? NULL : &colSrc,
1214 (NULL == indices) ? NULL : &idxSrc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001215 }
1216}
1217
1218///////////////////////////////////////////////////////////////////////////////
1219
1220static void GlyphCacheAuxProc(void* data) {
1221 delete (GrFontScaler*)data;
1222}
1223
1224static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) {
1225 void* auxData;
1226 GrFontScaler* scaler = NULL;
1227 if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
1228 scaler = (GrFontScaler*)auxData;
1229 }
1230 if (NULL == scaler) {
1231 scaler = new SkGrFontScaler(cache);
1232 cache->setAuxProc(GlyphCacheAuxProc, scaler);
1233 }
1234 return scaler;
1235}
1236
1237static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
1238 SkFixed fx, SkFixed fy,
1239 const SkGlyph& glyph) {
1240 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1241
1242 GrSkDrawProcs* procs = (GrSkDrawProcs*)state.fDraw->fProcs;
1243
1244 if (NULL == procs->fFontScaler) {
1245 procs->fFontScaler = get_gr_font_scaler(state.fCache);
1246 }
1247 procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0),
1248 SkIntToFixed(SkFixedFloor(fx)), fy,
1249 procs->fFontScaler);
1250}
1251
bsalomon@google.com5782d712011-01-21 21:03:59 +00001252SkDrawProcs* SkGpuDevice::initDrawForText(GrTextContext* context) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001253
1254 // deferred allocation
1255 if (NULL == fDrawProcs) {
1256 fDrawProcs = new GrSkDrawProcs;
1257 fDrawProcs->fD1GProc = SkGPU_Draw1Glyph;
1258 fDrawProcs->fContext = fContext;
1259 }
1260
1261 // init our (and GL's) state
1262 fDrawProcs->fTextContext = context;
1263 fDrawProcs->fFontScaler = NULL;
1264 return fDrawProcs;
1265}
1266
1267void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
1268 size_t byteLength, SkScalar x, SkScalar y,
1269 const SkPaint& paint) {
1270 CHECK_SHOULD_DRAW(draw);
1271
1272 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1273 // this guy will just call our drawPath()
1274 draw.drawText((const char*)text, byteLength, x, y, paint);
1275 } else {
1276 SkAutoExtMatrix aem(draw.fExtMatrix);
1277 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001278
1279 GrPaint grPaint;
1280 SkAutoCachedTexture act;
1281
1282 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1283 return;
1284 }
1285 GrTextContext context(fContext, grPaint, aem.extMatrix());
1286 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001287 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
1288 }
1289}
1290
1291void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
1292 size_t byteLength, const SkScalar pos[],
1293 SkScalar constY, int scalarsPerPos,
1294 const SkPaint& paint) {
1295 CHECK_SHOULD_DRAW(draw);
1296
1297 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1298 // this guy will just call our drawPath()
1299 draw.drawPosText((const char*)text, byteLength, pos, constY,
1300 scalarsPerPos, paint);
1301 } else {
1302 SkAutoExtMatrix aem(draw.fExtMatrix);
1303 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001304
1305 GrPaint grPaint;
1306 SkAutoCachedTexture act;
1307 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1308 return;
1309 }
1310
1311 GrTextContext context(fContext, grPaint, aem.extMatrix());
1312 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001313 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
1314 scalarsPerPos, paint);
1315 }
1316}
1317
1318void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
1319 size_t len, const SkPath& path,
1320 const SkMatrix* m, const SkPaint& paint) {
1321 CHECK_SHOULD_DRAW(draw);
1322
1323 SkASSERT(draw.fDevice == this);
1324 draw.drawTextOnPath((const char*)text, len, path, m, paint);
1325}
1326
1327///////////////////////////////////////////////////////////////////////////////
1328
reed@google.comf67e4cf2011-03-15 20:56:58 +00001329bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
1330 if (!paint.isLCDRenderText()) {
1331 // we're cool with the paint as is
1332 return false;
1333 }
1334
1335 if (paint.getShader() ||
1336 paint.getXfermode() || // unless its srcover
1337 paint.getMaskFilter() ||
1338 paint.getRasterizer() ||
1339 paint.getColorFilter() ||
1340 paint.getPathEffect() ||
1341 paint.isFakeBoldText() ||
1342 paint.getStyle() != SkPaint::kFill_Style) {
1343 // turn off lcd
1344 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
1345 flags->fHinting = paint.getHinting();
1346 return true;
1347 }
1348 // we're cool with the paint as is
1349 return false;
1350}
1351
1352///////////////////////////////////////////////////////////////////////////////
1353
reed@google.comac10a2d2010-12-22 21:39:39 +00001354SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
1355 const GrSamplerState& sampler,
1356 GrTexture** texture,
1357 bool forDeviceRenderTarget) {
1358 GrContext* ctx = this->context();
1359 uint32_t p0, p1;
1360 if (forDeviceRenderTarget) {
1361 p0 = p1 = -1;
1362 } else {
1363 p0 = bitmap.getGenerationID();
1364 p1 = bitmap.pixelRefOffset();
1365 }
1366
1367 GrTexture* newTexture = NULL;
1368 GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
1369 GrTextureEntry* entry = ctx->findAndLockTexture(&key, sampler);
1370
1371 if (NULL == entry) {
1372
1373 if (forDeviceRenderTarget) {
1374 const GrGpu::TextureDesc desc = {
1375 GrGpu::kRenderTarget_TextureFlag,
1376 GrGpu::kNone_AALevel,
1377 bitmap.width(),
1378 bitmap.height(),
1379 SkGr::Bitmap2PixelConfig(bitmap)
1380 };
1381 entry = ctx->createAndLockTexture(&key, sampler, desc, NULL, 0);
1382
1383 } else {
1384 entry = sk_gr_create_bitmap_texture(ctx, &key, sampler, bitmap);
1385 }
1386 if (NULL == entry) {
1387 GrPrintf("---- failed to create texture for cache [%d %d]\n",
1388 bitmap.width(), bitmap.height());
1389 }
1390 }
1391
1392 if (NULL != entry) {
1393 newTexture = entry->texture();
reed@google.comac10a2d2010-12-22 21:39:39 +00001394 if (texture) {
1395 *texture = newTexture;
1396 }
1397 // IMPORTANT: We can't allow another SkGpuDevice to get this
1398 // cache entry until this one is destroyed!
1399 if (forDeviceRenderTarget) {
1400 ctx->detachCachedTexture(entry);
1401 }
1402 }
1403 return (TexCache*)entry;
1404}
1405
1406void SkGpuDevice::unlockCachedTexture(TexCache* cache) {
1407 this->context()->unlockTexture((GrTextureEntry*)cache);
1408}
1409
reed@google.com7b201d22011-01-11 18:59:23 +00001410///////////////////////////////////////////////////////////////////////////////
1411
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001412SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context,
1413 GrRenderTarget* rootRenderTarget)
1414 : fContext(context) {
1415
1416 GrAssert(NULL != context);
1417 GrAssert(NULL != rootRenderTarget);
1418
1419 // check this now rather than passing this value to SkGpuDevice cons.
1420 // we want the rt that is bound *now* in the 3D API, not the one
1421 // at the time of newDevice.
1422 if (SkGpuDevice::Current3DApiRenderTarget() == rootRenderTarget) {
1423 fRootRenderTarget = context->createRenderTargetFrom3DApiState();
1424 } else {
1425 fRootRenderTarget = rootRenderTarget;
1426 rootRenderTarget->ref();
1427 }
reed@google.com7b201d22011-01-11 18:59:23 +00001428 context->ref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001429
reed@google.com7b201d22011-01-11 18:59:23 +00001430}
1431
1432SkGpuDeviceFactory::~SkGpuDeviceFactory() {
1433 fContext->unref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001434 fRootRenderTarget->unref();
reed@google.com7b201d22011-01-11 18:59:23 +00001435}
1436
1437SkDevice* SkGpuDeviceFactory::newDevice(SkCanvas*, SkBitmap::Config config,
1438 int width, int height,
1439 bool isOpaque, bool isLayer) {
1440 SkBitmap bm;
1441 bm.setConfig(config, width, height);
1442 bm.setIsOpaque(isOpaque);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001443 return new SkGpuDevice(fContext, bm, isLayer ? NULL : fRootRenderTarget);
reed@google.com7b201d22011-01-11 18:59:23 +00001444}
reed@google.comac10a2d2010-12-22 21:39:39 +00001445