blob: 43daa7c2993232b8d7c760a7fdf565ee43c23448 [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.combf86c632011-04-06 13:42:34 +0000773
reed@google.comc9aa5872011-04-05 21:05:37 +0000774 if (SkDraw::kHair_RectType == type && doAA) {
775 strokeSize.set(SK_Scalar1, SK_Scalar1);
776 type = SkDraw::kStroke_RectType;
reed@google.com62ab7ad2011-04-05 14:08:25 +0000777 }
reed@google.comc9aa5872011-04-05 21:05:37 +0000778
779 switch (type) {
780 case SkDraw::kHair_RectType:
781 SkASSERT(!doAA);
782 fContext->drawRect(grPaint, Sk2Gr(rect), 0);
783 break;
784 case SkDraw::kFill_RectType:
785 if (doAA) {
786 SkRect devRect;
787 matrix.mapRect(&devRect, rect);
788 fillDevAARect(fContext, grPaint, Sk2Gr(devRect));
789 } else {
790 fContext->drawRect(grPaint, Sk2Gr(rect), -1);
791 }
792 break;
793 case SkDraw::kStroke_RectType:
794 if (doAA) {
795 SkRect devRect;
796 matrix.mapRect(&devRect, rect);
797 strokeDevAARect(fContext, grPaint, Sk2Gr(devRect), strokeSize);
798 } else {
799 fContext->drawRect(grPaint, Sk2Gr(rect), paint.getStrokeWidth());
800 }
801 break;
802 default:
803 SkASSERT(!"bad value for RectType");
804 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000805 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000806}
807
reed@google.com69302852011-02-16 18:08:07 +0000808#include "SkMaskFilter.h"
809#include "SkBounder.h"
810
reed@google.com69302852011-02-16 18:08:07 +0000811static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
812 SkMaskFilter* filter, const SkMatrix& matrix,
813 const SkRegion& clip, SkBounder* bounder,
814 GrPaint* grp) {
815 SkMask srcM, dstM;
816
817 if (!SkDraw::DrawToMask(path, &clip.getBounds(), filter, &matrix, &srcM,
818 SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
819 return false;
820 }
821
822 SkAutoMaskImage autoSrc(&srcM, false);
823
824 if (!filter->filterMask(&dstM, srcM, matrix, NULL)) {
825 return false;
826 }
827 // this will free-up dstM when we're done (allocated in filterMask())
828 SkAutoMaskImage autoDst(&dstM, false);
829
830 if (clip.quickReject(dstM.fBounds)) {
831 return false;
832 }
833 if (bounder && !bounder->doIRect(dstM.fBounds)) {
834 return false;
835 }
836
837 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
838 // the current clip (and identity matrix) and grpaint settings
839
reed@google.com0c219b62011-02-16 21:31:18 +0000840 GrAutoMatrix avm(context, GrMatrix::I());
reed@google.com69302852011-02-16 18:08:07 +0000841
842 const GrGpu::TextureDesc desc = {
843 0,
844 GrGpu::kNone_AALevel,
845 dstM.fBounds.width(),
846 dstM.fBounds.height(),
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000847 kAlpha_8_GrPixelConfig
reed@google.com69302852011-02-16 18:08:07 +0000848 };
849
850 GrTexture* texture = context->createUncachedTexture(desc, dstM.fImage,
851 dstM.fRowBytes);
852 if (NULL == texture) {
853 return false;
854 }
855
reed@google.com0c219b62011-02-16 21:31:18 +0000856 grp->setTexture(texture);
857 texture->unref();
858 grp->fSampler.setClampNoFilter();
reed@google.com69302852011-02-16 18:08:07 +0000859
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000860 GrRect d;
861 d.setLTRB(GrIntToScalar(dstM.fBounds.fLeft),
reed@google.com0c219b62011-02-16 21:31:18 +0000862 GrIntToScalar(dstM.fBounds.fTop),
863 GrIntToScalar(dstM.fBounds.fRight),
864 GrIntToScalar(dstM.fBounds.fBottom));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000865 GrRect s;
866 s.setLTRB(0, 0, GR_Scalar1, GR_Scalar1);
867 context->drawRectToRect(*grp, d, s);
reed@google.com69302852011-02-16 18:08:07 +0000868 return true;
869}
reed@google.com69302852011-02-16 18:08:07 +0000870
reed@google.com0c219b62011-02-16 21:31:18 +0000871void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
reed@google.comac10a2d2010-12-22 21:39:39 +0000872 const SkPaint& paint, const SkMatrix* prePathMatrix,
873 bool pathIsMutable) {
874 CHECK_SHOULD_DRAW(draw);
875
bsalomon@google.com5782d712011-01-21 21:03:59 +0000876 GrPaint grPaint;
877 SkAutoCachedTexture act;
878 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000879 return;
880 }
881
reed@google.com0c219b62011-02-16 21:31:18 +0000882 // BEGIN lift from SkDraw::drawPath()
883
884 SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
885 bool doFill = true;
886 SkPath tmpPath;
reed@google.comac10a2d2010-12-22 21:39:39 +0000887
888 if (prePathMatrix) {
reed@google.come3445642011-02-16 23:20:39 +0000889 SkPath* result = pathPtr;
reed@google.com0c219b62011-02-16 21:31:18 +0000890
reed@google.come3445642011-02-16 23:20:39 +0000891 if (!pathIsMutable) {
892 result = &tmpPath;
893 pathIsMutable = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000894 }
reed@google.come3445642011-02-16 23:20:39 +0000895 // should I push prePathMatrix on our MV stack temporarily, instead
896 // of applying it here? See SkDraw.cpp
897 pathPtr->transform(*prePathMatrix, result);
898 pathPtr = result;
reed@google.comac10a2d2010-12-22 21:39:39 +0000899 }
reed@google.com0c219b62011-02-16 21:31:18 +0000900 // at this point we're done with prePathMatrix
901 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
reed@google.comac10a2d2010-12-22 21:39:39 +0000902
bsalomon@google.com04de7822011-03-25 18:04:43 +0000903 // This "if" is not part of the SkDraw::drawPath() lift.
904 // When we get a 1.0 wide stroke we hairline stroke it instead of creating
905 // a new stroked-path. This is motivated by canvas2D sites that draw
906 // lines as 1.0 wide stroked paths. We can consider doing an alpha-modulated-
907 // hairline for width < 1.0 when AA is enabled.
908 static const int gMatrixMask = ~(SkMatrix::kIdentity_Mask |
909 SkMatrix::kTranslate_Mask);
910 if (!paint.getPathEffect() &&
911 SkPaint::kStroke_Style == paint.getStyle() &&
912 !(draw.fMatrix->getType() & gMatrixMask) &&
913 SK_Scalar1 == paint.getStrokeWidth()) {
914 doFill = false;
915 }
916
917 if (doFill && (paint.getPathEffect() ||
918 paint.getStyle() != SkPaint::kFill_Style)) {
reed@google.com0c219b62011-02-16 21:31:18 +0000919 doFill = paint.getFillPath(*pathPtr, &tmpPath);
920 pathPtr = &tmpPath;
921 }
922
923 // END lift from SkDraw::drawPath()
924
reed@google.com69302852011-02-16 18:08:07 +0000925 if (paint.getMaskFilter()) {
reed@google.com0c219b62011-02-16 21:31:18 +0000926 // avoid possibly allocating a new path in transform if we can
927 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
928
929 // transform the path into device space
reed@google.come3445642011-02-16 23:20:39 +0000930 pathPtr->transform(*draw.fMatrix, devPathPtr);
reed@google.com0c219b62011-02-16 21:31:18 +0000931
932 drawWithMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
reed@google.com69302852011-02-16 18:08:07 +0000933 *draw.fMatrix, *draw.fClip, draw.fBounder, &grPaint);
934 return;
935 }
reed@google.com69302852011-02-16 18:08:07 +0000936
bsalomon@google.comffca4002011-02-22 20:34:01 +0000937 GrPathFill fill = kHairLine_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000938
reed@google.com0c219b62011-02-16 21:31:18 +0000939 if (doFill) {
940 switch (pathPtr->getFillType()) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000941 case SkPath::kWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000942 fill = kWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000943 break;
944 case SkPath::kEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000945 fill = kEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000946 break;
947 case SkPath::kInverseWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000948 fill = kInverseWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000949 break;
950 case SkPath::kInverseEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000951 fill = kInverseEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000952 break;
953 default:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000954 SkDebugf("Unsupported path fill type\n");
reed@google.comac10a2d2010-12-22 21:39:39 +0000955 return;
956 }
957 }
958
reed@google.com0c219b62011-02-16 21:31:18 +0000959 SkGrPathIter iter(*pathPtr);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000960 fContext->drawPath(grPaint, &iter, fill);
reed@google.comac10a2d2010-12-22 21:39:39 +0000961}
962
reed@google.comac10a2d2010-12-22 21:39:39 +0000963void SkGpuDevice::drawBitmap(const SkDraw& draw,
964 const SkBitmap& bitmap,
965 const SkIRect* srcRectPtr,
966 const SkMatrix& m,
967 const SkPaint& paint) {
968 CHECK_SHOULD_DRAW(draw);
969
970 SkIRect srcRect;
971 if (NULL == srcRectPtr) {
972 srcRect.set(0, 0, bitmap.width(), bitmap.height());
973 } else {
974 srcRect = *srcRectPtr;
975 }
976
bsalomon@google.com5782d712011-01-21 21:03:59 +0000977 GrPaint grPaint;
978 if (!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
979 return;
980 }
981 grPaint.fSampler.setFilter(paint.isFilterBitmap());
982
reed@google.com02a7e6c2011-01-28 21:21:49 +0000983 const int maxTextureDim = fContext->getMaxTextureDimension();
984 if (bitmap.getTexture() || (bitmap.width() <= maxTextureDim &&
985 bitmap.height() <= maxTextureDim)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000986 // take the fast case
bsalomon@google.com5782d712011-01-21 21:03:59 +0000987 this->internalDrawBitmap(draw, bitmap, srcRect, m, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000988 return;
989 }
990
991 // undo the translate done by SkCanvas
992 int DX = SkMax32(0, srcRect.fLeft);
993 int DY = SkMax32(0, srcRect.fTop);
994 // compute clip bounds in local coordinates
995 SkIRect clipRect;
996 {
997 SkRect r;
998 r.set(draw.fClip->getBounds());
999 SkMatrix matrix, inverse;
1000 matrix.setConcat(*draw.fMatrix, m);
1001 if (!matrix.invert(&inverse)) {
1002 return;
1003 }
1004 inverse.mapRect(&r);
1005 r.roundOut(&clipRect);
1006 // apply the canvas' translate to our local clip
1007 clipRect.offset(DX, DY);
1008 }
1009
reed@google.com02a7e6c2011-01-28 21:21:49 +00001010 int nx = bitmap.width() / maxTextureDim;
1011 int ny = bitmap.height() / maxTextureDim;
reed@google.comac10a2d2010-12-22 21:39:39 +00001012 for (int x = 0; x <= nx; x++) {
1013 for (int y = 0; y <= ny; y++) {
1014 SkIRect tileR;
reed@google.com02a7e6c2011-01-28 21:21:49 +00001015 tileR.set(x * maxTextureDim, y * maxTextureDim,
1016 (x + 1) * maxTextureDim, (y + 1) * maxTextureDim);
reed@google.comac10a2d2010-12-22 21:39:39 +00001017 if (!SkIRect::Intersects(tileR, clipRect)) {
1018 continue;
1019 }
1020
1021 SkIRect srcR = tileR;
1022 if (!srcR.intersect(srcRect)) {
1023 continue;
1024 }
1025
1026 SkBitmap tmpB;
1027 if (bitmap.extractSubset(&tmpB, tileR)) {
1028 // now offset it to make it "local" to our tmp bitmap
1029 srcR.offset(-tileR.fLeft, -tileR.fTop);
1030
1031 SkMatrix tmpM(m);
1032 {
1033 int dx = tileR.fLeft - DX + SkMax32(0, srcR.fLeft);
1034 int dy = tileR.fTop - DY + SkMax32(0, srcR.fTop);
1035 tmpM.preTranslate(SkIntToScalar(dx), SkIntToScalar(dy));
1036 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001037 this->internalDrawBitmap(draw, tmpB, srcR, tmpM, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +00001038 }
1039 }
1040 }
1041}
1042
1043/*
1044 * This is called by drawBitmap(), which has to handle images that may be too
1045 * large to be represented by a single texture.
1046 *
bsalomon@google.com5782d712011-01-21 21:03:59 +00001047 * internalDrawBitmap assumes that the specified bitmap will fit in a texture
1048 * and that non-texture portion of the GrPaint has already been setup.
reed@google.comac10a2d2010-12-22 21:39:39 +00001049 */
1050void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
1051 const SkBitmap& bitmap,
1052 const SkIRect& srcRect,
1053 const SkMatrix& m,
bsalomon@google.com5782d712011-01-21 21:03:59 +00001054 GrPaint* grPaint) {
reed@google.com02a7e6c2011-01-28 21:21:49 +00001055 SkASSERT(bitmap.width() <= fContext->getMaxTextureDimension() &&
1056 bitmap.height() <= fContext->getMaxTextureDimension());
reed@google.comac10a2d2010-12-22 21:39:39 +00001057
1058 SkAutoLockPixels alp(bitmap);
1059 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
1060 return;
1061 }
1062
bsalomon@google.com5782d712011-01-21 21:03:59 +00001063 grPaint->fSampler.setWrapX(GrSamplerState::kClamp_WrapMode);
1064 grPaint->fSampler.setWrapY(GrSamplerState::kClamp_WrapMode);
1065 grPaint->fSampler.setSampleMode(GrSamplerState::kNormal_SampleMode);
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001066 grPaint->fSampler.setMatrix(GrMatrix::I());
reed@google.comac10a2d2010-12-22 21:39:39 +00001067
1068 GrTexture* texture;
bsalomon@google.com5782d712011-01-21 21:03:59 +00001069 SkAutoCachedTexture act(this, bitmap, grPaint->fSampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +00001070 if (NULL == texture) {
1071 return;
1072 }
1073
bsalomon@google.com5782d712011-01-21 21:03:59 +00001074 grPaint->setTexture(texture);
reed@google.com46799cd2011-02-22 20:56:26 +00001075
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +00001076 GrRect dstRect(0, 0, GrIntToScalar(srcRect.width()), GrIntToScalar(srcRect.height()));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001077 GrRect paintRect;
1078 paintRect.setLTRB(GrFixedToScalar((srcRect.fLeft << 16) / bitmap.width()),
1079 GrFixedToScalar((srcRect.fTop << 16) / bitmap.height()),
1080 GrFixedToScalar((srcRect.fRight << 16) / bitmap.width()),
1081 GrFixedToScalar((srcRect.fBottom << 16) / bitmap.height()));
reed@google.comac10a2d2010-12-22 21:39:39 +00001082
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +00001083 GrMatrix grMat;
1084 SkGr::SkMatrix2GrMatrix(m, &grMat);
reed@google.comac10a2d2010-12-22 21:39:39 +00001085
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +00001086 fContext->drawRectToRect(*grPaint, dstRect, paintRect, &grMat);
reed@google.comac10a2d2010-12-22 21:39:39 +00001087}
1088
1089void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
1090 int left, int top, const SkPaint& paint) {
1091 CHECK_SHOULD_DRAW(draw);
1092
1093 SkAutoLockPixels alp(bitmap);
1094 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
1095 return;
1096 }
1097
bsalomon@google.com5782d712011-01-21 21:03:59 +00001098 GrPaint grPaint;
1099 if(!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
1100 return;
1101 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001102
bsalomon@google.com5782d712011-01-21 21:03:59 +00001103 GrAutoMatrix avm(fContext, GrMatrix::I());
1104
1105 GrTexture* texture;
1106 grPaint.fSampler.setClampNoFilter();
1107 SkAutoCachedTexture act(this, bitmap, grPaint.fSampler, &texture);
1108
bsalomon@google.com5782d712011-01-21 21:03:59 +00001109 grPaint.setTexture(texture);
1110
bsalomon@google.com5782d712011-01-21 21:03:59 +00001111 fContext->drawRectToRect(grPaint,
1112 GrRect(GrIntToScalar(left), GrIntToScalar(top),
1113 GrIntToScalar(left + bitmap.width()),
1114 GrIntToScalar(top + bitmap.height())),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001115 GrRect(0, 0, GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001116}
1117
1118void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
1119 int x, int y, const SkPaint& paint) {
1120 CHECK_SHOULD_DRAW(draw);
1121
bsalomon@google.com5782d712011-01-21 21:03:59 +00001122 GrPaint grPaint;
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001123 if (!((SkGpuDevice*)dev)->bindDeviceAsTexture(&grPaint) ||
bsalomon@google.com5782d712011-01-21 21:03:59 +00001124 !this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
1125 return;
reed@google.comac10a2d2010-12-22 21:39:39 +00001126 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001127
1128 SkASSERT(NULL != grPaint.getTexture());
1129
1130 const SkBitmap& bm = dev->accessBitmap(false);
1131 int w = bm.width();
1132 int h = bm.height();
1133
1134 GrAutoMatrix avm(fContext, GrMatrix::I());
1135
1136 grPaint.fSampler.setClampNoFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +00001137
1138 fContext->drawRectToRect(grPaint,
reed@google.com1a2e8d22011-01-21 22:08:29 +00001139 GrRect(GrIntToScalar(x),
1140 GrIntToScalar(y),
1141 GrIntToScalar(x + w),
bsalomon@google.com5782d712011-01-21 21:03:59 +00001142 GrIntToScalar(y + h)),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001143 GrRect(0, 0, GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001144}
1145
1146///////////////////////////////////////////////////////////////////////////////
1147
1148// must be in SkCanvas::VertexMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +00001149static const GrPrimitiveType gVertexMode2PrimitiveType[] = {
1150 kTriangles_PrimitiveType,
1151 kTriangleStrip_PrimitiveType,
1152 kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +00001153};
1154
1155void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
1156 int vertexCount, const SkPoint vertices[],
1157 const SkPoint texs[], const SkColor colors[],
1158 SkXfermode* xmode,
1159 const uint16_t indices[], int indexCount,
1160 const SkPaint& paint) {
1161 CHECK_SHOULD_DRAW(draw);
1162
bsalomon@google.com5782d712011-01-21 21:03:59 +00001163 GrPaint grPaint;
1164 SkAutoCachedTexture act;
1165 // we ignore the shader if texs is null.
1166 if (NULL == texs) {
1167 if (!this->skPaint2GrPaintNoShader(paint, false, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001168 return;
1169 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001170 } else {
reed@google.com1a2e8d22011-01-21 22:08:29 +00001171 if (!this->skPaint2GrPaintShader(paint, &act,
1172 *draw.fMatrix,
bsalomon@google.com5782d712011-01-21 21:03:59 +00001173 &grPaint)) {
1174 return;
1175 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001176 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001177
1178 if (NULL != xmode && NULL != texs && NULL != colors) {
1179 SkXfermode::Mode mode;
1180 if (!SkXfermode::IsMode(xmode, &mode) ||
1181 SkXfermode::kMultiply_Mode != mode) {
1182 SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
1183#if 0
1184 return
1185#endif
1186 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001187 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001188
1189#if SK_SCALAR_IS_GR_SCALAR
1190 // even if GrColor and SkColor byte offsets match we need
1191 // to perform pre-multiply.
1192 if (NULL == colors) {
1193 fContext->drawVertices(grPaint,
1194 gVertexMode2PrimitiveType[vmode],
1195 vertexCount,
1196 (GrPoint*) vertices,
1197 (GrPoint*) texs,
1198 NULL,
1199 indices,
1200 indexCount);
1201 } else
1202#endif
1203 {
1204 SkTexCoordSource texSrc(texs);
1205 SkColorSource colSrc(colors);
1206 SkIndexSource idxSrc(indices, indexCount);
1207
1208 fContext->drawCustomVertices(grPaint,
1209 gVertexMode2PrimitiveType[vmode],
1210 SkPositionSource(vertices, vertexCount),
1211 (NULL == texs) ? NULL : &texSrc,
1212 (NULL == colors) ? NULL : &colSrc,
1213 (NULL == indices) ? NULL : &idxSrc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001214 }
1215}
1216
1217///////////////////////////////////////////////////////////////////////////////
1218
1219static void GlyphCacheAuxProc(void* data) {
1220 delete (GrFontScaler*)data;
1221}
1222
1223static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) {
1224 void* auxData;
1225 GrFontScaler* scaler = NULL;
1226 if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
1227 scaler = (GrFontScaler*)auxData;
1228 }
1229 if (NULL == scaler) {
1230 scaler = new SkGrFontScaler(cache);
1231 cache->setAuxProc(GlyphCacheAuxProc, scaler);
1232 }
1233 return scaler;
1234}
1235
1236static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
1237 SkFixed fx, SkFixed fy,
1238 const SkGlyph& glyph) {
1239 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1240
1241 GrSkDrawProcs* procs = (GrSkDrawProcs*)state.fDraw->fProcs;
1242
1243 if (NULL == procs->fFontScaler) {
1244 procs->fFontScaler = get_gr_font_scaler(state.fCache);
1245 }
1246 procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0),
1247 SkIntToFixed(SkFixedFloor(fx)), fy,
1248 procs->fFontScaler);
1249}
1250
bsalomon@google.com5782d712011-01-21 21:03:59 +00001251SkDrawProcs* SkGpuDevice::initDrawForText(GrTextContext* context) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001252
1253 // deferred allocation
1254 if (NULL == fDrawProcs) {
1255 fDrawProcs = new GrSkDrawProcs;
1256 fDrawProcs->fD1GProc = SkGPU_Draw1Glyph;
1257 fDrawProcs->fContext = fContext;
1258 }
1259
1260 // init our (and GL's) state
1261 fDrawProcs->fTextContext = context;
1262 fDrawProcs->fFontScaler = NULL;
1263 return fDrawProcs;
1264}
1265
1266void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
1267 size_t byteLength, SkScalar x, SkScalar y,
1268 const SkPaint& paint) {
1269 CHECK_SHOULD_DRAW(draw);
1270
1271 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1272 // this guy will just call our drawPath()
1273 draw.drawText((const char*)text, byteLength, x, y, paint);
1274 } else {
1275 SkAutoExtMatrix aem(draw.fExtMatrix);
1276 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001277
1278 GrPaint grPaint;
1279 SkAutoCachedTexture act;
1280
1281 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1282 return;
1283 }
1284 GrTextContext context(fContext, grPaint, aem.extMatrix());
1285 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001286 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
1287 }
1288}
1289
1290void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
1291 size_t byteLength, const SkScalar pos[],
1292 SkScalar constY, int scalarsPerPos,
1293 const SkPaint& paint) {
1294 CHECK_SHOULD_DRAW(draw);
1295
1296 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1297 // this guy will just call our drawPath()
1298 draw.drawPosText((const char*)text, byteLength, pos, constY,
1299 scalarsPerPos, paint);
1300 } else {
1301 SkAutoExtMatrix aem(draw.fExtMatrix);
1302 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001303
1304 GrPaint grPaint;
1305 SkAutoCachedTexture act;
1306 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1307 return;
1308 }
1309
1310 GrTextContext context(fContext, grPaint, aem.extMatrix());
1311 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001312 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
1313 scalarsPerPos, paint);
1314 }
1315}
1316
1317void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
1318 size_t len, const SkPath& path,
1319 const SkMatrix* m, const SkPaint& paint) {
1320 CHECK_SHOULD_DRAW(draw);
1321
1322 SkASSERT(draw.fDevice == this);
1323 draw.drawTextOnPath((const char*)text, len, path, m, paint);
1324}
1325
1326///////////////////////////////////////////////////////////////////////////////
1327
reed@google.comf67e4cf2011-03-15 20:56:58 +00001328bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
1329 if (!paint.isLCDRenderText()) {
1330 // we're cool with the paint as is
1331 return false;
1332 }
1333
1334 if (paint.getShader() ||
1335 paint.getXfermode() || // unless its srcover
1336 paint.getMaskFilter() ||
1337 paint.getRasterizer() ||
1338 paint.getColorFilter() ||
1339 paint.getPathEffect() ||
1340 paint.isFakeBoldText() ||
1341 paint.getStyle() != SkPaint::kFill_Style) {
1342 // turn off lcd
1343 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
1344 flags->fHinting = paint.getHinting();
1345 return true;
1346 }
1347 // we're cool with the paint as is
1348 return false;
1349}
1350
1351///////////////////////////////////////////////////////////////////////////////
1352
reed@google.comac10a2d2010-12-22 21:39:39 +00001353SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
1354 const GrSamplerState& sampler,
1355 GrTexture** texture,
1356 bool forDeviceRenderTarget) {
1357 GrContext* ctx = this->context();
1358 uint32_t p0, p1;
1359 if (forDeviceRenderTarget) {
1360 p0 = p1 = -1;
1361 } else {
1362 p0 = bitmap.getGenerationID();
1363 p1 = bitmap.pixelRefOffset();
1364 }
1365
1366 GrTexture* newTexture = NULL;
1367 GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
1368 GrTextureEntry* entry = ctx->findAndLockTexture(&key, sampler);
1369
1370 if (NULL == entry) {
1371
1372 if (forDeviceRenderTarget) {
1373 const GrGpu::TextureDesc desc = {
1374 GrGpu::kRenderTarget_TextureFlag,
1375 GrGpu::kNone_AALevel,
1376 bitmap.width(),
1377 bitmap.height(),
1378 SkGr::Bitmap2PixelConfig(bitmap)
1379 };
1380 entry = ctx->createAndLockTexture(&key, sampler, desc, NULL, 0);
1381
1382 } else {
1383 entry = sk_gr_create_bitmap_texture(ctx, &key, sampler, bitmap);
1384 }
1385 if (NULL == entry) {
1386 GrPrintf("---- failed to create texture for cache [%d %d]\n",
1387 bitmap.width(), bitmap.height());
1388 }
1389 }
1390
1391 if (NULL != entry) {
1392 newTexture = entry->texture();
reed@google.comac10a2d2010-12-22 21:39:39 +00001393 if (texture) {
1394 *texture = newTexture;
1395 }
1396 // IMPORTANT: We can't allow another SkGpuDevice to get this
1397 // cache entry until this one is destroyed!
1398 if (forDeviceRenderTarget) {
1399 ctx->detachCachedTexture(entry);
1400 }
1401 }
1402 return (TexCache*)entry;
1403}
1404
1405void SkGpuDevice::unlockCachedTexture(TexCache* cache) {
1406 this->context()->unlockTexture((GrTextureEntry*)cache);
1407}
1408
reed@google.com7b201d22011-01-11 18:59:23 +00001409///////////////////////////////////////////////////////////////////////////////
1410
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001411SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context,
1412 GrRenderTarget* rootRenderTarget)
1413 : fContext(context) {
1414
1415 GrAssert(NULL != context);
1416 GrAssert(NULL != rootRenderTarget);
1417
1418 // check this now rather than passing this value to SkGpuDevice cons.
1419 // we want the rt that is bound *now* in the 3D API, not the one
1420 // at the time of newDevice.
1421 if (SkGpuDevice::Current3DApiRenderTarget() == rootRenderTarget) {
1422 fRootRenderTarget = context->createRenderTargetFrom3DApiState();
1423 } else {
1424 fRootRenderTarget = rootRenderTarget;
1425 rootRenderTarget->ref();
1426 }
reed@google.com7b201d22011-01-11 18:59:23 +00001427 context->ref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001428
reed@google.com7b201d22011-01-11 18:59:23 +00001429}
1430
1431SkGpuDeviceFactory::~SkGpuDeviceFactory() {
1432 fContext->unref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001433 fRootRenderTarget->unref();
reed@google.com7b201d22011-01-11 18:59:23 +00001434}
1435
1436SkDevice* SkGpuDeviceFactory::newDevice(SkCanvas*, SkBitmap::Config config,
1437 int width, int height,
1438 bool isOpaque, bool isLayer) {
1439 SkBitmap bm;
1440 bm.setConfig(config, width, height);
1441 bm.setIsOpaque(isOpaque);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001442 return new SkGpuDevice(fContext, bm, isLayer ? NULL : fRootRenderTarget);
reed@google.com7b201d22011-01-11 18:59:23 +00001443}
reed@google.comac10a2d2010-12-22 21:39:39 +00001444