blob: 036d9b5ae924d7b8c08c15b1376a35d510106d2f [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());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000195 fContext->unlockTexture((GrTextureEntry*)fCache);
reed@google.comac10a2d2010-12-22 21:39:39 +0000196 } else if (NULL != fTexture) {
197 GrAssert(!CACHE_LAYER_TEXTURES);
198 GrAssert(fRenderTarget == fTexture->asRenderTarget());
199 fTexture->unref();
200 } else if (NULL != fRenderTarget) {
201 fRenderTarget->unref();
202 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000203 fContext->unref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000204}
205
reed@google.comac10a2d2010-12-22 21:39:39 +0000206intptr_t SkGpuDevice::getLayerTextureHandle() const {
207 if (fTexture) {
208 return fTexture->getTextureHandle();
209 } else {
210 return 0;
211 }
212}
213///////////////////////////////////////////////////////////////////////////////
214
215void SkGpuDevice::makeRenderTargetCurrent() {
216 fContext->setRenderTarget(fRenderTarget);
217 fContext->flush(true);
218 fNeedPrepareRenderTarget = true;
219}
220
221///////////////////////////////////////////////////////////////////////////////
222
223bool SkGpuDevice::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
224 SkIRect bounds;
225 bounds.set(0, 0, this->width(), this->height());
226 if (!bounds.intersect(srcRect)) {
227 return false;
228 }
229
230 const int w = bounds.width();
231 const int h = bounds.height();
232 SkBitmap tmp;
233 // note we explicitly specify our rowBytes to be snug (no gap between rows)
234 tmp.setConfig(SkBitmap::kARGB_8888_Config, w, h, w * 4);
235 if (!tmp.allocPixels()) {
236 return false;
237 }
238
Scroggo813c33c2011-04-07 20:56:21 +0000239 tmp.lockPixels();
reed@google.comac10a2d2010-12-22 21:39:39 +0000240
Scroggoeb176032011-04-07 21:11:49 +0000241 bool read = fContext->readRenderTargetPixels(fRenderTarget,
242 bounds.fLeft, bounds.fTop,
243 bounds.width(), bounds.height(),
244 kRGBA_8888_GrPixelConfig,
245 tmp.getPixels());
Scroggo813c33c2011-04-07 20:56:21 +0000246 tmp.unlockPixels();
247 if (!read) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000248 return false;
249 }
250
251 tmp.swap(*bitmap);
252 return true;
253}
254
255void SkGpuDevice::writePixels(const SkBitmap& bitmap, int x, int y) {
256 SkAutoLockPixels alp(bitmap);
257 if (!bitmap.readyToDraw()) {
258 return;
259 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000260 GrPixelConfig config = SkGr::BitmapConfig2PixelConfig(bitmap.config(),
261 bitmap.isOpaque());
reed@google.comac10a2d2010-12-22 21:39:39 +0000262 fContext->setRenderTarget(fRenderTarget);
263 // we aren't setting the clip or matrix, so mark as dirty
264 // we don't need to set them for this call and don't have them anyway
265 fNeedPrepareRenderTarget = true;
266
267 fContext->writePixels(x, y, bitmap.width(), bitmap.height(),
268 config, bitmap.getPixels(), bitmap.rowBytes());
269}
270
271///////////////////////////////////////////////////////////////////////////////
272
273static void convert_matrixclip(GrContext* context, const SkMatrix& matrix,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000274 const SkClipStack& clipStack,
reed@google.com6f8f2922011-03-04 22:27:10 +0000275 const SkRegion& clipRegion,
276 const SkIPoint& origin) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000277 GrMatrix grmat;
278 SkGr::SkMatrix2GrMatrix(matrix, &grmat);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000279 context->setMatrix(grmat);
reed@google.comac10a2d2010-12-22 21:39:39 +0000280
281 SkGrClipIterator iter;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000282 iter.reset(clipStack);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000283 const SkIRect& skBounds = clipRegion.getBounds();
284 GrRect bounds;
285 bounds.setLTRB(GrIntToScalar(skBounds.fLeft),
286 GrIntToScalar(skBounds.fTop),
287 GrIntToScalar(skBounds.fRight),
288 GrIntToScalar(skBounds.fBottom));
reed@google.com6f8f2922011-03-04 22:27:10 +0000289 GrClip grc(&iter, GrIntToScalar(-origin.x()), GrIntToScalar(-origin.y()),
290 &bounds);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000291 context->setClip(grc);
reed@google.comac10a2d2010-12-22 21:39:39 +0000292}
293
294// call this ever each draw call, to ensure that the context reflects our state,
295// and not the state from some other canvas/device
296void SkGpuDevice::prepareRenderTarget(const SkDraw& draw) {
297 if (fNeedPrepareRenderTarget ||
bsalomon@google.com5782d712011-01-21 21:03:59 +0000298 fContext->getRenderTarget() != fRenderTarget) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000299
300 fContext->setRenderTarget(fRenderTarget);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000301 SkASSERT(draw.fClipStack);
302 convert_matrixclip(fContext, *draw.fMatrix,
reed@google.com6f8f2922011-03-04 22:27:10 +0000303 *draw.fClipStack, *draw.fClip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000304 fNeedPrepareRenderTarget = false;
305 }
306}
307
reed@google.com46799cd2011-02-22 20:56:26 +0000308void SkGpuDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& clip,
309 const SkClipStack& clipStack) {
310 this->INHERITED::setMatrixClip(matrix, clip, clipStack);
bsalomon@google.coma7bf6e22011-04-11 19:20:46 +0000311 // We don't need to set them now because the context may not reflect this device.
312 fNeedPrepareRenderTarget = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000313}
314
315void SkGpuDevice::gainFocus(SkCanvas* canvas, const SkMatrix& matrix,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000316 const SkRegion& clip, const SkClipStack& clipStack) {
317
reed@google.comac10a2d2010-12-22 21:39:39 +0000318 fContext->setRenderTarget(fRenderTarget);
319
bsalomon@google.comd302f142011-03-03 13:54:13 +0000320 this->INHERITED::gainFocus(canvas, matrix, clip, clipStack);
reed@google.comac10a2d2010-12-22 21:39:39 +0000321
reed@google.com6f8f2922011-03-04 22:27:10 +0000322 convert_matrixclip(fContext, matrix, clipStack, clip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000323
324 if (fNeedClear) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000325 fContext->clear(0x0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000326 fNeedClear = false;
327 }
328}
329
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000330bool SkGpuDevice::bindDeviceAsTexture(GrPaint* paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000331 if (NULL != fTexture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000332 paint->setTexture(fTexture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000333 return true;
334 }
335 return false;
336}
337
338///////////////////////////////////////////////////////////////////////////////
339
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000340SK_COMPILE_ASSERT(SkShader::kNone_BitmapType == 0, shader_type_mismatch);
341SK_COMPILE_ASSERT(SkShader::kDefault_BitmapType == 1, shader_type_mismatch);
342SK_COMPILE_ASSERT(SkShader::kRadial_BitmapType == 2, shader_type_mismatch);
343SK_COMPILE_ASSERT(SkShader::kSweep_BitmapType == 3, shader_type_mismatch);
344SK_COMPILE_ASSERT(SkShader::kTwoPointRadial_BitmapType == 4,
345 shader_type_mismatch);
346SK_COMPILE_ASSERT(SkShader::kLast_BitmapType == 4, shader_type_mismatch);
reed@google.comac10a2d2010-12-22 21:39:39 +0000347
bsalomon@google.com5782d712011-01-21 21:03:59 +0000348static const GrSamplerState::SampleMode sk_bmp_type_to_sample_mode[] = {
349 (GrSamplerState::SampleMode) -1, // kNone_BitmapType
350 GrSamplerState::kNormal_SampleMode, // kDefault_BitmapType
351 GrSamplerState::kRadial_SampleMode, // kRadial_BitmapType
352 GrSamplerState::kSweep_SampleMode, // kSweep_BitmapType
353 GrSamplerState::kRadial2_SampleMode, // kTwoPointRadial_BitmapType
354};
355
356bool SkGpuDevice::skPaint2GrPaintNoShader(const SkPaint& skPaint,
357 bool justAlpha,
358 GrPaint* grPaint) {
359
360 grPaint->fDither = skPaint.isDither();
361 grPaint->fAntiAlias = skPaint.isAntiAlias();
362
363 SkXfermode::Coeff sm = SkXfermode::kOne_Coeff;
364 SkXfermode::Coeff dm = SkXfermode::kISA_Coeff;
365
366 SkXfermode* mode = skPaint.getXfermode();
367 if (mode) {
368 if (!mode->asCoeff(&sm, &dm)) {
reed@google.com1a2e8d22011-01-21 22:08:29 +0000369 SkDEBUGCODE(SkDebugf("Unsupported xfer mode.\n");)
bsalomon@google.com5782d712011-01-21 21:03:59 +0000370#if 0
371 return false;
372#endif
373 }
374 }
375 grPaint->fSrcBlendCoeff = sk_blend_to_grblend(sm);
376 grPaint->fDstBlendCoeff = sk_blend_to_grblend(dm);
377
378 if (justAlpha) {
379 uint8_t alpha = skPaint.getAlpha();
380 grPaint->fColor = GrColorPackRGBA(alpha, alpha, alpha, alpha);
381 } else {
382 grPaint->fColor = SkGr::SkColor2GrColor(skPaint.getColor());
383 grPaint->setTexture(NULL);
384 }
385 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000386}
387
bsalomon@google.com5782d712011-01-21 21:03:59 +0000388bool SkGpuDevice::skPaint2GrPaintShader(const SkPaint& skPaint,
389 SkAutoCachedTexture* act,
390 const SkMatrix& ctm,
391 GrPaint* grPaint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000392
bsalomon@google.com5782d712011-01-21 21:03:59 +0000393 SkASSERT(NULL != act);
reed@google.comac10a2d2010-12-22 21:39:39 +0000394
bsalomon@google.com5782d712011-01-21 21:03:59 +0000395 SkShader* shader = skPaint.getShader();
reed@google.comac10a2d2010-12-22 21:39:39 +0000396 if (NULL == shader) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000397 return this->skPaint2GrPaintNoShader(skPaint, false, grPaint);
398 grPaint->setTexture(NULL);
399 return true;
400 } else if (!this->skPaint2GrPaintNoShader(skPaint, true, grPaint)) {
401 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000402 }
403
bsalomon@google.com5782d712011-01-21 21:03:59 +0000404 SkPaint noAlphaPaint(skPaint);
405 noAlphaPaint.setAlpha(255);
406 shader->setContext(this->accessBitmap(false), noAlphaPaint, ctm);
reed@google.comac10a2d2010-12-22 21:39:39 +0000407
reed@google.comac10a2d2010-12-22 21:39:39 +0000408 SkBitmap bitmap;
409 SkMatrix matrix;
410 SkShader::TileMode tileModes[2];
411 SkScalar twoPointParams[3];
412 SkShader::BitmapType bmptype = shader->asABitmap(&bitmap, &matrix,
413 tileModes, twoPointParams);
414
bsalomon@google.com5782d712011-01-21 21:03:59 +0000415 GrSamplerState::SampleMode sampleMode = sk_bmp_type_to_sample_mode[bmptype];
416 if (-1 == sampleMode) {
417 SkDebugf("shader->asABitmap() == kNone_BitmapType\n");
418 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000419 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000420 grPaint->fSampler.setSampleMode(sampleMode);
bsalomon@google.com0748f212011-02-01 22:56:16 +0000421 grPaint->fSampler.setFilter(skPaint.isFilterBitmap());
bsalomon@google.com5782d712011-01-21 21:03:59 +0000422 grPaint->fSampler.setWrapX(sk_tile_mode_to_grwrap(tileModes[0]));
423 grPaint->fSampler.setWrapY(sk_tile_mode_to_grwrap(tileModes[1]));
reed@google.comac10a2d2010-12-22 21:39:39 +0000424 if (GrSamplerState::kRadial2_SampleMode == sampleMode) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000425 grPaint->fSampler.setRadial2Params(twoPointParams[0],
426 twoPointParams[1],
427 twoPointParams[2] < 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000428 }
429
bsalomon@google.com5782d712011-01-21 21:03:59 +0000430 GrTexture* texture = act->set(this, bitmap, grPaint->fSampler);
reed@google.comac10a2d2010-12-22 21:39:39 +0000431 if (NULL == texture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000432 SkDebugf("Couldn't convert bitmap to texture.\n");
433 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000434 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000435 grPaint->setTexture(texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000436
437 // since our texture coords will be in local space, we wack the texture
438 // matrix to map them back into 0...1 before we load it
439 SkMatrix localM;
440 if (shader->getLocalMatrix(&localM)) {
441 SkMatrix inverse;
442 if (localM.invert(&inverse)) {
443 matrix.preConcat(inverse);
444 }
445 }
446 if (SkShader::kDefault_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000447 GrScalar sx = GrFixedToScalar(GR_Fixed1 / bitmap.width());
448 GrScalar sy = GrFixedToScalar(GR_Fixed1 / bitmap.height());
reed@google.comac10a2d2010-12-22 21:39:39 +0000449 matrix.postScale(sx, sy);
reed@google.comac10a2d2010-12-22 21:39:39 +0000450 } else if (SkShader::kRadial_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000451 GrScalar s = GrFixedToScalar(GR_Fixed1 / bitmap.width());
reed@google.comac10a2d2010-12-22 21:39:39 +0000452 matrix.postScale(s, s);
453 }
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000454 GrMatrix grMat;
455 SkGr::SkMatrix2GrMatrix(matrix, &grMat);
456 grPaint->fSampler.setMatrix(grMat);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000457
458 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000459}
460
461///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com5782d712011-01-21 21:03:59 +0000462
463class SkPositionSource {
464public:
465 SkPositionSource(const SkPoint* points, int count)
466 : fPoints(points), fCount(count) {}
467
468 int count() const { return fCount; }
469
470 void writeValue(int i, GrPoint* dstPosition) const {
471 SkASSERT(i < fCount);
472 dstPosition->fX = SkScalarToGrScalar(fPoints[i].fX);
473 dstPosition->fY = SkScalarToGrScalar(fPoints[i].fY);
474 }
475private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000476 const SkPoint* fPoints;
bsalomon@google.com19628322011-02-03 21:30:17 +0000477 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000478};
479
480class SkTexCoordSource {
481public:
482 SkTexCoordSource(const SkPoint* coords)
483 : fCoords(coords) {}
484
485 void writeValue(int i, GrPoint* dstCoord) const {
486 dstCoord->fX = SkScalarToGrScalar(fCoords[i].fX);
487 dstCoord->fY = SkScalarToGrScalar(fCoords[i].fY);
488 }
489private:
490 const SkPoint* fCoords;
491};
492
493class SkColorSource {
494public:
495 SkColorSource(const SkColor* colors) : fColors(colors) {}
496
497 void writeValue(int i, GrColor* dstColor) const {
498 *dstColor = SkGr::SkColor2GrColor(fColors[i]);
499 }
500private:
501 const SkColor* fColors;
502};
503
504class SkIndexSource {
505public:
506 SkIndexSource(const uint16_t* indices, int count)
507 : fIndices(indices), fCount(count) {
508 }
509
510 int count() const { return fCount; }
511
512 void writeValue(int i, uint16_t* dstIndex) const {
513 *dstIndex = fIndices[i];
514 }
515
516private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000517 const uint16_t* fIndices;
bsalomon@google.com19628322011-02-03 21:30:17 +0000518 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000519};
520
521///////////////////////////////////////////////////////////////////////////////
522
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000523#if 0 // not currently being used so don't compile,
524
bsalomon@google.com5782d712011-01-21 21:03:59 +0000525// can be used for positions or texture coordinates
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000526
bsalomon@google.com5782d712011-01-21 21:03:59 +0000527class SkRectFanSource {
528public:
529 SkRectFanSource(const SkRect& rect) : fRect(rect) {}
530
531 int count() const { return 4; }
532
533 void writeValue(int i, GrPoint* dstPoint) const {
534 SkASSERT(i < 4);
535 dstPoint->fX = SkScalarToGrScalar((i % 3) ? fRect.fRight :
536 fRect.fLeft);
537 dstPoint->fY = SkScalarToGrScalar((i < 2) ? fRect.fTop :
538 fRect.fBottom);
539 }
540private:
541 const SkRect& fRect;
542};
543
544class SkIRectFanSource {
545public:
546 SkIRectFanSource(const SkIRect& rect) : fRect(rect) {}
547
548 int count() const { return 4; }
549
550 void writeValue(int i, GrPoint* dstPoint) const {
551 SkASSERT(i < 4);
552 dstPoint->fX = (i % 3) ? GrIntToScalar(fRect.fRight) :
553 GrIntToScalar(fRect.fLeft);
554 dstPoint->fY = (i < 2) ? GrIntToScalar(fRect.fTop) :
555 GrIntToScalar(fRect.fBottom);
556 }
557private:
558 const SkIRect& fRect;
559};
560
561class SkMatRectFanSource {
562public:
563 SkMatRectFanSource(const SkRect& rect, const SkMatrix& matrix)
564 : fRect(rect), fMatrix(matrix) {}
565
566 int count() const { return 4; }
567
568 void writeValue(int i, GrPoint* dstPoint) const {
569 SkASSERT(i < 4);
570
571#if SK_SCALAR_IS_GR_SCALAR
572 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
573 (i < 2) ? fRect.fTop : fRect.fBottom,
574 (SkPoint*)dstPoint);
575#else
576 SkPoint dst;
577 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
578 (i < 2) ? fRect.fTop : fRect.fBottom,
579 &dst);
580 dstPoint->fX = SkScalarToGrScalar(dst.fX);
581 dstPoint->fY = SkScalarToGrScalar(dst.fY);
582#endif
583 }
584private:
585 const SkRect& fRect;
586 const SkMatrix& fMatrix;
587};
588
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000589#endif
590
reed@google.comac10a2d2010-12-22 21:39:39 +0000591///////////////////////////////////////////////////////////////////////////////
592
bsalomon@google.com398109c2011-04-14 18:40:27 +0000593void SkGpuDevice::clear(SkColor color) {
594 fContext->clear(color);
595}
596
reed@google.comac10a2d2010-12-22 21:39:39 +0000597void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
598 CHECK_SHOULD_DRAW(draw);
599
bsalomon@google.com5782d712011-01-21 21:03:59 +0000600 GrPaint grPaint;
601 SkAutoCachedTexture act;
602 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000603 return;
604 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000605
606 fContext->drawPaint(grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000607}
608
609// must be in SkCanvas::PointMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +0000610static const GrPrimitiveType gPointMode2PrimtiveType[] = {
611 kPoints_PrimitiveType,
612 kLines_PrimitiveType,
613 kLineStrip_PrimitiveType
reed@google.comac10a2d2010-12-22 21:39:39 +0000614};
615
616void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000617 size_t count, const SkPoint pts[], const SkPaint& paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000618 CHECK_SHOULD_DRAW(draw);
619
620 SkScalar width = paint.getStrokeWidth();
621 if (width < 0) {
622 return;
623 }
624
625 // we only handle hairlines here, else we let the SkDraw call our drawPath()
626 if (width > 0) {
627 draw.drawPoints(mode, count, pts, paint, true);
628 return;
629 }
630
bsalomon@google.com5782d712011-01-21 21:03:59 +0000631 GrPaint grPaint;
632 SkAutoCachedTexture act;
633 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000634 return;
635 }
636
reed@google.comac10a2d2010-12-22 21:39:39 +0000637#if SK_SCALAR_IS_GR_SCALAR
bsalomon@google.com5782d712011-01-21 21:03:59 +0000638 fContext->drawVertices(grPaint,
639 gPointMode2PrimtiveType[mode],
640 count,
641 (GrPoint*)pts,
642 NULL,
643 NULL,
644 NULL,
645 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000646#else
bsalomon@google.com5782d712011-01-21 21:03:59 +0000647 fContext->drawCustomVertices(grPaint,
648 gPointMode2PrimtiveType[mode],
649 SkPositionSource(pts, count));
reed@google.comac10a2d2010-12-22 21:39:39 +0000650#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000651}
652
reed@google.comc9aa5872011-04-05 21:05:37 +0000653///////////////////////////////////////////////////////////////////////////////
654
reed@google.comac10a2d2010-12-22 21:39:39 +0000655void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
656 const SkPaint& paint) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000657 CHECK_SHOULD_DRAW(draw);
658
659 bool doStroke = paint.getStyle() == SkPaint::kStroke_Style;
660 SkScalar width = paint.getStrokeWidth();
661
662 /*
663 We have special code for hairline strokes, miter-strokes, and fills.
664 Anything else we just call our path code.
665 */
666 bool usePath = doStroke && width > 0 &&
667 paint.getStrokeJoin() != SkPaint::kMiter_Join;
668 // another reason we might need to call drawPath...
669 if (paint.getMaskFilter()) {
670 usePath = true;
671 }
672
673 if (usePath) {
674 SkPath path;
675 path.addRect(rect);
676 this->drawPath(draw, path, paint, NULL, true);
677 return;
678 }
679
680 GrPaint grPaint;
681 SkAutoCachedTexture act;
682 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
683 return;
684 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000685 fContext->drawRect(grPaint, Sk2Gr(rect), doStroke ? width : -1);
reed@google.comac10a2d2010-12-22 21:39:39 +0000686}
687
reed@google.com69302852011-02-16 18:08:07 +0000688#include "SkMaskFilter.h"
689#include "SkBounder.h"
690
reed@google.com69302852011-02-16 18:08:07 +0000691static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
692 SkMaskFilter* filter, const SkMatrix& matrix,
693 const SkRegion& clip, SkBounder* bounder,
694 GrPaint* grp) {
695 SkMask srcM, dstM;
696
697 if (!SkDraw::DrawToMask(path, &clip.getBounds(), filter, &matrix, &srcM,
698 SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
699 return false;
700 }
701
702 SkAutoMaskImage autoSrc(&srcM, false);
703
704 if (!filter->filterMask(&dstM, srcM, matrix, NULL)) {
705 return false;
706 }
707 // this will free-up dstM when we're done (allocated in filterMask())
708 SkAutoMaskImage autoDst(&dstM, false);
709
710 if (clip.quickReject(dstM.fBounds)) {
711 return false;
712 }
713 if (bounder && !bounder->doIRect(dstM.fBounds)) {
714 return false;
715 }
716
717 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
718 // the current clip (and identity matrix) and grpaint settings
719
reed@google.com0c219b62011-02-16 21:31:18 +0000720 GrAutoMatrix avm(context, GrMatrix::I());
reed@google.com69302852011-02-16 18:08:07 +0000721
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000722 const GrTextureDesc desc = {
723 kNone_GrTextureFlags,
724 kNone_GrAALevel,
reed@google.com69302852011-02-16 18:08:07 +0000725 dstM.fBounds.width(),
726 dstM.fBounds.height(),
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000727 kAlpha_8_GrPixelConfig
reed@google.com69302852011-02-16 18:08:07 +0000728 };
729
730 GrTexture* texture = context->createUncachedTexture(desc, dstM.fImage,
731 dstM.fRowBytes);
732 if (NULL == texture) {
733 return false;
734 }
735
reed@google.com0c219b62011-02-16 21:31:18 +0000736 grp->setTexture(texture);
737 texture->unref();
738 grp->fSampler.setClampNoFilter();
reed@google.com69302852011-02-16 18:08:07 +0000739
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000740 GrRect d;
741 d.setLTRB(GrIntToScalar(dstM.fBounds.fLeft),
reed@google.com0c219b62011-02-16 21:31:18 +0000742 GrIntToScalar(dstM.fBounds.fTop),
743 GrIntToScalar(dstM.fBounds.fRight),
744 GrIntToScalar(dstM.fBounds.fBottom));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000745 GrRect s;
746 s.setLTRB(0, 0, GR_Scalar1, GR_Scalar1);
747 context->drawRectToRect(*grp, d, s);
reed@google.com69302852011-02-16 18:08:07 +0000748 return true;
749}
reed@google.com69302852011-02-16 18:08:07 +0000750
reed@google.com0c219b62011-02-16 21:31:18 +0000751void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
reed@google.comac10a2d2010-12-22 21:39:39 +0000752 const SkPaint& paint, const SkMatrix* prePathMatrix,
753 bool pathIsMutable) {
754 CHECK_SHOULD_DRAW(draw);
755
bsalomon@google.com5782d712011-01-21 21:03:59 +0000756 GrPaint grPaint;
757 SkAutoCachedTexture act;
758 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000759 return;
760 }
761
reed@google.com0c219b62011-02-16 21:31:18 +0000762 // BEGIN lift from SkDraw::drawPath()
763
764 SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
765 bool doFill = true;
766 SkPath tmpPath;
reed@google.comac10a2d2010-12-22 21:39:39 +0000767
768 if (prePathMatrix) {
reed@google.come3445642011-02-16 23:20:39 +0000769 SkPath* result = pathPtr;
reed@google.com0c219b62011-02-16 21:31:18 +0000770
reed@google.come3445642011-02-16 23:20:39 +0000771 if (!pathIsMutable) {
772 result = &tmpPath;
773 pathIsMutable = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000774 }
reed@google.come3445642011-02-16 23:20:39 +0000775 // should I push prePathMatrix on our MV stack temporarily, instead
776 // of applying it here? See SkDraw.cpp
777 pathPtr->transform(*prePathMatrix, result);
778 pathPtr = result;
reed@google.comac10a2d2010-12-22 21:39:39 +0000779 }
reed@google.com0c219b62011-02-16 21:31:18 +0000780 // at this point we're done with prePathMatrix
781 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
reed@google.comac10a2d2010-12-22 21:39:39 +0000782
bsalomon@google.com04de7822011-03-25 18:04:43 +0000783 // This "if" is not part of the SkDraw::drawPath() lift.
784 // When we get a 1.0 wide stroke we hairline stroke it instead of creating
785 // a new stroked-path. This is motivated by canvas2D sites that draw
786 // lines as 1.0 wide stroked paths. We can consider doing an alpha-modulated-
787 // hairline for width < 1.0 when AA is enabled.
788 static const int gMatrixMask = ~(SkMatrix::kIdentity_Mask |
789 SkMatrix::kTranslate_Mask);
790 if (!paint.getPathEffect() &&
791 SkPaint::kStroke_Style == paint.getStyle() &&
792 !(draw.fMatrix->getType() & gMatrixMask) &&
793 SK_Scalar1 == paint.getStrokeWidth()) {
794 doFill = false;
795 }
796
797 if (doFill && (paint.getPathEffect() ||
798 paint.getStyle() != SkPaint::kFill_Style)) {
reed@google.com0c219b62011-02-16 21:31:18 +0000799 doFill = paint.getFillPath(*pathPtr, &tmpPath);
800 pathPtr = &tmpPath;
801 }
802
803 // END lift from SkDraw::drawPath()
804
reed@google.com69302852011-02-16 18:08:07 +0000805 if (paint.getMaskFilter()) {
reed@google.com0c219b62011-02-16 21:31:18 +0000806 // avoid possibly allocating a new path in transform if we can
807 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
808
809 // transform the path into device space
reed@google.come3445642011-02-16 23:20:39 +0000810 pathPtr->transform(*draw.fMatrix, devPathPtr);
reed@google.com0c219b62011-02-16 21:31:18 +0000811
812 drawWithMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
reed@google.com69302852011-02-16 18:08:07 +0000813 *draw.fMatrix, *draw.fClip, draw.fBounder, &grPaint);
814 return;
815 }
reed@google.com69302852011-02-16 18:08:07 +0000816
bsalomon@google.comffca4002011-02-22 20:34:01 +0000817 GrPathFill fill = kHairLine_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000818
reed@google.com0c219b62011-02-16 21:31:18 +0000819 if (doFill) {
820 switch (pathPtr->getFillType()) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000821 case SkPath::kWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000822 fill = kWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000823 break;
824 case SkPath::kEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000825 fill = kEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000826 break;
827 case SkPath::kInverseWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000828 fill = kInverseWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000829 break;
830 case SkPath::kInverseEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000831 fill = kInverseEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000832 break;
833 default:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000834 SkDebugf("Unsupported path fill type\n");
reed@google.comac10a2d2010-12-22 21:39:39 +0000835 return;
836 }
837 }
838
reed@google.com0c219b62011-02-16 21:31:18 +0000839 SkGrPathIter iter(*pathPtr);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000840 fContext->drawPath(grPaint, &iter, fill);
reed@google.comac10a2d2010-12-22 21:39:39 +0000841}
842
reed@google.comac10a2d2010-12-22 21:39:39 +0000843void SkGpuDevice::drawBitmap(const SkDraw& draw,
844 const SkBitmap& bitmap,
845 const SkIRect* srcRectPtr,
846 const SkMatrix& m,
847 const SkPaint& paint) {
848 CHECK_SHOULD_DRAW(draw);
849
850 SkIRect srcRect;
851 if (NULL == srcRectPtr) {
852 srcRect.set(0, 0, bitmap.width(), bitmap.height());
853 } else {
854 srcRect = *srcRectPtr;
855 }
856
bsalomon@google.com5782d712011-01-21 21:03:59 +0000857 GrPaint grPaint;
858 if (!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
859 return;
860 }
861 grPaint.fSampler.setFilter(paint.isFilterBitmap());
862
reed@google.com02a7e6c2011-01-28 21:21:49 +0000863 const int maxTextureDim = fContext->getMaxTextureDimension();
864 if (bitmap.getTexture() || (bitmap.width() <= maxTextureDim &&
865 bitmap.height() <= maxTextureDim)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000866 // take the fast case
bsalomon@google.com5782d712011-01-21 21:03:59 +0000867 this->internalDrawBitmap(draw, bitmap, srcRect, m, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000868 return;
869 }
870
871 // undo the translate done by SkCanvas
872 int DX = SkMax32(0, srcRect.fLeft);
873 int DY = SkMax32(0, srcRect.fTop);
874 // compute clip bounds in local coordinates
875 SkIRect clipRect;
876 {
877 SkRect r;
878 r.set(draw.fClip->getBounds());
879 SkMatrix matrix, inverse;
880 matrix.setConcat(*draw.fMatrix, m);
881 if (!matrix.invert(&inverse)) {
882 return;
883 }
884 inverse.mapRect(&r);
885 r.roundOut(&clipRect);
886 // apply the canvas' translate to our local clip
887 clipRect.offset(DX, DY);
888 }
889
reed@google.com02a7e6c2011-01-28 21:21:49 +0000890 int nx = bitmap.width() / maxTextureDim;
891 int ny = bitmap.height() / maxTextureDim;
reed@google.comac10a2d2010-12-22 21:39:39 +0000892 for (int x = 0; x <= nx; x++) {
893 for (int y = 0; y <= ny; y++) {
894 SkIRect tileR;
reed@google.com02a7e6c2011-01-28 21:21:49 +0000895 tileR.set(x * maxTextureDim, y * maxTextureDim,
896 (x + 1) * maxTextureDim, (y + 1) * maxTextureDim);
reed@google.comac10a2d2010-12-22 21:39:39 +0000897 if (!SkIRect::Intersects(tileR, clipRect)) {
898 continue;
899 }
900
901 SkIRect srcR = tileR;
902 if (!srcR.intersect(srcRect)) {
903 continue;
904 }
905
906 SkBitmap tmpB;
907 if (bitmap.extractSubset(&tmpB, tileR)) {
908 // now offset it to make it "local" to our tmp bitmap
909 srcR.offset(-tileR.fLeft, -tileR.fTop);
910
911 SkMatrix tmpM(m);
912 {
913 int dx = tileR.fLeft - DX + SkMax32(0, srcR.fLeft);
914 int dy = tileR.fTop - DY + SkMax32(0, srcR.fTop);
915 tmpM.preTranslate(SkIntToScalar(dx), SkIntToScalar(dy));
916 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000917 this->internalDrawBitmap(draw, tmpB, srcR, tmpM, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000918 }
919 }
920 }
921}
922
923/*
924 * This is called by drawBitmap(), which has to handle images that may be too
925 * large to be represented by a single texture.
926 *
bsalomon@google.com5782d712011-01-21 21:03:59 +0000927 * internalDrawBitmap assumes that the specified bitmap will fit in a texture
928 * and that non-texture portion of the GrPaint has already been setup.
reed@google.comac10a2d2010-12-22 21:39:39 +0000929 */
930void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
931 const SkBitmap& bitmap,
932 const SkIRect& srcRect,
933 const SkMatrix& m,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000934 GrPaint* grPaint) {
reed@google.com02a7e6c2011-01-28 21:21:49 +0000935 SkASSERT(bitmap.width() <= fContext->getMaxTextureDimension() &&
936 bitmap.height() <= fContext->getMaxTextureDimension());
reed@google.comac10a2d2010-12-22 21:39:39 +0000937
938 SkAutoLockPixels alp(bitmap);
939 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
940 return;
941 }
942
bsalomon@google.com5782d712011-01-21 21:03:59 +0000943 grPaint->fSampler.setWrapX(GrSamplerState::kClamp_WrapMode);
944 grPaint->fSampler.setWrapY(GrSamplerState::kClamp_WrapMode);
945 grPaint->fSampler.setSampleMode(GrSamplerState::kNormal_SampleMode);
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000946 grPaint->fSampler.setMatrix(GrMatrix::I());
reed@google.comac10a2d2010-12-22 21:39:39 +0000947
948 GrTexture* texture;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000949 SkAutoCachedTexture act(this, bitmap, grPaint->fSampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000950 if (NULL == texture) {
951 return;
952 }
953
bsalomon@google.com5782d712011-01-21 21:03:59 +0000954 grPaint->setTexture(texture);
reed@google.com46799cd2011-02-22 20:56:26 +0000955
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000956 GrRect dstRect(0, 0, GrIntToScalar(srcRect.width()), GrIntToScalar(srcRect.height()));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000957 GrRect paintRect;
958 paintRect.setLTRB(GrFixedToScalar((srcRect.fLeft << 16) / bitmap.width()),
959 GrFixedToScalar((srcRect.fTop << 16) / bitmap.height()),
960 GrFixedToScalar((srcRect.fRight << 16) / bitmap.width()),
961 GrFixedToScalar((srcRect.fBottom << 16) / bitmap.height()));
reed@google.comac10a2d2010-12-22 21:39:39 +0000962
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000963 GrMatrix grMat;
964 SkGr::SkMatrix2GrMatrix(m, &grMat);
reed@google.comac10a2d2010-12-22 21:39:39 +0000965
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000966 fContext->drawRectToRect(*grPaint, dstRect, paintRect, &grMat);
reed@google.comac10a2d2010-12-22 21:39:39 +0000967}
968
969void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
970 int left, int top, const SkPaint& paint) {
971 CHECK_SHOULD_DRAW(draw);
972
973 SkAutoLockPixels alp(bitmap);
974 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
975 return;
976 }
977
bsalomon@google.com5782d712011-01-21 21:03:59 +0000978 GrPaint grPaint;
979 if(!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
980 return;
981 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000982
bsalomon@google.com5782d712011-01-21 21:03:59 +0000983 GrAutoMatrix avm(fContext, GrMatrix::I());
984
985 GrTexture* texture;
986 grPaint.fSampler.setClampNoFilter();
987 SkAutoCachedTexture act(this, bitmap, grPaint.fSampler, &texture);
988
bsalomon@google.com5782d712011-01-21 21:03:59 +0000989 grPaint.setTexture(texture);
990
bsalomon@google.com5782d712011-01-21 21:03:59 +0000991 fContext->drawRectToRect(grPaint,
992 GrRect(GrIntToScalar(left), GrIntToScalar(top),
993 GrIntToScalar(left + bitmap.width()),
994 GrIntToScalar(top + bitmap.height())),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000995 GrRect(0, 0, GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +0000996}
997
998void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
999 int x, int y, const SkPaint& paint) {
1000 CHECK_SHOULD_DRAW(draw);
1001
bsalomon@google.com5782d712011-01-21 21:03:59 +00001002 GrPaint grPaint;
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001003 if (!((SkGpuDevice*)dev)->bindDeviceAsTexture(&grPaint) ||
bsalomon@google.com5782d712011-01-21 21:03:59 +00001004 !this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
1005 return;
reed@google.comac10a2d2010-12-22 21:39:39 +00001006 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001007
1008 SkASSERT(NULL != grPaint.getTexture());
1009
1010 const SkBitmap& bm = dev->accessBitmap(false);
1011 int w = bm.width();
1012 int h = bm.height();
1013
1014 GrAutoMatrix avm(fContext, GrMatrix::I());
1015
1016 grPaint.fSampler.setClampNoFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +00001017
1018 fContext->drawRectToRect(grPaint,
reed@google.com1a2e8d22011-01-21 22:08:29 +00001019 GrRect(GrIntToScalar(x),
1020 GrIntToScalar(y),
1021 GrIntToScalar(x + w),
bsalomon@google.com5782d712011-01-21 21:03:59 +00001022 GrIntToScalar(y + h)),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001023 GrRect(0, 0, GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001024}
1025
1026///////////////////////////////////////////////////////////////////////////////
1027
1028// must be in SkCanvas::VertexMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +00001029static const GrPrimitiveType gVertexMode2PrimitiveType[] = {
1030 kTriangles_PrimitiveType,
1031 kTriangleStrip_PrimitiveType,
1032 kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +00001033};
1034
1035void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
1036 int vertexCount, const SkPoint vertices[],
1037 const SkPoint texs[], const SkColor colors[],
1038 SkXfermode* xmode,
1039 const uint16_t indices[], int indexCount,
1040 const SkPaint& paint) {
1041 CHECK_SHOULD_DRAW(draw);
1042
bsalomon@google.com5782d712011-01-21 21:03:59 +00001043 GrPaint grPaint;
1044 SkAutoCachedTexture act;
1045 // we ignore the shader if texs is null.
1046 if (NULL == texs) {
1047 if (!this->skPaint2GrPaintNoShader(paint, false, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001048 return;
1049 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001050 } else {
reed@google.com1a2e8d22011-01-21 22:08:29 +00001051 if (!this->skPaint2GrPaintShader(paint, &act,
1052 *draw.fMatrix,
bsalomon@google.com5782d712011-01-21 21:03:59 +00001053 &grPaint)) {
1054 return;
1055 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001056 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001057
1058 if (NULL != xmode && NULL != texs && NULL != colors) {
1059 SkXfermode::Mode mode;
1060 if (!SkXfermode::IsMode(xmode, &mode) ||
1061 SkXfermode::kMultiply_Mode != mode) {
1062 SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
1063#if 0
1064 return
1065#endif
1066 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001067 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001068
1069#if SK_SCALAR_IS_GR_SCALAR
1070 // even if GrColor and SkColor byte offsets match we need
1071 // to perform pre-multiply.
1072 if (NULL == colors) {
1073 fContext->drawVertices(grPaint,
1074 gVertexMode2PrimitiveType[vmode],
1075 vertexCount,
1076 (GrPoint*) vertices,
1077 (GrPoint*) texs,
1078 NULL,
1079 indices,
1080 indexCount);
1081 } else
1082#endif
1083 {
1084 SkTexCoordSource texSrc(texs);
1085 SkColorSource colSrc(colors);
1086 SkIndexSource idxSrc(indices, indexCount);
1087
1088 fContext->drawCustomVertices(grPaint,
1089 gVertexMode2PrimitiveType[vmode],
1090 SkPositionSource(vertices, vertexCount),
1091 (NULL == texs) ? NULL : &texSrc,
1092 (NULL == colors) ? NULL : &colSrc,
1093 (NULL == indices) ? NULL : &idxSrc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001094 }
1095}
1096
1097///////////////////////////////////////////////////////////////////////////////
1098
1099static void GlyphCacheAuxProc(void* data) {
1100 delete (GrFontScaler*)data;
1101}
1102
1103static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) {
1104 void* auxData;
1105 GrFontScaler* scaler = NULL;
1106 if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
1107 scaler = (GrFontScaler*)auxData;
1108 }
1109 if (NULL == scaler) {
1110 scaler = new SkGrFontScaler(cache);
1111 cache->setAuxProc(GlyphCacheAuxProc, scaler);
1112 }
1113 return scaler;
1114}
1115
1116static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
1117 SkFixed fx, SkFixed fy,
1118 const SkGlyph& glyph) {
1119 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1120
1121 GrSkDrawProcs* procs = (GrSkDrawProcs*)state.fDraw->fProcs;
1122
1123 if (NULL == procs->fFontScaler) {
1124 procs->fFontScaler = get_gr_font_scaler(state.fCache);
1125 }
reed@google.com39ce0ac2011-04-08 15:42:19 +00001126
1127 /*
1128 * Skia calls us with fx,fy already biased by 1/2. It does this to speed
1129 * up rounding these, so that all of its procs (like us) can just call
1130 * SkFixedFloor and get the "rounded" value.
1131 *
1132 * We take advantage of that for fx, where we pass a rounded value, but
1133 * we want the fractional fy, so we have to unbias it first.
1134 */
reed@google.comac10a2d2010-12-22 21:39:39 +00001135 procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0),
reed@google.com39ce0ac2011-04-08 15:42:19 +00001136 SkIntToFixed(SkFixedFloor(fx)),
1137 fy - SK_FixedHalf,
reed@google.comac10a2d2010-12-22 21:39:39 +00001138 procs->fFontScaler);
1139}
1140
bsalomon@google.com5782d712011-01-21 21:03:59 +00001141SkDrawProcs* SkGpuDevice::initDrawForText(GrTextContext* context) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001142
1143 // deferred allocation
1144 if (NULL == fDrawProcs) {
1145 fDrawProcs = new GrSkDrawProcs;
1146 fDrawProcs->fD1GProc = SkGPU_Draw1Glyph;
1147 fDrawProcs->fContext = fContext;
1148 }
1149
1150 // init our (and GL's) state
1151 fDrawProcs->fTextContext = context;
1152 fDrawProcs->fFontScaler = NULL;
1153 return fDrawProcs;
1154}
1155
1156void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
1157 size_t byteLength, SkScalar x, SkScalar y,
1158 const SkPaint& paint) {
1159 CHECK_SHOULD_DRAW(draw);
1160
1161 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1162 // this guy will just call our drawPath()
1163 draw.drawText((const char*)text, byteLength, x, y, paint);
1164 } else {
1165 SkAutoExtMatrix aem(draw.fExtMatrix);
1166 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001167
1168 GrPaint grPaint;
1169 SkAutoCachedTexture act;
1170
1171 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1172 return;
1173 }
1174 GrTextContext context(fContext, grPaint, aem.extMatrix());
1175 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001176 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
1177 }
1178}
1179
1180void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
1181 size_t byteLength, const SkScalar pos[],
1182 SkScalar constY, int scalarsPerPos,
1183 const SkPaint& paint) {
1184 CHECK_SHOULD_DRAW(draw);
1185
1186 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1187 // this guy will just call our drawPath()
1188 draw.drawPosText((const char*)text, byteLength, pos, constY,
1189 scalarsPerPos, paint);
1190 } else {
1191 SkAutoExtMatrix aem(draw.fExtMatrix);
1192 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001193
1194 GrPaint grPaint;
1195 SkAutoCachedTexture act;
1196 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1197 return;
1198 }
1199
1200 GrTextContext context(fContext, grPaint, aem.extMatrix());
1201 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001202 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
1203 scalarsPerPos, paint);
1204 }
1205}
1206
1207void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
1208 size_t len, const SkPath& path,
1209 const SkMatrix* m, const SkPaint& paint) {
1210 CHECK_SHOULD_DRAW(draw);
1211
1212 SkASSERT(draw.fDevice == this);
1213 draw.drawTextOnPath((const char*)text, len, path, m, paint);
1214}
1215
1216///////////////////////////////////////////////////////////////////////////////
1217
reed@google.comf67e4cf2011-03-15 20:56:58 +00001218bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
1219 if (!paint.isLCDRenderText()) {
1220 // we're cool with the paint as is
1221 return false;
1222 }
1223
1224 if (paint.getShader() ||
1225 paint.getXfermode() || // unless its srcover
1226 paint.getMaskFilter() ||
1227 paint.getRasterizer() ||
1228 paint.getColorFilter() ||
1229 paint.getPathEffect() ||
1230 paint.isFakeBoldText() ||
1231 paint.getStyle() != SkPaint::kFill_Style) {
1232 // turn off lcd
1233 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
1234 flags->fHinting = paint.getHinting();
1235 return true;
1236 }
1237 // we're cool with the paint as is
1238 return false;
1239}
1240
1241///////////////////////////////////////////////////////////////////////////////
1242
reed@google.comac10a2d2010-12-22 21:39:39 +00001243SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001244 const GrSamplerState& sampler,
1245 GrTexture** texture,
1246 bool forDeviceRenderTarget) {
1247 GrTexture* newTexture = NULL;
1248 GrTextureEntry* entry = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +00001249 GrContext* ctx = this->context();
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001250
reed@google.comac10a2d2010-12-22 21:39:39 +00001251 if (forDeviceRenderTarget) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001252 const GrTextureDesc desc = {
1253 kRenderTarget_GrTextureFlagBit,
1254 kNone_GrAALevel,
1255 bitmap.width(),
1256 bitmap.height(),
1257 SkGr::Bitmap2PixelConfig(bitmap)
1258 };
1259 entry = ctx->lockKeylessTexture(desc, sampler);
reed@google.comac10a2d2010-12-22 21:39:39 +00001260 } else {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001261 uint32_t p0, p1;
reed@google.comac10a2d2010-12-22 21:39:39 +00001262 p0 = bitmap.getGenerationID();
1263 p1 = bitmap.pixelRefOffset();
reed@google.comac10a2d2010-12-22 21:39:39 +00001264
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001265 GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
1266 entry = ctx->findAndLockTexture(&key, sampler);
reed@google.comac10a2d2010-12-22 21:39:39 +00001267
reed@google.comac10a2d2010-12-22 21:39:39 +00001268 if (NULL == entry) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001269 entry = sk_gr_create_bitmap_texture(ctx, &key, sampler, bitmap);
1270 if (NULL == entry) {
1271 GrPrintf("---- failed to create texture for cache [%d %d]\n",
1272 bitmap.width(), bitmap.height());
1273 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001274 }
1275 }
1276
1277 if (NULL != entry) {
1278 newTexture = entry->texture();
reed@google.comac10a2d2010-12-22 21:39:39 +00001279 if (texture) {
1280 *texture = newTexture;
1281 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001282 }
1283 return (TexCache*)entry;
1284}
1285
1286void SkGpuDevice::unlockCachedTexture(TexCache* cache) {
1287 this->context()->unlockTexture((GrTextureEntry*)cache);
1288}
1289
reed@google.com7b201d22011-01-11 18:59:23 +00001290///////////////////////////////////////////////////////////////////////////////
1291
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001292SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context,
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001293 GrRenderTarget* rootRenderTarget) {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001294 GrAssert(NULL != context);
1295 GrAssert(NULL != rootRenderTarget);
1296
1297 // check this now rather than passing this value to SkGpuDevice cons.
1298 // we want the rt that is bound *now* in the 3D API, not the one
1299 // at the time of newDevice.
1300 if (SkGpuDevice::Current3DApiRenderTarget() == rootRenderTarget) {
1301 fRootRenderTarget = context->createRenderTargetFrom3DApiState();
1302 } else {
1303 fRootRenderTarget = rootRenderTarget;
1304 rootRenderTarget->ref();
1305 }
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001306
1307 fContext = context;
reed@google.com7b201d22011-01-11 18:59:23 +00001308 context->ref();
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001309
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001310 fRootTexture = NULL;
1311}
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001312
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001313SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context, GrTexture* rootRenderTargetTexture) {
1314 GrAssert(NULL != context);
1315 GrAssert(NULL != rootRenderTargetTexture);
1316 GrAssert(NULL != rootRenderTargetTexture->asRenderTarget());
1317
1318 fRootTexture = rootRenderTargetTexture;
1319 rootRenderTargetTexture->ref();
1320
1321 fRootRenderTarget = rootRenderTargetTexture->asRenderTarget();
1322 fRootRenderTarget->ref();
1323
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001324 fContext = context;
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001325 context->ref();
reed@google.com7b201d22011-01-11 18:59:23 +00001326}
1327
1328SkGpuDeviceFactory::~SkGpuDeviceFactory() {
1329 fContext->unref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001330 fRootRenderTarget->unref();
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001331 GrSafeUnref(fRootTexture);
reed@google.com7b201d22011-01-11 18:59:23 +00001332}
1333
1334SkDevice* SkGpuDeviceFactory::newDevice(SkCanvas*, SkBitmap::Config config,
1335 int width, int height,
1336 bool isOpaque, bool isLayer) {
1337 SkBitmap bm;
1338 bm.setConfig(config, width, height);
1339 bm.setIsOpaque(isOpaque);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001340 return new SkGpuDevice(fContext, bm, isLayer ? NULL : fRootRenderTarget);
reed@google.com7b201d22011-01-11 18:59:23 +00001341}