blob: 5b4f529bdb27cfcd68a80844aeb5f2a958590ac8 [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
Scroggo97c88c22011-05-11 14:05:25 +000025#include "SkColorFilter.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000026#include "SkDrawProcs.h"
27#include "SkGlyphCache.h"
reed@google.comc9aa5872011-04-05 21:05:37 +000028#include "SkUtils.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000029
30#define CACHE_LAYER_TEXTURES 1
31
32#if 0
33 extern bool (*gShouldDrawProc)();
34 #define CHECK_SHOULD_DRAW(draw) \
35 do { \
36 if (gShouldDrawProc && !gShouldDrawProc()) return; \
37 this->prepareRenderTarget(draw); \
38 } while (0)
39#else
40 #define CHECK_SHOULD_DRAW(draw) this->prepareRenderTarget(draw)
41#endif
42
reed@google.comac10a2d2010-12-22 21:39:39 +000043///////////////////////////////////////////////////////////////////////////////
44
45SkGpuDevice::SkAutoCachedTexture::
46 SkAutoCachedTexture(SkGpuDevice* device,
47 const SkBitmap& bitmap,
48 const GrSamplerState& sampler,
49 GrTexture** texture) {
50 GrAssert(texture);
51 fTex = NULL;
52 *texture = this->set(device, bitmap, sampler);
53}
54
55SkGpuDevice::SkAutoCachedTexture::SkAutoCachedTexture() {
56 fTex = NULL;
57}
58
59GrTexture* SkGpuDevice::SkAutoCachedTexture::set(SkGpuDevice* device,
60 const SkBitmap& bitmap,
61 const GrSamplerState& sampler) {
62 if (fTex) {
63 fDevice->unlockCachedTexture(fTex);
64 }
65 fDevice = device;
66 GrTexture* texture = (GrTexture*)bitmap.getTexture();
67 if (texture) {
68 // return the native texture
69 fTex = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +000070 } else {
71 // look it up in our cache
72 fTex = device->lockCachedTexture(bitmap, sampler, &texture, false);
73 }
74 return texture;
75}
76
77SkGpuDevice::SkAutoCachedTexture::~SkAutoCachedTexture() {
78 if (fTex) {
79 fDevice->unlockCachedTexture(fTex);
80 }
81}
82
83///////////////////////////////////////////////////////////////////////////////
84
85bool gDoTraceDraw;
86
87struct GrSkDrawProcs : public SkDrawProcs {
88public:
89 GrContext* fContext;
90 GrTextContext* fTextContext;
91 GrFontScaler* fFontScaler; // cached in the skia glyphcache
92};
93
94///////////////////////////////////////////////////////////////////////////////
95
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +000096GrRenderTarget* SkGpuDevice::Current3DApiRenderTarget() {
97 return (GrRenderTarget*) -1;
98}
99
100SkGpuDevice::SkGpuDevice(GrContext* context,
101 const SkBitmap& bitmap,
102 GrRenderTarget* renderTargetOrNull)
103 : SkDevice(NULL, bitmap, (NULL == renderTargetOrNull)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000104
105 fNeedPrepareRenderTarget = false;
106 fDrawProcs = NULL;
107
reed@google.com7b201d22011-01-11 18:59:23 +0000108 fContext = context;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000109 fContext->ref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000110
111 fCache = NULL;
112 fTexture = NULL;
113 fRenderTarget = NULL;
114 fNeedClear = false;
115
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000116 if (NULL == renderTargetOrNull) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000117 SkBitmap::Config c = bitmap.config();
118 if (c != SkBitmap::kRGB_565_Config) {
119 c = SkBitmap::kARGB_8888_Config;
120 }
121 SkBitmap bm;
122 bm.setConfig(c, this->width(), this->height());
123
124#if CACHE_LAYER_TEXTURES
125
126 fCache = this->lockCachedTexture(bm, GrSamplerState::ClampNoFilter(),
127 &fTexture, true);
128 if (fCache) {
129 SkASSERT(NULL != fTexture);
bsalomon@google.com1da07462011-03-10 14:51:57 +0000130 SkASSERT(NULL != fTexture->asRenderTarget());
reed@google.comac10a2d2010-12-22 21:39:39 +0000131 }
132#else
133 const GrGpu::TextureDesc desc = {
134 GrGpu::kRenderTarget_TextureFlag,
135 GrGpu::kNone_AALevel,
136 this->width(),
137 this->height(),
138 SkGr::Bitmap2PixelConfig(bm)
139 };
140
141 fTexture = fContext->createUncachedTexture(desc, NULL, 0);
142#endif
143 if (NULL != fTexture) {
144 fRenderTarget = fTexture->asRenderTarget();
145
146 GrAssert(NULL != fRenderTarget);
147
148 // we defer the actual clear until our gainFocus()
149 fNeedClear = true;
150
151 // wrap the bitmap with a pixelref to expose our texture
152 SkGrTexturePixelRef* pr = new SkGrTexturePixelRef(fTexture);
153 this->setPixelRef(pr, 0)->unref();
154 } else {
155 GrPrintf("--- failed to create gpu-offscreen [%d %d]\n",
156 this->width(), this->height());
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000157 GrAssert(false);
reed@google.comac10a2d2010-12-22 21:39:39 +0000158 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000159 } else {
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000160 if (Current3DApiRenderTarget() == renderTargetOrNull) {
161 fRenderTarget = fContext->createRenderTargetFrom3DApiState();
162 } else {
163 fRenderTarget = renderTargetOrNull;
164 fRenderTarget->ref();
165 }
166 SkGrRenderTargetPixelRef* pr = new SkGrRenderTargetPixelRef(fRenderTarget);
167 this->setPixelRef(pr, 0)->unref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000168 }
169}
170
171SkGpuDevice::~SkGpuDevice() {
172 if (fDrawProcs) {
173 delete fDrawProcs;
174 }
175
176 if (fCache) {
177 GrAssert(NULL != fTexture);
178 GrAssert(fRenderTarget == fTexture->asRenderTarget());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000179 fContext->unlockTexture((GrTextureEntry*)fCache);
reed@google.comac10a2d2010-12-22 21:39:39 +0000180 } else if (NULL != fTexture) {
181 GrAssert(!CACHE_LAYER_TEXTURES);
182 GrAssert(fRenderTarget == fTexture->asRenderTarget());
183 fTexture->unref();
184 } else if (NULL != fRenderTarget) {
185 fRenderTarget->unref();
186 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000187 fContext->unref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000188}
189
reed@google.comac10a2d2010-12-22 21:39:39 +0000190intptr_t SkGpuDevice::getLayerTextureHandle() const {
191 if (fTexture) {
192 return fTexture->getTextureHandle();
193 } else {
194 return 0;
195 }
196}
mike@reedtribe.orgea4ac972011-04-26 11:48:33 +0000197
198SkDeviceFactory* SkGpuDevice::onNewDeviceFactory() {
199 return SkNEW_ARGS(SkGpuDeviceFactory, (fContext, fRenderTarget));
200}
201
reed@google.comac10a2d2010-12-22 21:39:39 +0000202///////////////////////////////////////////////////////////////////////////////
203
204void SkGpuDevice::makeRenderTargetCurrent() {
205 fContext->setRenderTarget(fRenderTarget);
206 fContext->flush(true);
207 fNeedPrepareRenderTarget = true;
208}
209
210///////////////////////////////////////////////////////////////////////////////
211
212bool SkGpuDevice::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
213 SkIRect bounds;
214 bounds.set(0, 0, this->width(), this->height());
215 if (!bounds.intersect(srcRect)) {
216 return false;
217 }
218
219 const int w = bounds.width();
220 const int h = bounds.height();
221 SkBitmap tmp;
222 // note we explicitly specify our rowBytes to be snug (no gap between rows)
223 tmp.setConfig(SkBitmap::kARGB_8888_Config, w, h, w * 4);
224 if (!tmp.allocPixels()) {
225 return false;
226 }
227
Scroggo813c33c2011-04-07 20:56:21 +0000228 tmp.lockPixels();
reed@google.comac10a2d2010-12-22 21:39:39 +0000229
Scroggoeb176032011-04-07 21:11:49 +0000230 bool read = fContext->readRenderTargetPixels(fRenderTarget,
231 bounds.fLeft, bounds.fTop,
232 bounds.width(), bounds.height(),
233 kRGBA_8888_GrPixelConfig,
234 tmp.getPixels());
Scroggo813c33c2011-04-07 20:56:21 +0000235 tmp.unlockPixels();
236 if (!read) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000237 return false;
238 }
239
240 tmp.swap(*bitmap);
241 return true;
242}
243
244void SkGpuDevice::writePixels(const SkBitmap& bitmap, int x, int y) {
245 SkAutoLockPixels alp(bitmap);
246 if (!bitmap.readyToDraw()) {
247 return;
248 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000249 GrPixelConfig config = SkGr::BitmapConfig2PixelConfig(bitmap.config(),
250 bitmap.isOpaque());
reed@google.comac10a2d2010-12-22 21:39:39 +0000251 fContext->setRenderTarget(fRenderTarget);
252 // we aren't setting the clip or matrix, so mark as dirty
253 // we don't need to set them for this call and don't have them anyway
254 fNeedPrepareRenderTarget = true;
255
256 fContext->writePixels(x, y, bitmap.width(), bitmap.height(),
257 config, bitmap.getPixels(), bitmap.rowBytes());
258}
259
260///////////////////////////////////////////////////////////////////////////////
261
262static void convert_matrixclip(GrContext* context, const SkMatrix& matrix,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000263 const SkClipStack& clipStack,
reed@google.com6f8f2922011-03-04 22:27:10 +0000264 const SkRegion& clipRegion,
265 const SkIPoint& origin) {
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000266 context->setMatrix(matrix);
reed@google.comac10a2d2010-12-22 21:39:39 +0000267
268 SkGrClipIterator iter;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000269 iter.reset(clipStack);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000270 const SkIRect& skBounds = clipRegion.getBounds();
271 GrRect bounds;
272 bounds.setLTRB(GrIntToScalar(skBounds.fLeft),
273 GrIntToScalar(skBounds.fTop),
274 GrIntToScalar(skBounds.fRight),
275 GrIntToScalar(skBounds.fBottom));
reed@google.com6f8f2922011-03-04 22:27:10 +0000276 GrClip grc(&iter, GrIntToScalar(-origin.x()), GrIntToScalar(-origin.y()),
277 &bounds);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000278 context->setClip(grc);
reed@google.comac10a2d2010-12-22 21:39:39 +0000279}
280
281// call this ever each draw call, to ensure that the context reflects our state,
282// and not the state from some other canvas/device
283void SkGpuDevice::prepareRenderTarget(const SkDraw& draw) {
284 if (fNeedPrepareRenderTarget ||
bsalomon@google.com5782d712011-01-21 21:03:59 +0000285 fContext->getRenderTarget() != fRenderTarget) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000286
287 fContext->setRenderTarget(fRenderTarget);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000288 SkASSERT(draw.fClipStack);
289 convert_matrixclip(fContext, *draw.fMatrix,
reed@google.com6f8f2922011-03-04 22:27:10 +0000290 *draw.fClipStack, *draw.fClip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000291 fNeedPrepareRenderTarget = false;
292 }
293}
294
reed@google.com46799cd2011-02-22 20:56:26 +0000295void SkGpuDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& clip,
296 const SkClipStack& clipStack) {
297 this->INHERITED::setMatrixClip(matrix, clip, clipStack);
bsalomon@google.coma7bf6e22011-04-11 19:20:46 +0000298 // We don't need to set them now because the context may not reflect this device.
299 fNeedPrepareRenderTarget = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000300}
301
302void SkGpuDevice::gainFocus(SkCanvas* canvas, const SkMatrix& matrix,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000303 const SkRegion& clip, const SkClipStack& clipStack) {
304
reed@google.comac10a2d2010-12-22 21:39:39 +0000305 fContext->setRenderTarget(fRenderTarget);
306
bsalomon@google.comd302f142011-03-03 13:54:13 +0000307 this->INHERITED::gainFocus(canvas, matrix, clip, clipStack);
reed@google.comac10a2d2010-12-22 21:39:39 +0000308
reed@google.com6f8f2922011-03-04 22:27:10 +0000309 convert_matrixclip(fContext, matrix, clipStack, clip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000310
311 if (fNeedClear) {
bsalomon@google.com31a58402011-04-27 21:00:02 +0000312 fContext->clear(NULL, 0x0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000313 fNeedClear = false;
314 }
315}
316
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000317bool SkGpuDevice::bindDeviceAsTexture(GrPaint* paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000318 if (NULL != fTexture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000319 paint->setTexture(fTexture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000320 return true;
321 }
322 return false;
323}
324
325///////////////////////////////////////////////////////////////////////////////
326
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000327SK_COMPILE_ASSERT(SkShader::kNone_BitmapType == 0, shader_type_mismatch);
328SK_COMPILE_ASSERT(SkShader::kDefault_BitmapType == 1, shader_type_mismatch);
329SK_COMPILE_ASSERT(SkShader::kRadial_BitmapType == 2, shader_type_mismatch);
330SK_COMPILE_ASSERT(SkShader::kSweep_BitmapType == 3, shader_type_mismatch);
331SK_COMPILE_ASSERT(SkShader::kTwoPointRadial_BitmapType == 4,
332 shader_type_mismatch);
333SK_COMPILE_ASSERT(SkShader::kLast_BitmapType == 4, shader_type_mismatch);
reed@google.comac10a2d2010-12-22 21:39:39 +0000334
bsalomon@google.com5782d712011-01-21 21:03:59 +0000335static const GrSamplerState::SampleMode sk_bmp_type_to_sample_mode[] = {
336 (GrSamplerState::SampleMode) -1, // kNone_BitmapType
337 GrSamplerState::kNormal_SampleMode, // kDefault_BitmapType
338 GrSamplerState::kRadial_SampleMode, // kRadial_BitmapType
339 GrSamplerState::kSweep_SampleMode, // kSweep_BitmapType
340 GrSamplerState::kRadial2_SampleMode, // kTwoPointRadial_BitmapType
341};
342
343bool SkGpuDevice::skPaint2GrPaintNoShader(const SkPaint& skPaint,
344 bool justAlpha,
345 GrPaint* grPaint) {
346
347 grPaint->fDither = skPaint.isDither();
348 grPaint->fAntiAlias = skPaint.isAntiAlias();
349
350 SkXfermode::Coeff sm = SkXfermode::kOne_Coeff;
351 SkXfermode::Coeff dm = SkXfermode::kISA_Coeff;
352
353 SkXfermode* mode = skPaint.getXfermode();
354 if (mode) {
355 if (!mode->asCoeff(&sm, &dm)) {
reed@google.com1a2e8d22011-01-21 22:08:29 +0000356 SkDEBUGCODE(SkDebugf("Unsupported xfer mode.\n");)
bsalomon@google.com5782d712011-01-21 21:03:59 +0000357#if 0
358 return false;
359#endif
360 }
361 }
362 grPaint->fSrcBlendCoeff = sk_blend_to_grblend(sm);
363 grPaint->fDstBlendCoeff = sk_blend_to_grblend(dm);
364
365 if (justAlpha) {
366 uint8_t alpha = skPaint.getAlpha();
367 grPaint->fColor = GrColorPackRGBA(alpha, alpha, alpha, alpha);
368 } else {
369 grPaint->fColor = SkGr::SkColor2GrColor(skPaint.getColor());
370 grPaint->setTexture(NULL);
371 }
Scroggo97c88c22011-05-11 14:05:25 +0000372 SkColorFilter* colorFilter = skPaint.getColorFilter();
373 SkColor color;
374 SkXfermode::Mode filterMode;
375 if (colorFilter != NULL && colorFilter->asColorMode(&color, &filterMode)) {
376 grPaint->fColorFilterColor = SkGr::SkColor2GrColor(color);
377 grPaint->fColorFilterXfermode = filterMode;
378 } else {
379 grPaint->resetColorFilter();
380 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000381 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000382}
383
bsalomon@google.com5782d712011-01-21 21:03:59 +0000384bool SkGpuDevice::skPaint2GrPaintShader(const SkPaint& skPaint,
385 SkAutoCachedTexture* act,
386 const SkMatrix& ctm,
387 GrPaint* grPaint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000388
bsalomon@google.com5782d712011-01-21 21:03:59 +0000389 SkASSERT(NULL != act);
reed@google.comac10a2d2010-12-22 21:39:39 +0000390
bsalomon@google.com5782d712011-01-21 21:03:59 +0000391 SkShader* shader = skPaint.getShader();
reed@google.comac10a2d2010-12-22 21:39:39 +0000392 if (NULL == shader) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000393 return this->skPaint2GrPaintNoShader(skPaint, false, grPaint);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000394 } else if (!this->skPaint2GrPaintNoShader(skPaint, true, grPaint)) {
395 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000396 }
397
bsalomon@google.com5782d712011-01-21 21:03:59 +0000398 SkPaint noAlphaPaint(skPaint);
399 noAlphaPaint.setAlpha(255);
400 shader->setContext(this->accessBitmap(false), noAlphaPaint, ctm);
reed@google.comac10a2d2010-12-22 21:39:39 +0000401
reed@google.comac10a2d2010-12-22 21:39:39 +0000402 SkBitmap bitmap;
403 SkMatrix matrix;
404 SkShader::TileMode tileModes[2];
405 SkScalar twoPointParams[3];
406 SkShader::BitmapType bmptype = shader->asABitmap(&bitmap, &matrix,
407 tileModes, twoPointParams);
408
bsalomon@google.com5782d712011-01-21 21:03:59 +0000409 GrSamplerState::SampleMode sampleMode = sk_bmp_type_to_sample_mode[bmptype];
410 if (-1 == sampleMode) {
411 SkDebugf("shader->asABitmap() == kNone_BitmapType\n");
412 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000413 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000414 grPaint->fSampler.setSampleMode(sampleMode);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000415 if (skPaint.isFilterBitmap()) {
416 grPaint->fSampler.setFilter(GrSamplerState::kBilinear_Filter);
417 } else {
418 grPaint->fSampler.setFilter(GrSamplerState::kNearest_Filter);
419 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000420 grPaint->fSampler.setWrapX(sk_tile_mode_to_grwrap(tileModes[0]));
421 grPaint->fSampler.setWrapY(sk_tile_mode_to_grwrap(tileModes[1]));
reed@google.comac10a2d2010-12-22 21:39:39 +0000422 if (GrSamplerState::kRadial2_SampleMode == sampleMode) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000423 grPaint->fSampler.setRadial2Params(twoPointParams[0],
424 twoPointParams[1],
425 twoPointParams[2] < 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000426 }
427
bsalomon@google.com5782d712011-01-21 21:03:59 +0000428 GrTexture* texture = act->set(this, bitmap, grPaint->fSampler);
reed@google.comac10a2d2010-12-22 21:39:39 +0000429 if (NULL == texture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000430 SkDebugf("Couldn't convert bitmap to texture.\n");
431 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000432 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000433 grPaint->setTexture(texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000434
435 // since our texture coords will be in local space, we wack the texture
436 // matrix to map them back into 0...1 before we load it
437 SkMatrix localM;
438 if (shader->getLocalMatrix(&localM)) {
439 SkMatrix inverse;
440 if (localM.invert(&inverse)) {
441 matrix.preConcat(inverse);
442 }
443 }
444 if (SkShader::kDefault_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000445 GrScalar sx = GrFixedToScalar(GR_Fixed1 / bitmap.width());
446 GrScalar sy = GrFixedToScalar(GR_Fixed1 / bitmap.height());
reed@google.comac10a2d2010-12-22 21:39:39 +0000447 matrix.postScale(sx, sy);
reed@google.comac10a2d2010-12-22 21:39:39 +0000448 } else if (SkShader::kRadial_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000449 GrScalar s = GrFixedToScalar(GR_Fixed1 / bitmap.width());
reed@google.comac10a2d2010-12-22 21:39:39 +0000450 matrix.postScale(s, s);
451 }
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000452 grPaint->fSampler.setMatrix(matrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000453
454 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000455}
456
457///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com5782d712011-01-21 21:03:59 +0000458
459class SkPositionSource {
460public:
461 SkPositionSource(const SkPoint* points, int count)
462 : fPoints(points), fCount(count) {}
463
464 int count() const { return fCount; }
465
466 void writeValue(int i, GrPoint* dstPosition) const {
467 SkASSERT(i < fCount);
468 dstPosition->fX = SkScalarToGrScalar(fPoints[i].fX);
469 dstPosition->fY = SkScalarToGrScalar(fPoints[i].fY);
470 }
471private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000472 const SkPoint* fPoints;
bsalomon@google.com19628322011-02-03 21:30:17 +0000473 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000474};
475
476class SkTexCoordSource {
477public:
478 SkTexCoordSource(const SkPoint* coords)
479 : fCoords(coords) {}
480
481 void writeValue(int i, GrPoint* dstCoord) const {
482 dstCoord->fX = SkScalarToGrScalar(fCoords[i].fX);
483 dstCoord->fY = SkScalarToGrScalar(fCoords[i].fY);
484 }
485private:
486 const SkPoint* fCoords;
487};
488
489class SkColorSource {
490public:
491 SkColorSource(const SkColor* colors) : fColors(colors) {}
492
493 void writeValue(int i, GrColor* dstColor) const {
494 *dstColor = SkGr::SkColor2GrColor(fColors[i]);
495 }
496private:
497 const SkColor* fColors;
498};
499
500class SkIndexSource {
501public:
502 SkIndexSource(const uint16_t* indices, int count)
503 : fIndices(indices), fCount(count) {
504 }
505
506 int count() const { return fCount; }
507
508 void writeValue(int i, uint16_t* dstIndex) const {
509 *dstIndex = fIndices[i];
510 }
511
512private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000513 const uint16_t* fIndices;
bsalomon@google.com19628322011-02-03 21:30:17 +0000514 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000515};
516
517///////////////////////////////////////////////////////////////////////////////
518
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000519#if 0 // not currently being used so don't compile,
520
bsalomon@google.com5782d712011-01-21 21:03:59 +0000521// can be used for positions or texture coordinates
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000522
bsalomon@google.com5782d712011-01-21 21:03:59 +0000523class SkRectFanSource {
524public:
525 SkRectFanSource(const SkRect& rect) : fRect(rect) {}
526
527 int count() const { return 4; }
528
529 void writeValue(int i, GrPoint* dstPoint) const {
530 SkASSERT(i < 4);
531 dstPoint->fX = SkScalarToGrScalar((i % 3) ? fRect.fRight :
532 fRect.fLeft);
533 dstPoint->fY = SkScalarToGrScalar((i < 2) ? fRect.fTop :
534 fRect.fBottom);
535 }
536private:
537 const SkRect& fRect;
538};
539
540class SkIRectFanSource {
541public:
542 SkIRectFanSource(const SkIRect& rect) : fRect(rect) {}
543
544 int count() const { return 4; }
545
546 void writeValue(int i, GrPoint* dstPoint) const {
547 SkASSERT(i < 4);
548 dstPoint->fX = (i % 3) ? GrIntToScalar(fRect.fRight) :
549 GrIntToScalar(fRect.fLeft);
550 dstPoint->fY = (i < 2) ? GrIntToScalar(fRect.fTop) :
551 GrIntToScalar(fRect.fBottom);
552 }
553private:
554 const SkIRect& fRect;
555};
556
557class SkMatRectFanSource {
558public:
559 SkMatRectFanSource(const SkRect& rect, const SkMatrix& matrix)
560 : fRect(rect), fMatrix(matrix) {}
561
562 int count() const { return 4; }
563
564 void writeValue(int i, GrPoint* dstPoint) const {
565 SkASSERT(i < 4);
566
567#if SK_SCALAR_IS_GR_SCALAR
568 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
569 (i < 2) ? fRect.fTop : fRect.fBottom,
570 (SkPoint*)dstPoint);
571#else
572 SkPoint dst;
573 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
574 (i < 2) ? fRect.fTop : fRect.fBottom,
575 &dst);
576 dstPoint->fX = SkScalarToGrScalar(dst.fX);
577 dstPoint->fY = SkScalarToGrScalar(dst.fY);
578#endif
579 }
580private:
581 const SkRect& fRect;
582 const SkMatrix& fMatrix;
583};
584
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000585#endif
586
reed@google.comac10a2d2010-12-22 21:39:39 +0000587///////////////////////////////////////////////////////////////////////////////
588
bsalomon@google.com398109c2011-04-14 18:40:27 +0000589void SkGpuDevice::clear(SkColor color) {
bsalomon@google.com31a58402011-04-27 21:00:02 +0000590 fContext->clear(NULL, color);
bsalomon@google.com398109c2011-04-14 18:40:27 +0000591}
592
reed@google.comac10a2d2010-12-22 21:39:39 +0000593void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
594 CHECK_SHOULD_DRAW(draw);
595
bsalomon@google.com5782d712011-01-21 21:03:59 +0000596 GrPaint grPaint;
597 SkAutoCachedTexture act;
598 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000599 return;
600 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000601
602 fContext->drawPaint(grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000603}
604
605// must be in SkCanvas::PointMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +0000606static const GrPrimitiveType gPointMode2PrimtiveType[] = {
607 kPoints_PrimitiveType,
608 kLines_PrimitiveType,
609 kLineStrip_PrimitiveType
reed@google.comac10a2d2010-12-22 21:39:39 +0000610};
611
612void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000613 size_t count, const SkPoint pts[], const SkPaint& paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000614 CHECK_SHOULD_DRAW(draw);
615
616 SkScalar width = paint.getStrokeWidth();
617 if (width < 0) {
618 return;
619 }
620
621 // we only handle hairlines here, else we let the SkDraw call our drawPath()
622 if (width > 0) {
623 draw.drawPoints(mode, count, pts, paint, true);
624 return;
625 }
626
bsalomon@google.com5782d712011-01-21 21:03:59 +0000627 GrPaint grPaint;
628 SkAutoCachedTexture act;
629 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000630 return;
631 }
632
reed@google.comac10a2d2010-12-22 21:39:39 +0000633#if SK_SCALAR_IS_GR_SCALAR
bsalomon@google.com5782d712011-01-21 21:03:59 +0000634 fContext->drawVertices(grPaint,
635 gPointMode2PrimtiveType[mode],
636 count,
637 (GrPoint*)pts,
638 NULL,
639 NULL,
640 NULL,
641 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000642#else
bsalomon@google.com5782d712011-01-21 21:03:59 +0000643 fContext->drawCustomVertices(grPaint,
644 gPointMode2PrimtiveType[mode],
645 SkPositionSource(pts, count));
reed@google.comac10a2d2010-12-22 21:39:39 +0000646#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000647}
648
reed@google.comc9aa5872011-04-05 21:05:37 +0000649///////////////////////////////////////////////////////////////////////////////
650
reed@google.comac10a2d2010-12-22 21:39:39 +0000651void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
652 const SkPaint& paint) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000653 CHECK_SHOULD_DRAW(draw);
654
655 bool doStroke = paint.getStyle() == SkPaint::kStroke_Style;
656 SkScalar width = paint.getStrokeWidth();
657
658 /*
659 We have special code for hairline strokes, miter-strokes, and fills.
660 Anything else we just call our path code.
661 */
662 bool usePath = doStroke && width > 0 &&
663 paint.getStrokeJoin() != SkPaint::kMiter_Join;
664 // another reason we might need to call drawPath...
665 if (paint.getMaskFilter()) {
666 usePath = true;
667 }
668
669 if (usePath) {
670 SkPath path;
671 path.addRect(rect);
672 this->drawPath(draw, path, paint, NULL, true);
673 return;
674 }
675
676 GrPaint grPaint;
677 SkAutoCachedTexture act;
678 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
679 return;
680 }
reed@google.com20efde72011-05-09 17:00:02 +0000681 fContext->drawRect(grPaint, rect, doStroke ? width : -1);
reed@google.comac10a2d2010-12-22 21:39:39 +0000682}
683
reed@google.com69302852011-02-16 18:08:07 +0000684#include "SkMaskFilter.h"
685#include "SkBounder.h"
686
reed@google.com69302852011-02-16 18:08:07 +0000687static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
688 SkMaskFilter* filter, const SkMatrix& matrix,
689 const SkRegion& clip, SkBounder* bounder,
690 GrPaint* grp) {
691 SkMask srcM, dstM;
692
693 if (!SkDraw::DrawToMask(path, &clip.getBounds(), filter, &matrix, &srcM,
694 SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
695 return false;
696 }
697
698 SkAutoMaskImage autoSrc(&srcM, false);
699
700 if (!filter->filterMask(&dstM, srcM, matrix, NULL)) {
701 return false;
702 }
703 // this will free-up dstM when we're done (allocated in filterMask())
704 SkAutoMaskImage autoDst(&dstM, false);
705
706 if (clip.quickReject(dstM.fBounds)) {
707 return false;
708 }
709 if (bounder && !bounder->doIRect(dstM.fBounds)) {
710 return false;
711 }
712
713 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
714 // the current clip (and identity matrix) and grpaint settings
715
reed@google.com0c219b62011-02-16 21:31:18 +0000716 GrAutoMatrix avm(context, GrMatrix::I());
reed@google.com69302852011-02-16 18:08:07 +0000717
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000718 const GrTextureDesc desc = {
719 kNone_GrTextureFlags,
720 kNone_GrAALevel,
reed@google.com69302852011-02-16 18:08:07 +0000721 dstM.fBounds.width(),
722 dstM.fBounds.height(),
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000723 kAlpha_8_GrPixelConfig
reed@google.com69302852011-02-16 18:08:07 +0000724 };
725
726 GrTexture* texture = context->createUncachedTexture(desc, dstM.fImage,
727 dstM.fRowBytes);
728 if (NULL == texture) {
729 return false;
730 }
731
reed@google.com0c219b62011-02-16 21:31:18 +0000732 grp->setTexture(texture);
733 texture->unref();
734 grp->fSampler.setClampNoFilter();
reed@google.com69302852011-02-16 18:08:07 +0000735
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000736 GrRect d;
737 d.setLTRB(GrIntToScalar(dstM.fBounds.fLeft),
reed@google.com0c219b62011-02-16 21:31:18 +0000738 GrIntToScalar(dstM.fBounds.fTop),
739 GrIntToScalar(dstM.fBounds.fRight),
740 GrIntToScalar(dstM.fBounds.fBottom));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000741 GrRect s;
742 s.setLTRB(0, 0, GR_Scalar1, GR_Scalar1);
743 context->drawRectToRect(*grp, d, s);
reed@google.com69302852011-02-16 18:08:07 +0000744 return true;
745}
reed@google.com69302852011-02-16 18:08:07 +0000746
reed@google.com0c219b62011-02-16 21:31:18 +0000747void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
reed@google.comac10a2d2010-12-22 21:39:39 +0000748 const SkPaint& paint, const SkMatrix* prePathMatrix,
749 bool pathIsMutable) {
750 CHECK_SHOULD_DRAW(draw);
751
bsalomon@google.com5782d712011-01-21 21:03:59 +0000752 GrPaint grPaint;
753 SkAutoCachedTexture act;
754 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000755 return;
756 }
757
reed@google.com0c219b62011-02-16 21:31:18 +0000758 // BEGIN lift from SkDraw::drawPath()
759
760 SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
761 bool doFill = true;
762 SkPath tmpPath;
reed@google.comac10a2d2010-12-22 21:39:39 +0000763
764 if (prePathMatrix) {
reed@google.come3445642011-02-16 23:20:39 +0000765 SkPath* result = pathPtr;
reed@google.com0c219b62011-02-16 21:31:18 +0000766
reed@google.come3445642011-02-16 23:20:39 +0000767 if (!pathIsMutable) {
768 result = &tmpPath;
769 pathIsMutable = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000770 }
reed@google.come3445642011-02-16 23:20:39 +0000771 // should I push prePathMatrix on our MV stack temporarily, instead
772 // of applying it here? See SkDraw.cpp
773 pathPtr->transform(*prePathMatrix, result);
774 pathPtr = result;
reed@google.comac10a2d2010-12-22 21:39:39 +0000775 }
reed@google.com0c219b62011-02-16 21:31:18 +0000776 // at this point we're done with prePathMatrix
777 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
reed@google.comac10a2d2010-12-22 21:39:39 +0000778
bsalomon@google.com04de7822011-03-25 18:04:43 +0000779 // This "if" is not part of the SkDraw::drawPath() lift.
780 // When we get a 1.0 wide stroke we hairline stroke it instead of creating
781 // a new stroked-path. This is motivated by canvas2D sites that draw
782 // lines as 1.0 wide stroked paths. We can consider doing an alpha-modulated-
783 // hairline for width < 1.0 when AA is enabled.
784 static const int gMatrixMask = ~(SkMatrix::kIdentity_Mask |
785 SkMatrix::kTranslate_Mask);
786 if (!paint.getPathEffect() &&
787 SkPaint::kStroke_Style == paint.getStyle() &&
788 !(draw.fMatrix->getType() & gMatrixMask) &&
789 SK_Scalar1 == paint.getStrokeWidth()) {
790 doFill = false;
791 }
792
793 if (doFill && (paint.getPathEffect() ||
794 paint.getStyle() != SkPaint::kFill_Style)) {
reed@google.com0c219b62011-02-16 21:31:18 +0000795 doFill = paint.getFillPath(*pathPtr, &tmpPath);
796 pathPtr = &tmpPath;
797 }
798
799 // END lift from SkDraw::drawPath()
800
reed@google.com69302852011-02-16 18:08:07 +0000801 if (paint.getMaskFilter()) {
reed@google.com0c219b62011-02-16 21:31:18 +0000802 // avoid possibly allocating a new path in transform if we can
803 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
804
805 // transform the path into device space
reed@google.come3445642011-02-16 23:20:39 +0000806 pathPtr->transform(*draw.fMatrix, devPathPtr);
reed@google.com0c219b62011-02-16 21:31:18 +0000807
808 drawWithMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
reed@google.com69302852011-02-16 18:08:07 +0000809 *draw.fMatrix, *draw.fClip, draw.fBounder, &grPaint);
810 return;
811 }
reed@google.com69302852011-02-16 18:08:07 +0000812
bsalomon@google.comffca4002011-02-22 20:34:01 +0000813 GrPathFill fill = kHairLine_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000814
reed@google.com0c219b62011-02-16 21:31:18 +0000815 if (doFill) {
816 switch (pathPtr->getFillType()) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000817 case SkPath::kWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000818 fill = kWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000819 break;
820 case SkPath::kEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000821 fill = kEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000822 break;
823 case SkPath::kInverseWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000824 fill = kInverseWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000825 break;
826 case SkPath::kInverseEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000827 fill = kInverseEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000828 break;
829 default:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000830 SkDebugf("Unsupported path fill type\n");
reed@google.comac10a2d2010-12-22 21:39:39 +0000831 return;
832 }
833 }
834
reed@google.com0c219b62011-02-16 21:31:18 +0000835 SkGrPathIter iter(*pathPtr);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000836 fContext->drawPath(grPaint, &iter, fill);
reed@google.comac10a2d2010-12-22 21:39:39 +0000837}
838
reed@google.comac10a2d2010-12-22 21:39:39 +0000839void SkGpuDevice::drawBitmap(const SkDraw& draw,
840 const SkBitmap& bitmap,
841 const SkIRect* srcRectPtr,
842 const SkMatrix& m,
843 const SkPaint& paint) {
844 CHECK_SHOULD_DRAW(draw);
845
846 SkIRect srcRect;
847 if (NULL == srcRectPtr) {
848 srcRect.set(0, 0, bitmap.width(), bitmap.height());
849 } else {
850 srcRect = *srcRectPtr;
851 }
852
bsalomon@google.com5782d712011-01-21 21:03:59 +0000853 GrPaint grPaint;
854 if (!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
855 return;
856 }
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000857 if (paint.isFilterBitmap()) {
858 grPaint.fSampler.setFilter(GrSamplerState::kBilinear_Filter);
859 } else {
860 grPaint.fSampler.setFilter(GrSamplerState::kNearest_Filter);
861 }
862
bsalomon@google.com5782d712011-01-21 21:03:59 +0000863
reed@google.com02a7e6c2011-01-28 21:21:49 +0000864 const int maxTextureDim = fContext->getMaxTextureDimension();
865 if (bitmap.getTexture() || (bitmap.width() <= maxTextureDim &&
866 bitmap.height() <= maxTextureDim)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000867 // take the fast case
bsalomon@google.com5782d712011-01-21 21:03:59 +0000868 this->internalDrawBitmap(draw, bitmap, srcRect, m, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000869 return;
870 }
871
872 // undo the translate done by SkCanvas
873 int DX = SkMax32(0, srcRect.fLeft);
874 int DY = SkMax32(0, srcRect.fTop);
875 // compute clip bounds in local coordinates
876 SkIRect clipRect;
877 {
878 SkRect r;
879 r.set(draw.fClip->getBounds());
880 SkMatrix matrix, inverse;
881 matrix.setConcat(*draw.fMatrix, m);
882 if (!matrix.invert(&inverse)) {
883 return;
884 }
885 inverse.mapRect(&r);
886 r.roundOut(&clipRect);
887 // apply the canvas' translate to our local clip
888 clipRect.offset(DX, DY);
889 }
890
reed@google.com02a7e6c2011-01-28 21:21:49 +0000891 int nx = bitmap.width() / maxTextureDim;
892 int ny = bitmap.height() / maxTextureDim;
reed@google.comac10a2d2010-12-22 21:39:39 +0000893 for (int x = 0; x <= nx; x++) {
894 for (int y = 0; y <= ny; y++) {
895 SkIRect tileR;
reed@google.com02a7e6c2011-01-28 21:21:49 +0000896 tileR.set(x * maxTextureDim, y * maxTextureDim,
897 (x + 1) * maxTextureDim, (y + 1) * maxTextureDim);
reed@google.comac10a2d2010-12-22 21:39:39 +0000898 if (!SkIRect::Intersects(tileR, clipRect)) {
899 continue;
900 }
901
902 SkIRect srcR = tileR;
903 if (!srcR.intersect(srcRect)) {
904 continue;
905 }
906
907 SkBitmap tmpB;
908 if (bitmap.extractSubset(&tmpB, tileR)) {
909 // now offset it to make it "local" to our tmp bitmap
910 srcR.offset(-tileR.fLeft, -tileR.fTop);
911
912 SkMatrix tmpM(m);
913 {
914 int dx = tileR.fLeft - DX + SkMax32(0, srcR.fLeft);
915 int dy = tileR.fTop - DY + SkMax32(0, srcR.fTop);
916 tmpM.preTranslate(SkIntToScalar(dx), SkIntToScalar(dy));
917 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000918 this->internalDrawBitmap(draw, tmpB, srcR, tmpM, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000919 }
920 }
921 }
922}
923
924/*
925 * This is called by drawBitmap(), which has to handle images that may be too
926 * large to be represented by a single texture.
927 *
bsalomon@google.com5782d712011-01-21 21:03:59 +0000928 * internalDrawBitmap assumes that the specified bitmap will fit in a texture
929 * and that non-texture portion of the GrPaint has already been setup.
reed@google.comac10a2d2010-12-22 21:39:39 +0000930 */
931void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
932 const SkBitmap& bitmap,
933 const SkIRect& srcRect,
934 const SkMatrix& m,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000935 GrPaint* grPaint) {
reed@google.com02a7e6c2011-01-28 21:21:49 +0000936 SkASSERT(bitmap.width() <= fContext->getMaxTextureDimension() &&
937 bitmap.height() <= fContext->getMaxTextureDimension());
reed@google.comac10a2d2010-12-22 21:39:39 +0000938
939 SkAutoLockPixels alp(bitmap);
940 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
941 return;
942 }
943
bsalomon@google.com5782d712011-01-21 21:03:59 +0000944 grPaint->fSampler.setWrapX(GrSamplerState::kClamp_WrapMode);
945 grPaint->fSampler.setWrapY(GrSamplerState::kClamp_WrapMode);
946 grPaint->fSampler.setSampleMode(GrSamplerState::kNormal_SampleMode);
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000947 grPaint->fSampler.setMatrix(GrMatrix::I());
reed@google.comac10a2d2010-12-22 21:39:39 +0000948
949 GrTexture* texture;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000950 SkAutoCachedTexture act(this, bitmap, grPaint->fSampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000951 if (NULL == texture) {
952 return;
953 }
954
bsalomon@google.com5782d712011-01-21 21:03:59 +0000955 grPaint->setTexture(texture);
reed@google.com46799cd2011-02-22 20:56:26 +0000956
reed@google.com20efde72011-05-09 17:00:02 +0000957 GrRect dstRect = SkRect::MakeWH(GrIntToScalar(srcRect.width()),
958 GrIntToScalar(srcRect.height()));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000959 GrRect paintRect;
960 paintRect.setLTRB(GrFixedToScalar((srcRect.fLeft << 16) / bitmap.width()),
961 GrFixedToScalar((srcRect.fTop << 16) / bitmap.height()),
962 GrFixedToScalar((srcRect.fRight << 16) / bitmap.width()),
963 GrFixedToScalar((srcRect.fBottom << 16) / bitmap.height()));
reed@google.comac10a2d2010-12-22 21:39:39 +0000964
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000965 fContext->drawRectToRect(*grPaint, dstRect, paintRect, &m);
reed@google.comac10a2d2010-12-22 21:39:39 +0000966}
967
968void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
969 int left, int top, const SkPaint& paint) {
970 CHECK_SHOULD_DRAW(draw);
971
972 SkAutoLockPixels alp(bitmap);
973 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
974 return;
975 }
976
bsalomon@google.com5782d712011-01-21 21:03:59 +0000977 GrPaint grPaint;
978 if(!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
979 return;
980 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000981
bsalomon@google.com5782d712011-01-21 21:03:59 +0000982 GrAutoMatrix avm(fContext, GrMatrix::I());
983
984 GrTexture* texture;
985 grPaint.fSampler.setClampNoFilter();
986 SkAutoCachedTexture act(this, bitmap, grPaint.fSampler, &texture);
987
bsalomon@google.com5782d712011-01-21 21:03:59 +0000988 grPaint.setTexture(texture);
989
bsalomon@google.com5782d712011-01-21 21:03:59 +0000990 fContext->drawRectToRect(grPaint,
reed@google.com20efde72011-05-09 17:00:02 +0000991 GrRect::MakeXYWH(GrIntToScalar(left),
992 GrIntToScalar(top),
993 GrIntToScalar(bitmap.width()),
994 GrIntToScalar(bitmap.height())),
995 GrRect::MakeWH(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.com20efde72011-05-09 17:00:02 +00001019 GrRect::MakeXYWH(GrIntToScalar(x),
1020 GrIntToScalar(y),
1021 GrIntToScalar(w),
1022 GrIntToScalar(h)),
1023 GrRect::MakeWH(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 {
reed@google.comac10a2d2010-12-22 21:39:39 +00001165 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001166
1167 GrPaint grPaint;
1168 SkAutoCachedTexture act;
1169
1170 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1171 return;
1172 }
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001173 GrTextContext context(fContext, grPaint, draw.fExtMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001174 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001175 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
1176 }
1177}
1178
1179void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
1180 size_t byteLength, const SkScalar pos[],
1181 SkScalar constY, int scalarsPerPos,
1182 const SkPaint& paint) {
1183 CHECK_SHOULD_DRAW(draw);
1184
1185 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1186 // this guy will just call our drawPath()
1187 draw.drawPosText((const char*)text, byteLength, pos, constY,
1188 scalarsPerPos, paint);
1189 } else {
reed@google.comac10a2d2010-12-22 21:39:39 +00001190 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001191
1192 GrPaint grPaint;
1193 SkAutoCachedTexture act;
1194 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1195 return;
1196 }
1197
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001198 GrTextContext context(fContext, grPaint, draw.fExtMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001199 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001200 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
1201 scalarsPerPos, paint);
1202 }
1203}
1204
1205void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
1206 size_t len, const SkPath& path,
1207 const SkMatrix* m, const SkPaint& paint) {
1208 CHECK_SHOULD_DRAW(draw);
1209
1210 SkASSERT(draw.fDevice == this);
1211 draw.drawTextOnPath((const char*)text, len, path, m, paint);
1212}
1213
1214///////////////////////////////////////////////////////////////////////////////
1215
reed@google.comf67e4cf2011-03-15 20:56:58 +00001216bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
1217 if (!paint.isLCDRenderText()) {
1218 // we're cool with the paint as is
1219 return false;
1220 }
1221
1222 if (paint.getShader() ||
1223 paint.getXfermode() || // unless its srcover
1224 paint.getMaskFilter() ||
1225 paint.getRasterizer() ||
1226 paint.getColorFilter() ||
1227 paint.getPathEffect() ||
1228 paint.isFakeBoldText() ||
1229 paint.getStyle() != SkPaint::kFill_Style) {
1230 // turn off lcd
1231 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
1232 flags->fHinting = paint.getHinting();
1233 return true;
1234 }
1235 // we're cool with the paint as is
1236 return false;
1237}
1238
1239///////////////////////////////////////////////////////////////////////////////
1240
reed@google.comac10a2d2010-12-22 21:39:39 +00001241SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001242 const GrSamplerState& sampler,
1243 GrTexture** texture,
1244 bool forDeviceRenderTarget) {
1245 GrTexture* newTexture = NULL;
1246 GrTextureEntry* entry = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +00001247 GrContext* ctx = this->context();
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001248
reed@google.comac10a2d2010-12-22 21:39:39 +00001249 if (forDeviceRenderTarget) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001250 const GrTextureDesc desc = {
1251 kRenderTarget_GrTextureFlagBit,
1252 kNone_GrAALevel,
1253 bitmap.width(),
1254 bitmap.height(),
1255 SkGr::Bitmap2PixelConfig(bitmap)
1256 };
bsalomon@google.coma39f4042011-04-26 13:18:16 +00001257 entry = ctx->lockKeylessTexture(desc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001258 } else {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001259 uint32_t p0, p1;
reed@google.comac10a2d2010-12-22 21:39:39 +00001260 p0 = bitmap.getGenerationID();
1261 p1 = bitmap.pixelRefOffset();
reed@google.comac10a2d2010-12-22 21:39:39 +00001262
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001263 GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
1264 entry = ctx->findAndLockTexture(&key, sampler);
reed@google.comac10a2d2010-12-22 21:39:39 +00001265
reed@google.comac10a2d2010-12-22 21:39:39 +00001266 if (NULL == entry) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001267 entry = sk_gr_create_bitmap_texture(ctx, &key, sampler, bitmap);
1268 if (NULL == entry) {
1269 GrPrintf("---- failed to create texture for cache [%d %d]\n",
1270 bitmap.width(), bitmap.height());
1271 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001272 }
1273 }
1274
1275 if (NULL != entry) {
1276 newTexture = entry->texture();
reed@google.comac10a2d2010-12-22 21:39:39 +00001277 if (texture) {
1278 *texture = newTexture;
1279 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001280 }
1281 return (TexCache*)entry;
1282}
1283
1284void SkGpuDevice::unlockCachedTexture(TexCache* cache) {
1285 this->context()->unlockTexture((GrTextureEntry*)cache);
1286}
1287
reed@google.com7b201d22011-01-11 18:59:23 +00001288///////////////////////////////////////////////////////////////////////////////
1289
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001290SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context,
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001291 GrRenderTarget* rootRenderTarget) {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001292 GrAssert(NULL != context);
1293 GrAssert(NULL != rootRenderTarget);
1294
1295 // check this now rather than passing this value to SkGpuDevice cons.
1296 // we want the rt that is bound *now* in the 3D API, not the one
1297 // at the time of newDevice.
1298 if (SkGpuDevice::Current3DApiRenderTarget() == rootRenderTarget) {
1299 fRootRenderTarget = context->createRenderTargetFrom3DApiState();
1300 } else {
1301 fRootRenderTarget = rootRenderTarget;
1302 rootRenderTarget->ref();
1303 }
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001304
1305 fContext = context;
reed@google.com7b201d22011-01-11 18:59:23 +00001306 context->ref();
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001307
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001308 fRootTexture = NULL;
1309}
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001310
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001311SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context, GrTexture* rootRenderTargetTexture) {
1312 GrAssert(NULL != context);
1313 GrAssert(NULL != rootRenderTargetTexture);
1314 GrAssert(NULL != rootRenderTargetTexture->asRenderTarget());
1315
1316 fRootTexture = rootRenderTargetTexture;
1317 rootRenderTargetTexture->ref();
1318
1319 fRootRenderTarget = rootRenderTargetTexture->asRenderTarget();
1320 fRootRenderTarget->ref();
1321
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001322 fContext = context;
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001323 context->ref();
reed@google.com7b201d22011-01-11 18:59:23 +00001324}
1325
1326SkGpuDeviceFactory::~SkGpuDeviceFactory() {
1327 fContext->unref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001328 fRootRenderTarget->unref();
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001329 GrSafeUnref(fRootTexture);
reed@google.com7b201d22011-01-11 18:59:23 +00001330}
1331
1332SkDevice* SkGpuDeviceFactory::newDevice(SkCanvas*, SkBitmap::Config config,
1333 int width, int height,
1334 bool isOpaque, bool isLayer) {
1335 SkBitmap bm;
1336 bm.setConfig(config, width, height);
1337 bm.setIsOpaque(isOpaque);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001338 return new SkGpuDevice(fContext, bm, isLayer ? NULL : fRootRenderTarget);
reed@google.com7b201d22011-01-11 18:59:23 +00001339}