blob: 7be1db596c6c6b4923ae30d9065fae6f68dc8de9 [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();
773 // disable for now
774 doAA = false;
775
776 if (SkDraw::kHair_RectType == type && doAA) {
777 strokeSize.set(SK_Scalar1, SK_Scalar1);
778 type = SkDraw::kStroke_RectType;
reed@google.com62ab7ad2011-04-05 14:08:25 +0000779 }
reed@google.comc9aa5872011-04-05 21:05:37 +0000780
781 switch (type) {
782 case SkDraw::kHair_RectType:
783 SkASSERT(!doAA);
784 fContext->drawRect(grPaint, Sk2Gr(rect), 0);
785 break;
786 case SkDraw::kFill_RectType:
787 if (doAA) {
788 SkRect devRect;
789 matrix.mapRect(&devRect, rect);
790 fillDevAARect(fContext, grPaint, Sk2Gr(devRect));
791 } else {
792 fContext->drawRect(grPaint, Sk2Gr(rect), -1);
793 }
794 break;
795 case SkDraw::kStroke_RectType:
796 if (doAA) {
797 SkRect devRect;
798 matrix.mapRect(&devRect, rect);
799 strokeDevAARect(fContext, grPaint, Sk2Gr(devRect), strokeSize);
800 } else {
801 fContext->drawRect(grPaint, Sk2Gr(rect), paint.getStrokeWidth());
802 }
803 break;
804 default:
805 SkASSERT(!"bad value for RectType");
806 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000807 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000808}
809
reed@google.com69302852011-02-16 18:08:07 +0000810#include "SkMaskFilter.h"
811#include "SkBounder.h"
812
reed@google.com69302852011-02-16 18:08:07 +0000813static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
814 SkMaskFilter* filter, const SkMatrix& matrix,
815 const SkRegion& clip, SkBounder* bounder,
816 GrPaint* grp) {
817 SkMask srcM, dstM;
818
819 if (!SkDraw::DrawToMask(path, &clip.getBounds(), filter, &matrix, &srcM,
820 SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
821 return false;
822 }
823
824 SkAutoMaskImage autoSrc(&srcM, false);
825
826 if (!filter->filterMask(&dstM, srcM, matrix, NULL)) {
827 return false;
828 }
829 // this will free-up dstM when we're done (allocated in filterMask())
830 SkAutoMaskImage autoDst(&dstM, false);
831
832 if (clip.quickReject(dstM.fBounds)) {
833 return false;
834 }
835 if (bounder && !bounder->doIRect(dstM.fBounds)) {
836 return false;
837 }
838
839 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
840 // the current clip (and identity matrix) and grpaint settings
841
reed@google.com0c219b62011-02-16 21:31:18 +0000842 GrAutoMatrix avm(context, GrMatrix::I());
reed@google.com69302852011-02-16 18:08:07 +0000843
844 const GrGpu::TextureDesc desc = {
845 0,
846 GrGpu::kNone_AALevel,
847 dstM.fBounds.width(),
848 dstM.fBounds.height(),
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000849 kAlpha_8_GrPixelConfig
reed@google.com69302852011-02-16 18:08:07 +0000850 };
851
852 GrTexture* texture = context->createUncachedTexture(desc, dstM.fImage,
853 dstM.fRowBytes);
854 if (NULL == texture) {
855 return false;
856 }
857
reed@google.com0c219b62011-02-16 21:31:18 +0000858 grp->setTexture(texture);
859 texture->unref();
860 grp->fSampler.setClampNoFilter();
reed@google.com69302852011-02-16 18:08:07 +0000861
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000862 GrRect d;
863 d.setLTRB(GrIntToScalar(dstM.fBounds.fLeft),
reed@google.com0c219b62011-02-16 21:31:18 +0000864 GrIntToScalar(dstM.fBounds.fTop),
865 GrIntToScalar(dstM.fBounds.fRight),
866 GrIntToScalar(dstM.fBounds.fBottom));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000867 GrRect s;
868 s.setLTRB(0, 0, GR_Scalar1, GR_Scalar1);
869 context->drawRectToRect(*grp, d, s);
reed@google.com69302852011-02-16 18:08:07 +0000870 return true;
871}
reed@google.com69302852011-02-16 18:08:07 +0000872
reed@google.com0c219b62011-02-16 21:31:18 +0000873void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
reed@google.comac10a2d2010-12-22 21:39:39 +0000874 const SkPaint& paint, const SkMatrix* prePathMatrix,
875 bool pathIsMutable) {
876 CHECK_SHOULD_DRAW(draw);
877
bsalomon@google.com5782d712011-01-21 21:03:59 +0000878 GrPaint grPaint;
879 SkAutoCachedTexture act;
880 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000881 return;
882 }
883
reed@google.com0c219b62011-02-16 21:31:18 +0000884 // BEGIN lift from SkDraw::drawPath()
885
886 SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
887 bool doFill = true;
888 SkPath tmpPath;
reed@google.comac10a2d2010-12-22 21:39:39 +0000889
890 if (prePathMatrix) {
reed@google.come3445642011-02-16 23:20:39 +0000891 SkPath* result = pathPtr;
reed@google.com0c219b62011-02-16 21:31:18 +0000892
reed@google.come3445642011-02-16 23:20:39 +0000893 if (!pathIsMutable) {
894 result = &tmpPath;
895 pathIsMutable = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000896 }
reed@google.come3445642011-02-16 23:20:39 +0000897 // should I push prePathMatrix on our MV stack temporarily, instead
898 // of applying it here? See SkDraw.cpp
899 pathPtr->transform(*prePathMatrix, result);
900 pathPtr = result;
reed@google.comac10a2d2010-12-22 21:39:39 +0000901 }
reed@google.com0c219b62011-02-16 21:31:18 +0000902 // at this point we're done with prePathMatrix
903 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
reed@google.comac10a2d2010-12-22 21:39:39 +0000904
bsalomon@google.com04de7822011-03-25 18:04:43 +0000905 // This "if" is not part of the SkDraw::drawPath() lift.
906 // When we get a 1.0 wide stroke we hairline stroke it instead of creating
907 // a new stroked-path. This is motivated by canvas2D sites that draw
908 // lines as 1.0 wide stroked paths. We can consider doing an alpha-modulated-
909 // hairline for width < 1.0 when AA is enabled.
910 static const int gMatrixMask = ~(SkMatrix::kIdentity_Mask |
911 SkMatrix::kTranslate_Mask);
912 if (!paint.getPathEffect() &&
913 SkPaint::kStroke_Style == paint.getStyle() &&
914 !(draw.fMatrix->getType() & gMatrixMask) &&
915 SK_Scalar1 == paint.getStrokeWidth()) {
916 doFill = false;
917 }
918
919 if (doFill && (paint.getPathEffect() ||
920 paint.getStyle() != SkPaint::kFill_Style)) {
reed@google.com0c219b62011-02-16 21:31:18 +0000921 doFill = paint.getFillPath(*pathPtr, &tmpPath);
922 pathPtr = &tmpPath;
923 }
924
925 // END lift from SkDraw::drawPath()
926
reed@google.com69302852011-02-16 18:08:07 +0000927 if (paint.getMaskFilter()) {
reed@google.com0c219b62011-02-16 21:31:18 +0000928 // avoid possibly allocating a new path in transform if we can
929 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
930
931 // transform the path into device space
reed@google.come3445642011-02-16 23:20:39 +0000932 pathPtr->transform(*draw.fMatrix, devPathPtr);
reed@google.com0c219b62011-02-16 21:31:18 +0000933
934 drawWithMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
reed@google.com69302852011-02-16 18:08:07 +0000935 *draw.fMatrix, *draw.fClip, draw.fBounder, &grPaint);
936 return;
937 }
reed@google.com69302852011-02-16 18:08:07 +0000938
bsalomon@google.comffca4002011-02-22 20:34:01 +0000939 GrPathFill fill = kHairLine_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000940
reed@google.com0c219b62011-02-16 21:31:18 +0000941 if (doFill) {
942 switch (pathPtr->getFillType()) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000943 case SkPath::kWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000944 fill = kWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000945 break;
946 case SkPath::kEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000947 fill = kEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000948 break;
949 case SkPath::kInverseWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000950 fill = kInverseWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000951 break;
952 case SkPath::kInverseEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000953 fill = kInverseEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000954 break;
955 default:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000956 SkDebugf("Unsupported path fill type\n");
reed@google.comac10a2d2010-12-22 21:39:39 +0000957 return;
958 }
959 }
960
reed@google.com0c219b62011-02-16 21:31:18 +0000961 SkGrPathIter iter(*pathPtr);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000962 fContext->drawPath(grPaint, &iter, fill);
reed@google.comac10a2d2010-12-22 21:39:39 +0000963}
964
reed@google.comac10a2d2010-12-22 21:39:39 +0000965void SkGpuDevice::drawBitmap(const SkDraw& draw,
966 const SkBitmap& bitmap,
967 const SkIRect* srcRectPtr,
968 const SkMatrix& m,
969 const SkPaint& paint) {
970 CHECK_SHOULD_DRAW(draw);
971
972 SkIRect srcRect;
973 if (NULL == srcRectPtr) {
974 srcRect.set(0, 0, bitmap.width(), bitmap.height());
975 } else {
976 srcRect = *srcRectPtr;
977 }
978
bsalomon@google.com5782d712011-01-21 21:03:59 +0000979 GrPaint grPaint;
980 if (!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
981 return;
982 }
983 grPaint.fSampler.setFilter(paint.isFilterBitmap());
984
reed@google.com02a7e6c2011-01-28 21:21:49 +0000985 const int maxTextureDim = fContext->getMaxTextureDimension();
986 if (bitmap.getTexture() || (bitmap.width() <= maxTextureDim &&
987 bitmap.height() <= maxTextureDim)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000988 // take the fast case
bsalomon@google.com5782d712011-01-21 21:03:59 +0000989 this->internalDrawBitmap(draw, bitmap, srcRect, m, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000990 return;
991 }
992
993 // undo the translate done by SkCanvas
994 int DX = SkMax32(0, srcRect.fLeft);
995 int DY = SkMax32(0, srcRect.fTop);
996 // compute clip bounds in local coordinates
997 SkIRect clipRect;
998 {
999 SkRect r;
1000 r.set(draw.fClip->getBounds());
1001 SkMatrix matrix, inverse;
1002 matrix.setConcat(*draw.fMatrix, m);
1003 if (!matrix.invert(&inverse)) {
1004 return;
1005 }
1006 inverse.mapRect(&r);
1007 r.roundOut(&clipRect);
1008 // apply the canvas' translate to our local clip
1009 clipRect.offset(DX, DY);
1010 }
1011
reed@google.com02a7e6c2011-01-28 21:21:49 +00001012 int nx = bitmap.width() / maxTextureDim;
1013 int ny = bitmap.height() / maxTextureDim;
reed@google.comac10a2d2010-12-22 21:39:39 +00001014 for (int x = 0; x <= nx; x++) {
1015 for (int y = 0; y <= ny; y++) {
1016 SkIRect tileR;
reed@google.com02a7e6c2011-01-28 21:21:49 +00001017 tileR.set(x * maxTextureDim, y * maxTextureDim,
1018 (x + 1) * maxTextureDim, (y + 1) * maxTextureDim);
reed@google.comac10a2d2010-12-22 21:39:39 +00001019 if (!SkIRect::Intersects(tileR, clipRect)) {
1020 continue;
1021 }
1022
1023 SkIRect srcR = tileR;
1024 if (!srcR.intersect(srcRect)) {
1025 continue;
1026 }
1027
1028 SkBitmap tmpB;
1029 if (bitmap.extractSubset(&tmpB, tileR)) {
1030 // now offset it to make it "local" to our tmp bitmap
1031 srcR.offset(-tileR.fLeft, -tileR.fTop);
1032
1033 SkMatrix tmpM(m);
1034 {
1035 int dx = tileR.fLeft - DX + SkMax32(0, srcR.fLeft);
1036 int dy = tileR.fTop - DY + SkMax32(0, srcR.fTop);
1037 tmpM.preTranslate(SkIntToScalar(dx), SkIntToScalar(dy));
1038 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001039 this->internalDrawBitmap(draw, tmpB, srcR, tmpM, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +00001040 }
1041 }
1042 }
1043}
1044
1045/*
1046 * This is called by drawBitmap(), which has to handle images that may be too
1047 * large to be represented by a single texture.
1048 *
bsalomon@google.com5782d712011-01-21 21:03:59 +00001049 * internalDrawBitmap assumes that the specified bitmap will fit in a texture
1050 * and that non-texture portion of the GrPaint has already been setup.
reed@google.comac10a2d2010-12-22 21:39:39 +00001051 */
1052void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
1053 const SkBitmap& bitmap,
1054 const SkIRect& srcRect,
1055 const SkMatrix& m,
bsalomon@google.com5782d712011-01-21 21:03:59 +00001056 GrPaint* grPaint) {
reed@google.com02a7e6c2011-01-28 21:21:49 +00001057 SkASSERT(bitmap.width() <= fContext->getMaxTextureDimension() &&
1058 bitmap.height() <= fContext->getMaxTextureDimension());
reed@google.comac10a2d2010-12-22 21:39:39 +00001059
1060 SkAutoLockPixels alp(bitmap);
1061 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
1062 return;
1063 }
1064
bsalomon@google.com5782d712011-01-21 21:03:59 +00001065 grPaint->fSampler.setWrapX(GrSamplerState::kClamp_WrapMode);
1066 grPaint->fSampler.setWrapY(GrSamplerState::kClamp_WrapMode);
1067 grPaint->fSampler.setSampleMode(GrSamplerState::kNormal_SampleMode);
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001068 grPaint->fSampler.setMatrix(GrMatrix::I());
reed@google.comac10a2d2010-12-22 21:39:39 +00001069
1070 GrTexture* texture;
bsalomon@google.com5782d712011-01-21 21:03:59 +00001071 SkAutoCachedTexture act(this, bitmap, grPaint->fSampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +00001072 if (NULL == texture) {
1073 return;
1074 }
1075
bsalomon@google.com5782d712011-01-21 21:03:59 +00001076 grPaint->setTexture(texture);
reed@google.com46799cd2011-02-22 20:56:26 +00001077
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +00001078 GrRect dstRect(0, 0, GrIntToScalar(srcRect.width()), GrIntToScalar(srcRect.height()));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001079 GrRect paintRect;
1080 paintRect.setLTRB(GrFixedToScalar((srcRect.fLeft << 16) / bitmap.width()),
1081 GrFixedToScalar((srcRect.fTop << 16) / bitmap.height()),
1082 GrFixedToScalar((srcRect.fRight << 16) / bitmap.width()),
1083 GrFixedToScalar((srcRect.fBottom << 16) / bitmap.height()));
reed@google.comac10a2d2010-12-22 21:39:39 +00001084
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +00001085 GrMatrix grMat;
1086 SkGr::SkMatrix2GrMatrix(m, &grMat);
reed@google.comac10a2d2010-12-22 21:39:39 +00001087
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +00001088 fContext->drawRectToRect(*grPaint, dstRect, paintRect, &grMat);
reed@google.comac10a2d2010-12-22 21:39:39 +00001089}
1090
1091void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
1092 int left, int top, const SkPaint& paint) {
1093 CHECK_SHOULD_DRAW(draw);
1094
1095 SkAutoLockPixels alp(bitmap);
1096 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
1097 return;
1098 }
1099
bsalomon@google.com5782d712011-01-21 21:03:59 +00001100 GrPaint grPaint;
1101 if(!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
1102 return;
1103 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001104
bsalomon@google.com5782d712011-01-21 21:03:59 +00001105 GrAutoMatrix avm(fContext, GrMatrix::I());
1106
1107 GrTexture* texture;
1108 grPaint.fSampler.setClampNoFilter();
1109 SkAutoCachedTexture act(this, bitmap, grPaint.fSampler, &texture);
1110
bsalomon@google.com5782d712011-01-21 21:03:59 +00001111 grPaint.setTexture(texture);
1112
bsalomon@google.com5782d712011-01-21 21:03:59 +00001113 fContext->drawRectToRect(grPaint,
1114 GrRect(GrIntToScalar(left), GrIntToScalar(top),
1115 GrIntToScalar(left + bitmap.width()),
1116 GrIntToScalar(top + bitmap.height())),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001117 GrRect(0, 0, GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001118}
1119
1120void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
1121 int x, int y, const SkPaint& paint) {
1122 CHECK_SHOULD_DRAW(draw);
1123
bsalomon@google.com5782d712011-01-21 21:03:59 +00001124 GrPaint grPaint;
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001125 if (!((SkGpuDevice*)dev)->bindDeviceAsTexture(&grPaint) ||
bsalomon@google.com5782d712011-01-21 21:03:59 +00001126 !this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
1127 return;
reed@google.comac10a2d2010-12-22 21:39:39 +00001128 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001129
1130 SkASSERT(NULL != grPaint.getTexture());
1131
1132 const SkBitmap& bm = dev->accessBitmap(false);
1133 int w = bm.width();
1134 int h = bm.height();
1135
1136 GrAutoMatrix avm(fContext, GrMatrix::I());
1137
1138 grPaint.fSampler.setClampNoFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +00001139
1140 fContext->drawRectToRect(grPaint,
reed@google.com1a2e8d22011-01-21 22:08:29 +00001141 GrRect(GrIntToScalar(x),
1142 GrIntToScalar(y),
1143 GrIntToScalar(x + w),
bsalomon@google.com5782d712011-01-21 21:03:59 +00001144 GrIntToScalar(y + h)),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001145 GrRect(0, 0, GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001146}
1147
1148///////////////////////////////////////////////////////////////////////////////
1149
1150// must be in SkCanvas::VertexMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +00001151static const GrPrimitiveType gVertexMode2PrimitiveType[] = {
1152 kTriangles_PrimitiveType,
1153 kTriangleStrip_PrimitiveType,
1154 kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +00001155};
1156
1157void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
1158 int vertexCount, const SkPoint vertices[],
1159 const SkPoint texs[], const SkColor colors[],
1160 SkXfermode* xmode,
1161 const uint16_t indices[], int indexCount,
1162 const SkPaint& paint) {
1163 CHECK_SHOULD_DRAW(draw);
1164
bsalomon@google.com5782d712011-01-21 21:03:59 +00001165 GrPaint grPaint;
1166 SkAutoCachedTexture act;
1167 // we ignore the shader if texs is null.
1168 if (NULL == texs) {
1169 if (!this->skPaint2GrPaintNoShader(paint, false, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001170 return;
1171 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001172 } else {
reed@google.com1a2e8d22011-01-21 22:08:29 +00001173 if (!this->skPaint2GrPaintShader(paint, &act,
1174 *draw.fMatrix,
bsalomon@google.com5782d712011-01-21 21:03:59 +00001175 &grPaint)) {
1176 return;
1177 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001178 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001179
1180 if (NULL != xmode && NULL != texs && NULL != colors) {
1181 SkXfermode::Mode mode;
1182 if (!SkXfermode::IsMode(xmode, &mode) ||
1183 SkXfermode::kMultiply_Mode != mode) {
1184 SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
1185#if 0
1186 return
1187#endif
1188 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001189 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001190
1191#if SK_SCALAR_IS_GR_SCALAR
1192 // even if GrColor and SkColor byte offsets match we need
1193 // to perform pre-multiply.
1194 if (NULL == colors) {
1195 fContext->drawVertices(grPaint,
1196 gVertexMode2PrimitiveType[vmode],
1197 vertexCount,
1198 (GrPoint*) vertices,
1199 (GrPoint*) texs,
1200 NULL,
1201 indices,
1202 indexCount);
1203 } else
1204#endif
1205 {
1206 SkTexCoordSource texSrc(texs);
1207 SkColorSource colSrc(colors);
1208 SkIndexSource idxSrc(indices, indexCount);
1209
1210 fContext->drawCustomVertices(grPaint,
1211 gVertexMode2PrimitiveType[vmode],
1212 SkPositionSource(vertices, vertexCount),
1213 (NULL == texs) ? NULL : &texSrc,
1214 (NULL == colors) ? NULL : &colSrc,
1215 (NULL == indices) ? NULL : &idxSrc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001216 }
1217}
1218
1219///////////////////////////////////////////////////////////////////////////////
1220
1221static void GlyphCacheAuxProc(void* data) {
1222 delete (GrFontScaler*)data;
1223}
1224
1225static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) {
1226 void* auxData;
1227 GrFontScaler* scaler = NULL;
1228 if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
1229 scaler = (GrFontScaler*)auxData;
1230 }
1231 if (NULL == scaler) {
1232 scaler = new SkGrFontScaler(cache);
1233 cache->setAuxProc(GlyphCacheAuxProc, scaler);
1234 }
1235 return scaler;
1236}
1237
1238static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
1239 SkFixed fx, SkFixed fy,
1240 const SkGlyph& glyph) {
1241 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1242
1243 GrSkDrawProcs* procs = (GrSkDrawProcs*)state.fDraw->fProcs;
1244
1245 if (NULL == procs->fFontScaler) {
1246 procs->fFontScaler = get_gr_font_scaler(state.fCache);
1247 }
1248 procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0),
1249 SkIntToFixed(SkFixedFloor(fx)), fy,
1250 procs->fFontScaler);
1251}
1252
bsalomon@google.com5782d712011-01-21 21:03:59 +00001253SkDrawProcs* SkGpuDevice::initDrawForText(GrTextContext* context) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001254
1255 // deferred allocation
1256 if (NULL == fDrawProcs) {
1257 fDrawProcs = new GrSkDrawProcs;
1258 fDrawProcs->fD1GProc = SkGPU_Draw1Glyph;
1259 fDrawProcs->fContext = fContext;
1260 }
1261
1262 // init our (and GL's) state
1263 fDrawProcs->fTextContext = context;
1264 fDrawProcs->fFontScaler = NULL;
1265 return fDrawProcs;
1266}
1267
1268void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
1269 size_t byteLength, SkScalar x, SkScalar y,
1270 const SkPaint& paint) {
1271 CHECK_SHOULD_DRAW(draw);
1272
1273 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1274 // this guy will just call our drawPath()
1275 draw.drawText((const char*)text, byteLength, x, y, paint);
1276 } else {
1277 SkAutoExtMatrix aem(draw.fExtMatrix);
1278 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001279
1280 GrPaint grPaint;
1281 SkAutoCachedTexture act;
1282
1283 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1284 return;
1285 }
1286 GrTextContext context(fContext, grPaint, aem.extMatrix());
1287 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001288 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
1289 }
1290}
1291
1292void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
1293 size_t byteLength, const SkScalar pos[],
1294 SkScalar constY, int scalarsPerPos,
1295 const SkPaint& paint) {
1296 CHECK_SHOULD_DRAW(draw);
1297
1298 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1299 // this guy will just call our drawPath()
1300 draw.drawPosText((const char*)text, byteLength, pos, constY,
1301 scalarsPerPos, paint);
1302 } else {
1303 SkAutoExtMatrix aem(draw.fExtMatrix);
1304 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001305
1306 GrPaint grPaint;
1307 SkAutoCachedTexture act;
1308 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1309 return;
1310 }
1311
1312 GrTextContext context(fContext, grPaint, aem.extMatrix());
1313 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001314 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
1315 scalarsPerPos, paint);
1316 }
1317}
1318
1319void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
1320 size_t len, const SkPath& path,
1321 const SkMatrix* m, const SkPaint& paint) {
1322 CHECK_SHOULD_DRAW(draw);
1323
1324 SkASSERT(draw.fDevice == this);
1325 draw.drawTextOnPath((const char*)text, len, path, m, paint);
1326}
1327
1328///////////////////////////////////////////////////////////////////////////////
1329
reed@google.comf67e4cf2011-03-15 20:56:58 +00001330bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
1331 if (!paint.isLCDRenderText()) {
1332 // we're cool with the paint as is
1333 return false;
1334 }
1335
1336 if (paint.getShader() ||
1337 paint.getXfermode() || // unless its srcover
1338 paint.getMaskFilter() ||
1339 paint.getRasterizer() ||
1340 paint.getColorFilter() ||
1341 paint.getPathEffect() ||
1342 paint.isFakeBoldText() ||
1343 paint.getStyle() != SkPaint::kFill_Style) {
1344 // turn off lcd
1345 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
1346 flags->fHinting = paint.getHinting();
1347 return true;
1348 }
1349 // we're cool with the paint as is
1350 return false;
1351}
1352
1353///////////////////////////////////////////////////////////////////////////////
1354
reed@google.comac10a2d2010-12-22 21:39:39 +00001355SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
1356 const GrSamplerState& sampler,
1357 GrTexture** texture,
1358 bool forDeviceRenderTarget) {
1359 GrContext* ctx = this->context();
1360 uint32_t p0, p1;
1361 if (forDeviceRenderTarget) {
1362 p0 = p1 = -1;
1363 } else {
1364 p0 = bitmap.getGenerationID();
1365 p1 = bitmap.pixelRefOffset();
1366 }
1367
1368 GrTexture* newTexture = NULL;
1369 GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
1370 GrTextureEntry* entry = ctx->findAndLockTexture(&key, sampler);
1371
1372 if (NULL == entry) {
1373
1374 if (forDeviceRenderTarget) {
1375 const GrGpu::TextureDesc desc = {
1376 GrGpu::kRenderTarget_TextureFlag,
1377 GrGpu::kNone_AALevel,
1378 bitmap.width(),
1379 bitmap.height(),
1380 SkGr::Bitmap2PixelConfig(bitmap)
1381 };
1382 entry = ctx->createAndLockTexture(&key, sampler, desc, NULL, 0);
1383
1384 } else {
1385 entry = sk_gr_create_bitmap_texture(ctx, &key, sampler, bitmap);
1386 }
1387 if (NULL == entry) {
1388 GrPrintf("---- failed to create texture for cache [%d %d]\n",
1389 bitmap.width(), bitmap.height());
1390 }
1391 }
1392
1393 if (NULL != entry) {
1394 newTexture = entry->texture();
reed@google.comac10a2d2010-12-22 21:39:39 +00001395 if (texture) {
1396 *texture = newTexture;
1397 }
1398 // IMPORTANT: We can't allow another SkGpuDevice to get this
1399 // cache entry until this one is destroyed!
1400 if (forDeviceRenderTarget) {
1401 ctx->detachCachedTexture(entry);
1402 }
1403 }
1404 return (TexCache*)entry;
1405}
1406
1407void SkGpuDevice::unlockCachedTexture(TexCache* cache) {
1408 this->context()->unlockTexture((GrTextureEntry*)cache);
1409}
1410
reed@google.com7b201d22011-01-11 18:59:23 +00001411///////////////////////////////////////////////////////////////////////////////
1412
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001413SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context,
1414 GrRenderTarget* rootRenderTarget)
1415 : fContext(context) {
1416
1417 GrAssert(NULL != context);
1418 GrAssert(NULL != rootRenderTarget);
1419
1420 // check this now rather than passing this value to SkGpuDevice cons.
1421 // we want the rt that is bound *now* in the 3D API, not the one
1422 // at the time of newDevice.
1423 if (SkGpuDevice::Current3DApiRenderTarget() == rootRenderTarget) {
1424 fRootRenderTarget = context->createRenderTargetFrom3DApiState();
1425 } else {
1426 fRootRenderTarget = rootRenderTarget;
1427 rootRenderTarget->ref();
1428 }
reed@google.com7b201d22011-01-11 18:59:23 +00001429 context->ref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001430
reed@google.com7b201d22011-01-11 18:59:23 +00001431}
1432
1433SkGpuDeviceFactory::~SkGpuDeviceFactory() {
1434 fContext->unref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001435 fRootRenderTarget->unref();
reed@google.com7b201d22011-01-11 18:59:23 +00001436}
1437
1438SkDevice* SkGpuDeviceFactory::newDevice(SkCanvas*, SkBitmap::Config config,
1439 int width, int height,
1440 bool isOpaque, bool isLayer) {
1441 SkBitmap bm;
1442 bm.setConfig(config, width, height);
1443 bm.setIsOpaque(isOpaque);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001444 return new SkGpuDevice(fContext, bm, isLayer ? NULL : fRootRenderTarget);
reed@google.com7b201d22011-01-11 18:59:23 +00001445}
reed@google.comac10a2d2010-12-22 21:39:39 +00001446