blob: 8818dc0b06e4e3d808db67f4cac3032af4b77cdb [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
reed@google.comac10a2d2010-12-22 21:39:39 +000042///////////////////////////////////////////////////////////////////////////////
43
44SkGpuDevice::SkAutoCachedTexture::
45 SkAutoCachedTexture(SkGpuDevice* device,
46 const SkBitmap& bitmap,
47 const GrSamplerState& sampler,
48 GrTexture** texture) {
49 GrAssert(texture);
50 fTex = NULL;
51 *texture = this->set(device, bitmap, sampler);
52}
53
54SkGpuDevice::SkAutoCachedTexture::SkAutoCachedTexture() {
55 fTex = NULL;
56}
57
58GrTexture* SkGpuDevice::SkAutoCachedTexture::set(SkGpuDevice* device,
59 const SkBitmap& bitmap,
60 const GrSamplerState& sampler) {
61 if (fTex) {
62 fDevice->unlockCachedTexture(fTex);
63 }
64 fDevice = device;
65 GrTexture* texture = (GrTexture*)bitmap.getTexture();
66 if (texture) {
67 // return the native texture
68 fTex = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +000069 } else {
70 // look it up in our cache
71 fTex = device->lockCachedTexture(bitmap, sampler, &texture, false);
72 }
73 return texture;
74}
75
76SkGpuDevice::SkAutoCachedTexture::~SkAutoCachedTexture() {
77 if (fTex) {
78 fDevice->unlockCachedTexture(fTex);
79 }
80}
81
82///////////////////////////////////////////////////////////////////////////////
83
84bool gDoTraceDraw;
85
86struct GrSkDrawProcs : public SkDrawProcs {
87public:
88 GrContext* fContext;
89 GrTextContext* fTextContext;
90 GrFontScaler* fFontScaler; // cached in the skia glyphcache
91};
92
93///////////////////////////////////////////////////////////////////////////////
94
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +000095GrRenderTarget* SkGpuDevice::Current3DApiRenderTarget() {
96 return (GrRenderTarget*) -1;
97}
98
99SkGpuDevice::SkGpuDevice(GrContext* context,
100 const SkBitmap& bitmap,
101 GrRenderTarget* renderTargetOrNull)
102 : SkDevice(NULL, bitmap, (NULL == renderTargetOrNull)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000103
104 fNeedPrepareRenderTarget = false;
105 fDrawProcs = NULL;
106
reed@google.com7b201d22011-01-11 18:59:23 +0000107 fContext = context;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000108 fContext->ref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000109
110 fCache = NULL;
111 fTexture = NULL;
112 fRenderTarget = NULL;
113 fNeedClear = false;
114
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000115 if (NULL == renderTargetOrNull) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000116 SkBitmap::Config c = bitmap.config();
117 if (c != SkBitmap::kRGB_565_Config) {
118 c = SkBitmap::kARGB_8888_Config;
119 }
120 SkBitmap bm;
121 bm.setConfig(c, this->width(), this->height());
122
123#if CACHE_LAYER_TEXTURES
124
125 fCache = this->lockCachedTexture(bm, GrSamplerState::ClampNoFilter(),
126 &fTexture, true);
127 if (fCache) {
128 SkASSERT(NULL != fTexture);
bsalomon@google.com1da07462011-03-10 14:51:57 +0000129 SkASSERT(NULL != fTexture->asRenderTarget());
reed@google.comac10a2d2010-12-22 21:39:39 +0000130 }
131#else
132 const GrGpu::TextureDesc desc = {
133 GrGpu::kRenderTarget_TextureFlag,
134 GrGpu::kNone_AALevel,
135 this->width(),
136 this->height(),
137 SkGr::Bitmap2PixelConfig(bm)
138 };
139
140 fTexture = fContext->createUncachedTexture(desc, NULL, 0);
141#endif
142 if (NULL != fTexture) {
143 fRenderTarget = fTexture->asRenderTarget();
144
145 GrAssert(NULL != fRenderTarget);
146
147 // we defer the actual clear until our gainFocus()
148 fNeedClear = true;
149
150 // wrap the bitmap with a pixelref to expose our texture
151 SkGrTexturePixelRef* pr = new SkGrTexturePixelRef(fTexture);
152 this->setPixelRef(pr, 0)->unref();
153 } else {
154 GrPrintf("--- failed to create gpu-offscreen [%d %d]\n",
155 this->width(), this->height());
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000156 GrAssert(false);
reed@google.comac10a2d2010-12-22 21:39:39 +0000157 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000158 } else {
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000159 if (Current3DApiRenderTarget() == renderTargetOrNull) {
160 fRenderTarget = fContext->createRenderTargetFrom3DApiState();
161 } else {
162 fRenderTarget = renderTargetOrNull;
163 fRenderTarget->ref();
164 }
165 SkGrRenderTargetPixelRef* pr = new SkGrRenderTargetPixelRef(fRenderTarget);
166 this->setPixelRef(pr, 0)->unref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000167 }
168}
169
170SkGpuDevice::~SkGpuDevice() {
171 if (fDrawProcs) {
172 delete fDrawProcs;
173 }
174
175 if (fCache) {
176 GrAssert(NULL != fTexture);
177 GrAssert(fRenderTarget == fTexture->asRenderTarget());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000178 fContext->unlockTexture((GrTextureEntry*)fCache);
reed@google.comac10a2d2010-12-22 21:39:39 +0000179 } else if (NULL != fTexture) {
180 GrAssert(!CACHE_LAYER_TEXTURES);
181 GrAssert(fRenderTarget == fTexture->asRenderTarget());
182 fTexture->unref();
183 } else if (NULL != fRenderTarget) {
184 fRenderTarget->unref();
185 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000186 fContext->unref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000187}
188
reed@google.comac10a2d2010-12-22 21:39:39 +0000189intptr_t SkGpuDevice::getLayerTextureHandle() const {
190 if (fTexture) {
191 return fTexture->getTextureHandle();
192 } else {
193 return 0;
194 }
195}
mike@reedtribe.orgea4ac972011-04-26 11:48:33 +0000196
197SkDeviceFactory* SkGpuDevice::onNewDeviceFactory() {
198 return SkNEW_ARGS(SkGpuDeviceFactory, (fContext, fRenderTarget));
199}
200
reed@google.comac10a2d2010-12-22 21:39:39 +0000201///////////////////////////////////////////////////////////////////////////////
202
203void SkGpuDevice::makeRenderTargetCurrent() {
204 fContext->setRenderTarget(fRenderTarget);
205 fContext->flush(true);
206 fNeedPrepareRenderTarget = true;
207}
208
209///////////////////////////////////////////////////////////////////////////////
210
211bool SkGpuDevice::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
212 SkIRect bounds;
213 bounds.set(0, 0, this->width(), this->height());
214 if (!bounds.intersect(srcRect)) {
215 return false;
216 }
217
218 const int w = bounds.width();
219 const int h = bounds.height();
220 SkBitmap tmp;
221 // note we explicitly specify our rowBytes to be snug (no gap between rows)
222 tmp.setConfig(SkBitmap::kARGB_8888_Config, w, h, w * 4);
223 if (!tmp.allocPixels()) {
224 return false;
225 }
226
Scroggo813c33c2011-04-07 20:56:21 +0000227 tmp.lockPixels();
reed@google.comac10a2d2010-12-22 21:39:39 +0000228
Scroggoeb176032011-04-07 21:11:49 +0000229 bool read = fContext->readRenderTargetPixels(fRenderTarget,
230 bounds.fLeft, bounds.fTop,
231 bounds.width(), bounds.height(),
232 kRGBA_8888_GrPixelConfig,
233 tmp.getPixels());
Scroggo813c33c2011-04-07 20:56:21 +0000234 tmp.unlockPixels();
235 if (!read) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000236 return false;
237 }
238
239 tmp.swap(*bitmap);
240 return true;
241}
242
243void SkGpuDevice::writePixels(const SkBitmap& bitmap, int x, int y) {
244 SkAutoLockPixels alp(bitmap);
245 if (!bitmap.readyToDraw()) {
246 return;
247 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000248 GrPixelConfig config = SkGr::BitmapConfig2PixelConfig(bitmap.config(),
249 bitmap.isOpaque());
reed@google.comac10a2d2010-12-22 21:39:39 +0000250 fContext->setRenderTarget(fRenderTarget);
251 // we aren't setting the clip or matrix, so mark as dirty
252 // we don't need to set them for this call and don't have them anyway
253 fNeedPrepareRenderTarget = true;
254
255 fContext->writePixels(x, y, bitmap.width(), bitmap.height(),
256 config, bitmap.getPixels(), bitmap.rowBytes());
257}
258
259///////////////////////////////////////////////////////////////////////////////
260
261static void convert_matrixclip(GrContext* context, const SkMatrix& matrix,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000262 const SkClipStack& clipStack,
reed@google.com6f8f2922011-03-04 22:27:10 +0000263 const SkRegion& clipRegion,
264 const SkIPoint& origin) {
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000265 context->setMatrix(matrix);
reed@google.comac10a2d2010-12-22 21:39:39 +0000266
267 SkGrClipIterator iter;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000268 iter.reset(clipStack);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000269 const SkIRect& skBounds = clipRegion.getBounds();
270 GrRect bounds;
271 bounds.setLTRB(GrIntToScalar(skBounds.fLeft),
272 GrIntToScalar(skBounds.fTop),
273 GrIntToScalar(skBounds.fRight),
274 GrIntToScalar(skBounds.fBottom));
reed@google.com6f8f2922011-03-04 22:27:10 +0000275 GrClip grc(&iter, GrIntToScalar(-origin.x()), GrIntToScalar(-origin.y()),
276 &bounds);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000277 context->setClip(grc);
reed@google.comac10a2d2010-12-22 21:39:39 +0000278}
279
280// call this ever each draw call, to ensure that the context reflects our state,
281// and not the state from some other canvas/device
282void SkGpuDevice::prepareRenderTarget(const SkDraw& draw) {
283 if (fNeedPrepareRenderTarget ||
bsalomon@google.com5782d712011-01-21 21:03:59 +0000284 fContext->getRenderTarget() != fRenderTarget) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000285
286 fContext->setRenderTarget(fRenderTarget);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000287 SkASSERT(draw.fClipStack);
288 convert_matrixclip(fContext, *draw.fMatrix,
reed@google.com6f8f2922011-03-04 22:27:10 +0000289 *draw.fClipStack, *draw.fClip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000290 fNeedPrepareRenderTarget = false;
291 }
292}
293
reed@google.com46799cd2011-02-22 20:56:26 +0000294void SkGpuDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& clip,
295 const SkClipStack& clipStack) {
296 this->INHERITED::setMatrixClip(matrix, clip, clipStack);
bsalomon@google.coma7bf6e22011-04-11 19:20:46 +0000297 // We don't need to set them now because the context may not reflect this device.
298 fNeedPrepareRenderTarget = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000299}
300
301void SkGpuDevice::gainFocus(SkCanvas* canvas, const SkMatrix& matrix,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000302 const SkRegion& clip, const SkClipStack& clipStack) {
303
reed@google.comac10a2d2010-12-22 21:39:39 +0000304 fContext->setRenderTarget(fRenderTarget);
305
bsalomon@google.comd302f142011-03-03 13:54:13 +0000306 this->INHERITED::gainFocus(canvas, matrix, clip, clipStack);
reed@google.comac10a2d2010-12-22 21:39:39 +0000307
reed@google.com6f8f2922011-03-04 22:27:10 +0000308 convert_matrixclip(fContext, matrix, clipStack, clip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000309
310 if (fNeedClear) {
bsalomon@google.com31a58402011-04-27 21:00:02 +0000311 fContext->clear(NULL, 0x0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000312 fNeedClear = false;
313 }
314}
315
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000316bool SkGpuDevice::bindDeviceAsTexture(GrPaint* paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000317 if (NULL != fTexture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000318 paint->setTexture(fTexture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000319 return true;
320 }
321 return false;
322}
323
324///////////////////////////////////////////////////////////////////////////////
325
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000326SK_COMPILE_ASSERT(SkShader::kNone_BitmapType == 0, shader_type_mismatch);
327SK_COMPILE_ASSERT(SkShader::kDefault_BitmapType == 1, shader_type_mismatch);
328SK_COMPILE_ASSERT(SkShader::kRadial_BitmapType == 2, shader_type_mismatch);
329SK_COMPILE_ASSERT(SkShader::kSweep_BitmapType == 3, shader_type_mismatch);
330SK_COMPILE_ASSERT(SkShader::kTwoPointRadial_BitmapType == 4,
331 shader_type_mismatch);
332SK_COMPILE_ASSERT(SkShader::kLast_BitmapType == 4, shader_type_mismatch);
reed@google.comac10a2d2010-12-22 21:39:39 +0000333
bsalomon@google.com5782d712011-01-21 21:03:59 +0000334static const GrSamplerState::SampleMode sk_bmp_type_to_sample_mode[] = {
335 (GrSamplerState::SampleMode) -1, // kNone_BitmapType
336 GrSamplerState::kNormal_SampleMode, // kDefault_BitmapType
337 GrSamplerState::kRadial_SampleMode, // kRadial_BitmapType
338 GrSamplerState::kSweep_SampleMode, // kSweep_BitmapType
339 GrSamplerState::kRadial2_SampleMode, // kTwoPointRadial_BitmapType
340};
341
342bool SkGpuDevice::skPaint2GrPaintNoShader(const SkPaint& skPaint,
343 bool justAlpha,
344 GrPaint* grPaint) {
345
346 grPaint->fDither = skPaint.isDither();
347 grPaint->fAntiAlias = skPaint.isAntiAlias();
348
349 SkXfermode::Coeff sm = SkXfermode::kOne_Coeff;
350 SkXfermode::Coeff dm = SkXfermode::kISA_Coeff;
351
352 SkXfermode* mode = skPaint.getXfermode();
353 if (mode) {
354 if (!mode->asCoeff(&sm, &dm)) {
reed@google.com1a2e8d22011-01-21 22:08:29 +0000355 SkDEBUGCODE(SkDebugf("Unsupported xfer mode.\n");)
bsalomon@google.com5782d712011-01-21 21:03:59 +0000356#if 0
357 return false;
358#endif
359 }
360 }
361 grPaint->fSrcBlendCoeff = sk_blend_to_grblend(sm);
362 grPaint->fDstBlendCoeff = sk_blend_to_grblend(dm);
363
364 if (justAlpha) {
365 uint8_t alpha = skPaint.getAlpha();
366 grPaint->fColor = GrColorPackRGBA(alpha, alpha, alpha, alpha);
367 } else {
368 grPaint->fColor = SkGr::SkColor2GrColor(skPaint.getColor());
369 grPaint->setTexture(NULL);
370 }
371 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000372}
373
bsalomon@google.com5782d712011-01-21 21:03:59 +0000374bool SkGpuDevice::skPaint2GrPaintShader(const SkPaint& skPaint,
375 SkAutoCachedTexture* act,
376 const SkMatrix& ctm,
377 GrPaint* grPaint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000378
bsalomon@google.com5782d712011-01-21 21:03:59 +0000379 SkASSERT(NULL != act);
reed@google.comac10a2d2010-12-22 21:39:39 +0000380
bsalomon@google.com5782d712011-01-21 21:03:59 +0000381 SkShader* shader = skPaint.getShader();
reed@google.comac10a2d2010-12-22 21:39:39 +0000382 if (NULL == shader) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000383 return this->skPaint2GrPaintNoShader(skPaint, false, grPaint);
384 grPaint->setTexture(NULL);
385 return true;
386 } else if (!this->skPaint2GrPaintNoShader(skPaint, true, grPaint)) {
387 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000388 }
389
bsalomon@google.com5782d712011-01-21 21:03:59 +0000390 SkPaint noAlphaPaint(skPaint);
391 noAlphaPaint.setAlpha(255);
392 shader->setContext(this->accessBitmap(false), noAlphaPaint, ctm);
reed@google.comac10a2d2010-12-22 21:39:39 +0000393
reed@google.comac10a2d2010-12-22 21:39:39 +0000394 SkBitmap bitmap;
395 SkMatrix matrix;
396 SkShader::TileMode tileModes[2];
397 SkScalar twoPointParams[3];
398 SkShader::BitmapType bmptype = shader->asABitmap(&bitmap, &matrix,
399 tileModes, twoPointParams);
400
bsalomon@google.com5782d712011-01-21 21:03:59 +0000401 GrSamplerState::SampleMode sampleMode = sk_bmp_type_to_sample_mode[bmptype];
402 if (-1 == sampleMode) {
403 SkDebugf("shader->asABitmap() == kNone_BitmapType\n");
404 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000405 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000406 grPaint->fSampler.setSampleMode(sampleMode);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000407 if (skPaint.isFilterBitmap()) {
408 grPaint->fSampler.setFilter(GrSamplerState::kBilinear_Filter);
409 } else {
410 grPaint->fSampler.setFilter(GrSamplerState::kNearest_Filter);
411 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000412 grPaint->fSampler.setWrapX(sk_tile_mode_to_grwrap(tileModes[0]));
413 grPaint->fSampler.setWrapY(sk_tile_mode_to_grwrap(tileModes[1]));
reed@google.comac10a2d2010-12-22 21:39:39 +0000414 if (GrSamplerState::kRadial2_SampleMode == sampleMode) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000415 grPaint->fSampler.setRadial2Params(twoPointParams[0],
416 twoPointParams[1],
417 twoPointParams[2] < 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000418 }
419
bsalomon@google.com5782d712011-01-21 21:03:59 +0000420 GrTexture* texture = act->set(this, bitmap, grPaint->fSampler);
reed@google.comac10a2d2010-12-22 21:39:39 +0000421 if (NULL == texture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000422 SkDebugf("Couldn't convert bitmap to texture.\n");
423 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000424 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000425 grPaint->setTexture(texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000426
427 // since our texture coords will be in local space, we wack the texture
428 // matrix to map them back into 0...1 before we load it
429 SkMatrix localM;
430 if (shader->getLocalMatrix(&localM)) {
431 SkMatrix inverse;
432 if (localM.invert(&inverse)) {
433 matrix.preConcat(inverse);
434 }
435 }
436 if (SkShader::kDefault_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000437 GrScalar sx = GrFixedToScalar(GR_Fixed1 / bitmap.width());
438 GrScalar sy = GrFixedToScalar(GR_Fixed1 / bitmap.height());
reed@google.comac10a2d2010-12-22 21:39:39 +0000439 matrix.postScale(sx, sy);
reed@google.comac10a2d2010-12-22 21:39:39 +0000440 } else if (SkShader::kRadial_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000441 GrScalar s = GrFixedToScalar(GR_Fixed1 / bitmap.width());
reed@google.comac10a2d2010-12-22 21:39:39 +0000442 matrix.postScale(s, s);
443 }
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000444 grPaint->fSampler.setMatrix(matrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000445
446 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000447}
448
449///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com5782d712011-01-21 21:03:59 +0000450
451class SkPositionSource {
452public:
453 SkPositionSource(const SkPoint* points, int count)
454 : fPoints(points), fCount(count) {}
455
456 int count() const { return fCount; }
457
458 void writeValue(int i, GrPoint* dstPosition) const {
459 SkASSERT(i < fCount);
460 dstPosition->fX = SkScalarToGrScalar(fPoints[i].fX);
461 dstPosition->fY = SkScalarToGrScalar(fPoints[i].fY);
462 }
463private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000464 const SkPoint* fPoints;
bsalomon@google.com19628322011-02-03 21:30:17 +0000465 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000466};
467
468class SkTexCoordSource {
469public:
470 SkTexCoordSource(const SkPoint* coords)
471 : fCoords(coords) {}
472
473 void writeValue(int i, GrPoint* dstCoord) const {
474 dstCoord->fX = SkScalarToGrScalar(fCoords[i].fX);
475 dstCoord->fY = SkScalarToGrScalar(fCoords[i].fY);
476 }
477private:
478 const SkPoint* fCoords;
479};
480
481class SkColorSource {
482public:
483 SkColorSource(const SkColor* colors) : fColors(colors) {}
484
485 void writeValue(int i, GrColor* dstColor) const {
486 *dstColor = SkGr::SkColor2GrColor(fColors[i]);
487 }
488private:
489 const SkColor* fColors;
490};
491
492class SkIndexSource {
493public:
494 SkIndexSource(const uint16_t* indices, int count)
495 : fIndices(indices), fCount(count) {
496 }
497
498 int count() const { return fCount; }
499
500 void writeValue(int i, uint16_t* dstIndex) const {
501 *dstIndex = fIndices[i];
502 }
503
504private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000505 const uint16_t* fIndices;
bsalomon@google.com19628322011-02-03 21:30:17 +0000506 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000507};
508
509///////////////////////////////////////////////////////////////////////////////
510
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000511#if 0 // not currently being used so don't compile,
512
bsalomon@google.com5782d712011-01-21 21:03:59 +0000513// can be used for positions or texture coordinates
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000514
bsalomon@google.com5782d712011-01-21 21:03:59 +0000515class SkRectFanSource {
516public:
517 SkRectFanSource(const SkRect& rect) : fRect(rect) {}
518
519 int count() const { return 4; }
520
521 void writeValue(int i, GrPoint* dstPoint) const {
522 SkASSERT(i < 4);
523 dstPoint->fX = SkScalarToGrScalar((i % 3) ? fRect.fRight :
524 fRect.fLeft);
525 dstPoint->fY = SkScalarToGrScalar((i < 2) ? fRect.fTop :
526 fRect.fBottom);
527 }
528private:
529 const SkRect& fRect;
530};
531
532class SkIRectFanSource {
533public:
534 SkIRectFanSource(const SkIRect& rect) : fRect(rect) {}
535
536 int count() const { return 4; }
537
538 void writeValue(int i, GrPoint* dstPoint) const {
539 SkASSERT(i < 4);
540 dstPoint->fX = (i % 3) ? GrIntToScalar(fRect.fRight) :
541 GrIntToScalar(fRect.fLeft);
542 dstPoint->fY = (i < 2) ? GrIntToScalar(fRect.fTop) :
543 GrIntToScalar(fRect.fBottom);
544 }
545private:
546 const SkIRect& fRect;
547};
548
549class SkMatRectFanSource {
550public:
551 SkMatRectFanSource(const SkRect& rect, const SkMatrix& matrix)
552 : fRect(rect), fMatrix(matrix) {}
553
554 int count() const { return 4; }
555
556 void writeValue(int i, GrPoint* dstPoint) const {
557 SkASSERT(i < 4);
558
559#if SK_SCALAR_IS_GR_SCALAR
560 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
561 (i < 2) ? fRect.fTop : fRect.fBottom,
562 (SkPoint*)dstPoint);
563#else
564 SkPoint dst;
565 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
566 (i < 2) ? fRect.fTop : fRect.fBottom,
567 &dst);
568 dstPoint->fX = SkScalarToGrScalar(dst.fX);
569 dstPoint->fY = SkScalarToGrScalar(dst.fY);
570#endif
571 }
572private:
573 const SkRect& fRect;
574 const SkMatrix& fMatrix;
575};
576
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000577#endif
578
reed@google.comac10a2d2010-12-22 21:39:39 +0000579///////////////////////////////////////////////////////////////////////////////
580
bsalomon@google.com398109c2011-04-14 18:40:27 +0000581void SkGpuDevice::clear(SkColor color) {
bsalomon@google.com31a58402011-04-27 21:00:02 +0000582 fContext->clear(NULL, color);
bsalomon@google.com398109c2011-04-14 18:40:27 +0000583}
584
reed@google.comac10a2d2010-12-22 21:39:39 +0000585void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
586 CHECK_SHOULD_DRAW(draw);
587
bsalomon@google.com5782d712011-01-21 21:03:59 +0000588 GrPaint grPaint;
589 SkAutoCachedTexture act;
590 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000591 return;
592 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000593
594 fContext->drawPaint(grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000595}
596
597// must be in SkCanvas::PointMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +0000598static const GrPrimitiveType gPointMode2PrimtiveType[] = {
599 kPoints_PrimitiveType,
600 kLines_PrimitiveType,
601 kLineStrip_PrimitiveType
reed@google.comac10a2d2010-12-22 21:39:39 +0000602};
603
604void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000605 size_t count, const SkPoint pts[], const SkPaint& paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000606 CHECK_SHOULD_DRAW(draw);
607
608 SkScalar width = paint.getStrokeWidth();
609 if (width < 0) {
610 return;
611 }
612
613 // we only handle hairlines here, else we let the SkDraw call our drawPath()
614 if (width > 0) {
615 draw.drawPoints(mode, count, pts, paint, true);
616 return;
617 }
618
bsalomon@google.com5782d712011-01-21 21:03:59 +0000619 GrPaint grPaint;
620 SkAutoCachedTexture act;
621 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000622 return;
623 }
624
reed@google.comac10a2d2010-12-22 21:39:39 +0000625#if SK_SCALAR_IS_GR_SCALAR
bsalomon@google.com5782d712011-01-21 21:03:59 +0000626 fContext->drawVertices(grPaint,
627 gPointMode2PrimtiveType[mode],
628 count,
629 (GrPoint*)pts,
630 NULL,
631 NULL,
632 NULL,
633 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000634#else
bsalomon@google.com5782d712011-01-21 21:03:59 +0000635 fContext->drawCustomVertices(grPaint,
636 gPointMode2PrimtiveType[mode],
637 SkPositionSource(pts, count));
reed@google.comac10a2d2010-12-22 21:39:39 +0000638#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000639}
640
reed@google.comc9aa5872011-04-05 21:05:37 +0000641///////////////////////////////////////////////////////////////////////////////
642
reed@google.comac10a2d2010-12-22 21:39:39 +0000643void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
644 const SkPaint& paint) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000645 CHECK_SHOULD_DRAW(draw);
646
647 bool doStroke = paint.getStyle() == SkPaint::kStroke_Style;
648 SkScalar width = paint.getStrokeWidth();
649
650 /*
651 We have special code for hairline strokes, miter-strokes, and fills.
652 Anything else we just call our path code.
653 */
654 bool usePath = doStroke && width > 0 &&
655 paint.getStrokeJoin() != SkPaint::kMiter_Join;
656 // another reason we might need to call drawPath...
657 if (paint.getMaskFilter()) {
658 usePath = true;
659 }
660
661 if (usePath) {
662 SkPath path;
663 path.addRect(rect);
664 this->drawPath(draw, path, paint, NULL, true);
665 return;
666 }
667
668 GrPaint grPaint;
669 SkAutoCachedTexture act;
670 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
671 return;
672 }
reed@google.com20efde72011-05-09 17:00:02 +0000673 fContext->drawRect(grPaint, rect, doStroke ? width : -1);
reed@google.comac10a2d2010-12-22 21:39:39 +0000674}
675
reed@google.com69302852011-02-16 18:08:07 +0000676#include "SkMaskFilter.h"
677#include "SkBounder.h"
678
reed@google.com69302852011-02-16 18:08:07 +0000679static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
680 SkMaskFilter* filter, const SkMatrix& matrix,
681 const SkRegion& clip, SkBounder* bounder,
682 GrPaint* grp) {
683 SkMask srcM, dstM;
684
685 if (!SkDraw::DrawToMask(path, &clip.getBounds(), filter, &matrix, &srcM,
686 SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
687 return false;
688 }
689
690 SkAutoMaskImage autoSrc(&srcM, false);
691
692 if (!filter->filterMask(&dstM, srcM, matrix, NULL)) {
693 return false;
694 }
695 // this will free-up dstM when we're done (allocated in filterMask())
696 SkAutoMaskImage autoDst(&dstM, false);
697
698 if (clip.quickReject(dstM.fBounds)) {
699 return false;
700 }
701 if (bounder && !bounder->doIRect(dstM.fBounds)) {
702 return false;
703 }
704
705 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
706 // the current clip (and identity matrix) and grpaint settings
707
reed@google.com0c219b62011-02-16 21:31:18 +0000708 GrAutoMatrix avm(context, GrMatrix::I());
reed@google.com69302852011-02-16 18:08:07 +0000709
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000710 const GrTextureDesc desc = {
711 kNone_GrTextureFlags,
712 kNone_GrAALevel,
reed@google.com69302852011-02-16 18:08:07 +0000713 dstM.fBounds.width(),
714 dstM.fBounds.height(),
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000715 kAlpha_8_GrPixelConfig
reed@google.com69302852011-02-16 18:08:07 +0000716 };
717
718 GrTexture* texture = context->createUncachedTexture(desc, dstM.fImage,
719 dstM.fRowBytes);
720 if (NULL == texture) {
721 return false;
722 }
723
reed@google.com0c219b62011-02-16 21:31:18 +0000724 grp->setTexture(texture);
725 texture->unref();
726 grp->fSampler.setClampNoFilter();
reed@google.com69302852011-02-16 18:08:07 +0000727
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000728 GrRect d;
729 d.setLTRB(GrIntToScalar(dstM.fBounds.fLeft),
reed@google.com0c219b62011-02-16 21:31:18 +0000730 GrIntToScalar(dstM.fBounds.fTop),
731 GrIntToScalar(dstM.fBounds.fRight),
732 GrIntToScalar(dstM.fBounds.fBottom));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000733 GrRect s;
734 s.setLTRB(0, 0, GR_Scalar1, GR_Scalar1);
735 context->drawRectToRect(*grp, d, s);
reed@google.com69302852011-02-16 18:08:07 +0000736 return true;
737}
reed@google.com69302852011-02-16 18:08:07 +0000738
reed@google.com0c219b62011-02-16 21:31:18 +0000739void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
reed@google.comac10a2d2010-12-22 21:39:39 +0000740 const SkPaint& paint, const SkMatrix* prePathMatrix,
741 bool pathIsMutable) {
742 CHECK_SHOULD_DRAW(draw);
743
bsalomon@google.com5782d712011-01-21 21:03:59 +0000744 GrPaint grPaint;
745 SkAutoCachedTexture act;
746 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000747 return;
748 }
749
reed@google.com0c219b62011-02-16 21:31:18 +0000750 // BEGIN lift from SkDraw::drawPath()
751
752 SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
753 bool doFill = true;
754 SkPath tmpPath;
reed@google.comac10a2d2010-12-22 21:39:39 +0000755
756 if (prePathMatrix) {
reed@google.come3445642011-02-16 23:20:39 +0000757 SkPath* result = pathPtr;
reed@google.com0c219b62011-02-16 21:31:18 +0000758
reed@google.come3445642011-02-16 23:20:39 +0000759 if (!pathIsMutable) {
760 result = &tmpPath;
761 pathIsMutable = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000762 }
reed@google.come3445642011-02-16 23:20:39 +0000763 // should I push prePathMatrix on our MV stack temporarily, instead
764 // of applying it here? See SkDraw.cpp
765 pathPtr->transform(*prePathMatrix, result);
766 pathPtr = result;
reed@google.comac10a2d2010-12-22 21:39:39 +0000767 }
reed@google.com0c219b62011-02-16 21:31:18 +0000768 // at this point we're done with prePathMatrix
769 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
reed@google.comac10a2d2010-12-22 21:39:39 +0000770
bsalomon@google.com04de7822011-03-25 18:04:43 +0000771 // This "if" is not part of the SkDraw::drawPath() lift.
772 // When we get a 1.0 wide stroke we hairline stroke it instead of creating
773 // a new stroked-path. This is motivated by canvas2D sites that draw
774 // lines as 1.0 wide stroked paths. We can consider doing an alpha-modulated-
775 // hairline for width < 1.0 when AA is enabled.
776 static const int gMatrixMask = ~(SkMatrix::kIdentity_Mask |
777 SkMatrix::kTranslate_Mask);
778 if (!paint.getPathEffect() &&
779 SkPaint::kStroke_Style == paint.getStyle() &&
780 !(draw.fMatrix->getType() & gMatrixMask) &&
781 SK_Scalar1 == paint.getStrokeWidth()) {
782 doFill = false;
783 }
784
785 if (doFill && (paint.getPathEffect() ||
786 paint.getStyle() != SkPaint::kFill_Style)) {
reed@google.com0c219b62011-02-16 21:31:18 +0000787 doFill = paint.getFillPath(*pathPtr, &tmpPath);
788 pathPtr = &tmpPath;
789 }
790
791 // END lift from SkDraw::drawPath()
792
reed@google.com69302852011-02-16 18:08:07 +0000793 if (paint.getMaskFilter()) {
reed@google.com0c219b62011-02-16 21:31:18 +0000794 // avoid possibly allocating a new path in transform if we can
795 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
796
797 // transform the path into device space
reed@google.come3445642011-02-16 23:20:39 +0000798 pathPtr->transform(*draw.fMatrix, devPathPtr);
reed@google.com0c219b62011-02-16 21:31:18 +0000799
800 drawWithMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
reed@google.com69302852011-02-16 18:08:07 +0000801 *draw.fMatrix, *draw.fClip, draw.fBounder, &grPaint);
802 return;
803 }
reed@google.com69302852011-02-16 18:08:07 +0000804
bsalomon@google.comffca4002011-02-22 20:34:01 +0000805 GrPathFill fill = kHairLine_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000806
reed@google.com0c219b62011-02-16 21:31:18 +0000807 if (doFill) {
808 switch (pathPtr->getFillType()) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000809 case SkPath::kWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000810 fill = kWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000811 break;
812 case SkPath::kEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000813 fill = kEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000814 break;
815 case SkPath::kInverseWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000816 fill = kInverseWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000817 break;
818 case SkPath::kInverseEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000819 fill = kInverseEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000820 break;
821 default:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000822 SkDebugf("Unsupported path fill type\n");
reed@google.comac10a2d2010-12-22 21:39:39 +0000823 return;
824 }
825 }
826
reed@google.com0c219b62011-02-16 21:31:18 +0000827 SkGrPathIter iter(*pathPtr);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000828 fContext->drawPath(grPaint, &iter, fill);
reed@google.comac10a2d2010-12-22 21:39:39 +0000829}
830
reed@google.comac10a2d2010-12-22 21:39:39 +0000831void SkGpuDevice::drawBitmap(const SkDraw& draw,
832 const SkBitmap& bitmap,
833 const SkIRect* srcRectPtr,
834 const SkMatrix& m,
835 const SkPaint& paint) {
836 CHECK_SHOULD_DRAW(draw);
837
838 SkIRect srcRect;
839 if (NULL == srcRectPtr) {
840 srcRect.set(0, 0, bitmap.width(), bitmap.height());
841 } else {
842 srcRect = *srcRectPtr;
843 }
844
bsalomon@google.com5782d712011-01-21 21:03:59 +0000845 GrPaint grPaint;
846 if (!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
847 return;
848 }
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000849 if (paint.isFilterBitmap()) {
850 grPaint.fSampler.setFilter(GrSamplerState::kBilinear_Filter);
851 } else {
852 grPaint.fSampler.setFilter(GrSamplerState::kNearest_Filter);
853 }
854
bsalomon@google.com5782d712011-01-21 21:03:59 +0000855
reed@google.com02a7e6c2011-01-28 21:21:49 +0000856 const int maxTextureDim = fContext->getMaxTextureDimension();
857 if (bitmap.getTexture() || (bitmap.width() <= maxTextureDim &&
858 bitmap.height() <= maxTextureDim)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000859 // take the fast case
bsalomon@google.com5782d712011-01-21 21:03:59 +0000860 this->internalDrawBitmap(draw, bitmap, srcRect, m, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000861 return;
862 }
863
864 // undo the translate done by SkCanvas
865 int DX = SkMax32(0, srcRect.fLeft);
866 int DY = SkMax32(0, srcRect.fTop);
867 // compute clip bounds in local coordinates
868 SkIRect clipRect;
869 {
870 SkRect r;
871 r.set(draw.fClip->getBounds());
872 SkMatrix matrix, inverse;
873 matrix.setConcat(*draw.fMatrix, m);
874 if (!matrix.invert(&inverse)) {
875 return;
876 }
877 inverse.mapRect(&r);
878 r.roundOut(&clipRect);
879 // apply the canvas' translate to our local clip
880 clipRect.offset(DX, DY);
881 }
882
reed@google.com02a7e6c2011-01-28 21:21:49 +0000883 int nx = bitmap.width() / maxTextureDim;
884 int ny = bitmap.height() / maxTextureDim;
reed@google.comac10a2d2010-12-22 21:39:39 +0000885 for (int x = 0; x <= nx; x++) {
886 for (int y = 0; y <= ny; y++) {
887 SkIRect tileR;
reed@google.com02a7e6c2011-01-28 21:21:49 +0000888 tileR.set(x * maxTextureDim, y * maxTextureDim,
889 (x + 1) * maxTextureDim, (y + 1) * maxTextureDim);
reed@google.comac10a2d2010-12-22 21:39:39 +0000890 if (!SkIRect::Intersects(tileR, clipRect)) {
891 continue;
892 }
893
894 SkIRect srcR = tileR;
895 if (!srcR.intersect(srcRect)) {
896 continue;
897 }
898
899 SkBitmap tmpB;
900 if (bitmap.extractSubset(&tmpB, tileR)) {
901 // now offset it to make it "local" to our tmp bitmap
902 srcR.offset(-tileR.fLeft, -tileR.fTop);
903
904 SkMatrix tmpM(m);
905 {
906 int dx = tileR.fLeft - DX + SkMax32(0, srcR.fLeft);
907 int dy = tileR.fTop - DY + SkMax32(0, srcR.fTop);
908 tmpM.preTranslate(SkIntToScalar(dx), SkIntToScalar(dy));
909 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000910 this->internalDrawBitmap(draw, tmpB, srcR, tmpM, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000911 }
912 }
913 }
914}
915
916/*
917 * This is called by drawBitmap(), which has to handle images that may be too
918 * large to be represented by a single texture.
919 *
bsalomon@google.com5782d712011-01-21 21:03:59 +0000920 * internalDrawBitmap assumes that the specified bitmap will fit in a texture
921 * and that non-texture portion of the GrPaint has already been setup.
reed@google.comac10a2d2010-12-22 21:39:39 +0000922 */
923void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
924 const SkBitmap& bitmap,
925 const SkIRect& srcRect,
926 const SkMatrix& m,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000927 GrPaint* grPaint) {
reed@google.com02a7e6c2011-01-28 21:21:49 +0000928 SkASSERT(bitmap.width() <= fContext->getMaxTextureDimension() &&
929 bitmap.height() <= fContext->getMaxTextureDimension());
reed@google.comac10a2d2010-12-22 21:39:39 +0000930
931 SkAutoLockPixels alp(bitmap);
932 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
933 return;
934 }
935
bsalomon@google.com5782d712011-01-21 21:03:59 +0000936 grPaint->fSampler.setWrapX(GrSamplerState::kClamp_WrapMode);
937 grPaint->fSampler.setWrapY(GrSamplerState::kClamp_WrapMode);
938 grPaint->fSampler.setSampleMode(GrSamplerState::kNormal_SampleMode);
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000939 grPaint->fSampler.setMatrix(GrMatrix::I());
reed@google.comac10a2d2010-12-22 21:39:39 +0000940
941 GrTexture* texture;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000942 SkAutoCachedTexture act(this, bitmap, grPaint->fSampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000943 if (NULL == texture) {
944 return;
945 }
946
bsalomon@google.com5782d712011-01-21 21:03:59 +0000947 grPaint->setTexture(texture);
reed@google.com46799cd2011-02-22 20:56:26 +0000948
reed@google.com20efde72011-05-09 17:00:02 +0000949 GrRect dstRect = SkRect::MakeWH(GrIntToScalar(srcRect.width()),
950 GrIntToScalar(srcRect.height()));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000951 GrRect paintRect;
952 paintRect.setLTRB(GrFixedToScalar((srcRect.fLeft << 16) / bitmap.width()),
953 GrFixedToScalar((srcRect.fTop << 16) / bitmap.height()),
954 GrFixedToScalar((srcRect.fRight << 16) / bitmap.width()),
955 GrFixedToScalar((srcRect.fBottom << 16) / bitmap.height()));
reed@google.comac10a2d2010-12-22 21:39:39 +0000956
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000957 fContext->drawRectToRect(*grPaint, dstRect, paintRect, &m);
reed@google.comac10a2d2010-12-22 21:39:39 +0000958}
959
960void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
961 int left, int top, const SkPaint& paint) {
962 CHECK_SHOULD_DRAW(draw);
963
964 SkAutoLockPixels alp(bitmap);
965 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
966 return;
967 }
968
bsalomon@google.com5782d712011-01-21 21:03:59 +0000969 GrPaint grPaint;
970 if(!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
971 return;
972 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000973
bsalomon@google.com5782d712011-01-21 21:03:59 +0000974 GrAutoMatrix avm(fContext, GrMatrix::I());
975
976 GrTexture* texture;
977 grPaint.fSampler.setClampNoFilter();
978 SkAutoCachedTexture act(this, bitmap, grPaint.fSampler, &texture);
979
bsalomon@google.com5782d712011-01-21 21:03:59 +0000980 grPaint.setTexture(texture);
981
bsalomon@google.com5782d712011-01-21 21:03:59 +0000982 fContext->drawRectToRect(grPaint,
reed@google.com20efde72011-05-09 17:00:02 +0000983 GrRect::MakeXYWH(GrIntToScalar(left),
984 GrIntToScalar(top),
985 GrIntToScalar(bitmap.width()),
986 GrIntToScalar(bitmap.height())),
987 GrRect::MakeWH(GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +0000988}
989
990void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
991 int x, int y, const SkPaint& paint) {
992 CHECK_SHOULD_DRAW(draw);
993
bsalomon@google.com5782d712011-01-21 21:03:59 +0000994 GrPaint grPaint;
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000995 if (!((SkGpuDevice*)dev)->bindDeviceAsTexture(&grPaint) ||
bsalomon@google.com5782d712011-01-21 21:03:59 +0000996 !this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
997 return;
reed@google.comac10a2d2010-12-22 21:39:39 +0000998 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000999
1000 SkASSERT(NULL != grPaint.getTexture());
1001
1002 const SkBitmap& bm = dev->accessBitmap(false);
1003 int w = bm.width();
1004 int h = bm.height();
1005
1006 GrAutoMatrix avm(fContext, GrMatrix::I());
1007
1008 grPaint.fSampler.setClampNoFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +00001009
1010 fContext->drawRectToRect(grPaint,
reed@google.com20efde72011-05-09 17:00:02 +00001011 GrRect::MakeXYWH(GrIntToScalar(x),
1012 GrIntToScalar(y),
1013 GrIntToScalar(w),
1014 GrIntToScalar(h)),
1015 GrRect::MakeWH(GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001016}
1017
1018///////////////////////////////////////////////////////////////////////////////
1019
1020// must be in SkCanvas::VertexMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +00001021static const GrPrimitiveType gVertexMode2PrimitiveType[] = {
1022 kTriangles_PrimitiveType,
1023 kTriangleStrip_PrimitiveType,
1024 kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +00001025};
1026
1027void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
1028 int vertexCount, const SkPoint vertices[],
1029 const SkPoint texs[], const SkColor colors[],
1030 SkXfermode* xmode,
1031 const uint16_t indices[], int indexCount,
1032 const SkPaint& paint) {
1033 CHECK_SHOULD_DRAW(draw);
1034
bsalomon@google.com5782d712011-01-21 21:03:59 +00001035 GrPaint grPaint;
1036 SkAutoCachedTexture act;
1037 // we ignore the shader if texs is null.
1038 if (NULL == texs) {
1039 if (!this->skPaint2GrPaintNoShader(paint, false, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001040 return;
1041 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001042 } else {
reed@google.com1a2e8d22011-01-21 22:08:29 +00001043 if (!this->skPaint2GrPaintShader(paint, &act,
1044 *draw.fMatrix,
bsalomon@google.com5782d712011-01-21 21:03:59 +00001045 &grPaint)) {
1046 return;
1047 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001048 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001049
1050 if (NULL != xmode && NULL != texs && NULL != colors) {
1051 SkXfermode::Mode mode;
1052 if (!SkXfermode::IsMode(xmode, &mode) ||
1053 SkXfermode::kMultiply_Mode != mode) {
1054 SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
1055#if 0
1056 return
1057#endif
1058 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001059 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001060
1061#if SK_SCALAR_IS_GR_SCALAR
1062 // even if GrColor and SkColor byte offsets match we need
1063 // to perform pre-multiply.
1064 if (NULL == colors) {
1065 fContext->drawVertices(grPaint,
1066 gVertexMode2PrimitiveType[vmode],
1067 vertexCount,
1068 (GrPoint*) vertices,
1069 (GrPoint*) texs,
1070 NULL,
1071 indices,
1072 indexCount);
1073 } else
1074#endif
1075 {
1076 SkTexCoordSource texSrc(texs);
1077 SkColorSource colSrc(colors);
1078 SkIndexSource idxSrc(indices, indexCount);
1079
1080 fContext->drawCustomVertices(grPaint,
1081 gVertexMode2PrimitiveType[vmode],
1082 SkPositionSource(vertices, vertexCount),
1083 (NULL == texs) ? NULL : &texSrc,
1084 (NULL == colors) ? NULL : &colSrc,
1085 (NULL == indices) ? NULL : &idxSrc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001086 }
1087}
1088
1089///////////////////////////////////////////////////////////////////////////////
1090
1091static void GlyphCacheAuxProc(void* data) {
1092 delete (GrFontScaler*)data;
1093}
1094
1095static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) {
1096 void* auxData;
1097 GrFontScaler* scaler = NULL;
1098 if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
1099 scaler = (GrFontScaler*)auxData;
1100 }
1101 if (NULL == scaler) {
1102 scaler = new SkGrFontScaler(cache);
1103 cache->setAuxProc(GlyphCacheAuxProc, scaler);
1104 }
1105 return scaler;
1106}
1107
1108static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
1109 SkFixed fx, SkFixed fy,
1110 const SkGlyph& glyph) {
1111 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1112
1113 GrSkDrawProcs* procs = (GrSkDrawProcs*)state.fDraw->fProcs;
1114
1115 if (NULL == procs->fFontScaler) {
1116 procs->fFontScaler = get_gr_font_scaler(state.fCache);
1117 }
reed@google.com39ce0ac2011-04-08 15:42:19 +00001118
1119 /*
1120 * Skia calls us with fx,fy already biased by 1/2. It does this to speed
1121 * up rounding these, so that all of its procs (like us) can just call
1122 * SkFixedFloor and get the "rounded" value.
1123 *
1124 * We take advantage of that for fx, where we pass a rounded value, but
1125 * we want the fractional fy, so we have to unbias it first.
1126 */
reed@google.comac10a2d2010-12-22 21:39:39 +00001127 procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0),
reed@google.com39ce0ac2011-04-08 15:42:19 +00001128 SkIntToFixed(SkFixedFloor(fx)),
1129 fy - SK_FixedHalf,
reed@google.comac10a2d2010-12-22 21:39:39 +00001130 procs->fFontScaler);
1131}
1132
bsalomon@google.com5782d712011-01-21 21:03:59 +00001133SkDrawProcs* SkGpuDevice::initDrawForText(GrTextContext* context) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001134
1135 // deferred allocation
1136 if (NULL == fDrawProcs) {
1137 fDrawProcs = new GrSkDrawProcs;
1138 fDrawProcs->fD1GProc = SkGPU_Draw1Glyph;
1139 fDrawProcs->fContext = fContext;
1140 }
1141
1142 // init our (and GL's) state
1143 fDrawProcs->fTextContext = context;
1144 fDrawProcs->fFontScaler = NULL;
1145 return fDrawProcs;
1146}
1147
1148void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
1149 size_t byteLength, SkScalar x, SkScalar y,
1150 const SkPaint& paint) {
1151 CHECK_SHOULD_DRAW(draw);
1152
1153 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1154 // this guy will just call our drawPath()
1155 draw.drawText((const char*)text, byteLength, x, y, paint);
1156 } else {
reed@google.comac10a2d2010-12-22 21:39:39 +00001157 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001158
1159 GrPaint grPaint;
1160 SkAutoCachedTexture act;
1161
1162 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1163 return;
1164 }
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001165 GrTextContext context(fContext, grPaint, draw.fExtMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001166 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001167 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
1168 }
1169}
1170
1171void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
1172 size_t byteLength, const SkScalar pos[],
1173 SkScalar constY, int scalarsPerPos,
1174 const SkPaint& paint) {
1175 CHECK_SHOULD_DRAW(draw);
1176
1177 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1178 // this guy will just call our drawPath()
1179 draw.drawPosText((const char*)text, byteLength, pos, constY,
1180 scalarsPerPos, paint);
1181 } else {
reed@google.comac10a2d2010-12-22 21:39:39 +00001182 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001183
1184 GrPaint grPaint;
1185 SkAutoCachedTexture act;
1186 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1187 return;
1188 }
1189
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001190 GrTextContext context(fContext, grPaint, draw.fExtMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001191 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001192 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
1193 scalarsPerPos, paint);
1194 }
1195}
1196
1197void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
1198 size_t len, const SkPath& path,
1199 const SkMatrix* m, const SkPaint& paint) {
1200 CHECK_SHOULD_DRAW(draw);
1201
1202 SkASSERT(draw.fDevice == this);
1203 draw.drawTextOnPath((const char*)text, len, path, m, paint);
1204}
1205
1206///////////////////////////////////////////////////////////////////////////////
1207
reed@google.comf67e4cf2011-03-15 20:56:58 +00001208bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
1209 if (!paint.isLCDRenderText()) {
1210 // we're cool with the paint as is
1211 return false;
1212 }
1213
1214 if (paint.getShader() ||
1215 paint.getXfermode() || // unless its srcover
1216 paint.getMaskFilter() ||
1217 paint.getRasterizer() ||
1218 paint.getColorFilter() ||
1219 paint.getPathEffect() ||
1220 paint.isFakeBoldText() ||
1221 paint.getStyle() != SkPaint::kFill_Style) {
1222 // turn off lcd
1223 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
1224 flags->fHinting = paint.getHinting();
1225 return true;
1226 }
1227 // we're cool with the paint as is
1228 return false;
1229}
1230
1231///////////////////////////////////////////////////////////////////////////////
1232
reed@google.comac10a2d2010-12-22 21:39:39 +00001233SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001234 const GrSamplerState& sampler,
1235 GrTexture** texture,
1236 bool forDeviceRenderTarget) {
1237 GrTexture* newTexture = NULL;
1238 GrTextureEntry* entry = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +00001239 GrContext* ctx = this->context();
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001240
reed@google.comac10a2d2010-12-22 21:39:39 +00001241 if (forDeviceRenderTarget) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001242 const GrTextureDesc desc = {
1243 kRenderTarget_GrTextureFlagBit,
1244 kNone_GrAALevel,
1245 bitmap.width(),
1246 bitmap.height(),
1247 SkGr::Bitmap2PixelConfig(bitmap)
1248 };
bsalomon@google.coma39f4042011-04-26 13:18:16 +00001249 entry = ctx->lockKeylessTexture(desc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001250 } else {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001251 uint32_t p0, p1;
reed@google.comac10a2d2010-12-22 21:39:39 +00001252 p0 = bitmap.getGenerationID();
1253 p1 = bitmap.pixelRefOffset();
reed@google.comac10a2d2010-12-22 21:39:39 +00001254
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001255 GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
1256 entry = ctx->findAndLockTexture(&key, sampler);
reed@google.comac10a2d2010-12-22 21:39:39 +00001257
reed@google.comac10a2d2010-12-22 21:39:39 +00001258 if (NULL == entry) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001259 entry = sk_gr_create_bitmap_texture(ctx, &key, sampler, bitmap);
1260 if (NULL == entry) {
1261 GrPrintf("---- failed to create texture for cache [%d %d]\n",
1262 bitmap.width(), bitmap.height());
1263 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001264 }
1265 }
1266
1267 if (NULL != entry) {
1268 newTexture = entry->texture();
reed@google.comac10a2d2010-12-22 21:39:39 +00001269 if (texture) {
1270 *texture = newTexture;
1271 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001272 }
1273 return (TexCache*)entry;
1274}
1275
1276void SkGpuDevice::unlockCachedTexture(TexCache* cache) {
1277 this->context()->unlockTexture((GrTextureEntry*)cache);
1278}
1279
reed@google.com7b201d22011-01-11 18:59:23 +00001280///////////////////////////////////////////////////////////////////////////////
1281
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001282SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context,
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001283 GrRenderTarget* rootRenderTarget) {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001284 GrAssert(NULL != context);
1285 GrAssert(NULL != rootRenderTarget);
1286
1287 // check this now rather than passing this value to SkGpuDevice cons.
1288 // we want the rt that is bound *now* in the 3D API, not the one
1289 // at the time of newDevice.
1290 if (SkGpuDevice::Current3DApiRenderTarget() == rootRenderTarget) {
1291 fRootRenderTarget = context->createRenderTargetFrom3DApiState();
1292 } else {
1293 fRootRenderTarget = rootRenderTarget;
1294 rootRenderTarget->ref();
1295 }
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001296
1297 fContext = context;
reed@google.com7b201d22011-01-11 18:59:23 +00001298 context->ref();
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001299
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001300 fRootTexture = NULL;
1301}
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001302
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001303SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context, GrTexture* rootRenderTargetTexture) {
1304 GrAssert(NULL != context);
1305 GrAssert(NULL != rootRenderTargetTexture);
1306 GrAssert(NULL != rootRenderTargetTexture->asRenderTarget());
1307
1308 fRootTexture = rootRenderTargetTexture;
1309 rootRenderTargetTexture->ref();
1310
1311 fRootRenderTarget = rootRenderTargetTexture->asRenderTarget();
1312 fRootRenderTarget->ref();
1313
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001314 fContext = context;
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001315 context->ref();
reed@google.com7b201d22011-01-11 18:59:23 +00001316}
1317
1318SkGpuDeviceFactory::~SkGpuDeviceFactory() {
1319 fContext->unref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001320 fRootRenderTarget->unref();
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001321 GrSafeUnref(fRootTexture);
reed@google.com7b201d22011-01-11 18:59:23 +00001322}
1323
1324SkDevice* SkGpuDeviceFactory::newDevice(SkCanvas*, SkBitmap::Config config,
1325 int width, int height,
1326 bool isOpaque, bool isLayer) {
1327 SkBitmap bm;
1328 bm.setConfig(config, width, height);
1329 bm.setIsOpaque(isOpaque);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001330 return new SkGpuDevice(fContext, bm, isLayer ? NULL : fRootRenderTarget);
reed@google.com7b201d22011-01-11 18:59:23 +00001331}