blob: afea47ae7767376e30d002fd551f3b5d688b7df4 [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,
Scroggod757df22011-05-16 13:11:16 +0000345 GrPaint* grPaint,
346 bool constantColor) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000347
348 grPaint->fDither = skPaint.isDither();
349 grPaint->fAntiAlias = skPaint.isAntiAlias();
350
351 SkXfermode::Coeff sm = SkXfermode::kOne_Coeff;
352 SkXfermode::Coeff dm = SkXfermode::kISA_Coeff;
353
354 SkXfermode* mode = skPaint.getXfermode();
355 if (mode) {
356 if (!mode->asCoeff(&sm, &dm)) {
reed@google.com1a2e8d22011-01-21 22:08:29 +0000357 SkDEBUGCODE(SkDebugf("Unsupported xfer mode.\n");)
bsalomon@google.com5782d712011-01-21 21:03:59 +0000358#if 0
359 return false;
360#endif
361 }
362 }
363 grPaint->fSrcBlendCoeff = sk_blend_to_grblend(sm);
364 grPaint->fDstBlendCoeff = sk_blend_to_grblend(dm);
365
366 if (justAlpha) {
367 uint8_t alpha = skPaint.getAlpha();
368 grPaint->fColor = GrColorPackRGBA(alpha, alpha, alpha, alpha);
Scroggod757df22011-05-16 13:11:16 +0000369 // justAlpha is currently set to true only if there is a texture,
370 // so constantColor should not also be true.
371 GrAssert(!constantColor);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000372 } else {
373 grPaint->fColor = SkGr::SkColor2GrColor(skPaint.getColor());
374 grPaint->setTexture(NULL);
375 }
Scroggo97c88c22011-05-11 14:05:25 +0000376 SkColorFilter* colorFilter = skPaint.getColorFilter();
377 SkColor color;
378 SkXfermode::Mode filterMode;
379 if (colorFilter != NULL && colorFilter->asColorMode(&color, &filterMode)) {
Scroggod757df22011-05-16 13:11:16 +0000380 if (!constantColor) {
381 grPaint->fColorFilterColor = SkGr::SkColor2GrColor(color);
382 grPaint->fColorFilterXfermode = filterMode;
383 return true;
384 }
385 SkColor filtered = colorFilter->filterColor(skPaint.getColor());
386 grPaint->fColor = SkGr::SkColor2GrColor(filtered);
Scroggo97c88c22011-05-11 14:05:25 +0000387 }
Scroggod757df22011-05-16 13:11:16 +0000388 grPaint->resetColorFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +0000389 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000390}
391
bsalomon@google.com5782d712011-01-21 21:03:59 +0000392bool SkGpuDevice::skPaint2GrPaintShader(const SkPaint& skPaint,
393 SkAutoCachedTexture* act,
394 const SkMatrix& ctm,
Scroggod757df22011-05-16 13:11:16 +0000395 GrPaint* grPaint,
396 bool constantColor) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000397
bsalomon@google.com5782d712011-01-21 21:03:59 +0000398 SkASSERT(NULL != act);
reed@google.comac10a2d2010-12-22 21:39:39 +0000399
bsalomon@google.com5782d712011-01-21 21:03:59 +0000400 SkShader* shader = skPaint.getShader();
reed@google.comac10a2d2010-12-22 21:39:39 +0000401 if (NULL == shader) {
Scroggod757df22011-05-16 13:11:16 +0000402 return this->skPaint2GrPaintNoShader(skPaint,
403 false,
404 grPaint,
405 constantColor);
406 } else if (!this->skPaint2GrPaintNoShader(skPaint, true, grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000407 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000408 }
409
bsalomon@google.com5782d712011-01-21 21:03:59 +0000410 SkPaint noAlphaPaint(skPaint);
411 noAlphaPaint.setAlpha(255);
412 shader->setContext(this->accessBitmap(false), noAlphaPaint, ctm);
reed@google.comac10a2d2010-12-22 21:39:39 +0000413
reed@google.comac10a2d2010-12-22 21:39:39 +0000414 SkBitmap bitmap;
415 SkMatrix matrix;
416 SkShader::TileMode tileModes[2];
417 SkScalar twoPointParams[3];
418 SkShader::BitmapType bmptype = shader->asABitmap(&bitmap, &matrix,
419 tileModes, twoPointParams);
420
bsalomon@google.com5782d712011-01-21 21:03:59 +0000421 GrSamplerState::SampleMode sampleMode = sk_bmp_type_to_sample_mode[bmptype];
422 if (-1 == sampleMode) {
423 SkDebugf("shader->asABitmap() == kNone_BitmapType\n");
424 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000425 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000426 grPaint->fSampler.setSampleMode(sampleMode);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000427 if (skPaint.isFilterBitmap()) {
428 grPaint->fSampler.setFilter(GrSamplerState::kBilinear_Filter);
429 } else {
430 grPaint->fSampler.setFilter(GrSamplerState::kNearest_Filter);
431 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000432 grPaint->fSampler.setWrapX(sk_tile_mode_to_grwrap(tileModes[0]));
433 grPaint->fSampler.setWrapY(sk_tile_mode_to_grwrap(tileModes[1]));
reed@google.comac10a2d2010-12-22 21:39:39 +0000434 if (GrSamplerState::kRadial2_SampleMode == sampleMode) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000435 grPaint->fSampler.setRadial2Params(twoPointParams[0],
436 twoPointParams[1],
437 twoPointParams[2] < 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000438 }
439
bsalomon@google.com5782d712011-01-21 21:03:59 +0000440 GrTexture* texture = act->set(this, bitmap, grPaint->fSampler);
reed@google.comac10a2d2010-12-22 21:39:39 +0000441 if (NULL == texture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000442 SkDebugf("Couldn't convert bitmap to texture.\n");
443 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000444 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000445 grPaint->setTexture(texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000446
447 // since our texture coords will be in local space, we wack the texture
448 // matrix to map them back into 0...1 before we load it
449 SkMatrix localM;
450 if (shader->getLocalMatrix(&localM)) {
451 SkMatrix inverse;
452 if (localM.invert(&inverse)) {
453 matrix.preConcat(inverse);
454 }
455 }
456 if (SkShader::kDefault_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000457 GrScalar sx = GrFixedToScalar(GR_Fixed1 / bitmap.width());
458 GrScalar sy = GrFixedToScalar(GR_Fixed1 / bitmap.height());
reed@google.comac10a2d2010-12-22 21:39:39 +0000459 matrix.postScale(sx, sy);
reed@google.comac10a2d2010-12-22 21:39:39 +0000460 } else if (SkShader::kRadial_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000461 GrScalar s = GrFixedToScalar(GR_Fixed1 / bitmap.width());
reed@google.comac10a2d2010-12-22 21:39:39 +0000462 matrix.postScale(s, s);
463 }
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000464 grPaint->fSampler.setMatrix(matrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000465
466 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000467}
468
469///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com5782d712011-01-21 21:03:59 +0000470
471class SkPositionSource {
472public:
473 SkPositionSource(const SkPoint* points, int count)
474 : fPoints(points), fCount(count) {}
475
476 int count() const { return fCount; }
477
478 void writeValue(int i, GrPoint* dstPosition) const {
479 SkASSERT(i < fCount);
480 dstPosition->fX = SkScalarToGrScalar(fPoints[i].fX);
481 dstPosition->fY = SkScalarToGrScalar(fPoints[i].fY);
482 }
483private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000484 const SkPoint* fPoints;
bsalomon@google.com19628322011-02-03 21:30:17 +0000485 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000486};
487
488class SkTexCoordSource {
489public:
490 SkTexCoordSource(const SkPoint* coords)
491 : fCoords(coords) {}
492
493 void writeValue(int i, GrPoint* dstCoord) const {
494 dstCoord->fX = SkScalarToGrScalar(fCoords[i].fX);
495 dstCoord->fY = SkScalarToGrScalar(fCoords[i].fY);
496 }
497private:
498 const SkPoint* fCoords;
499};
500
501class SkColorSource {
502public:
503 SkColorSource(const SkColor* colors) : fColors(colors) {}
504
505 void writeValue(int i, GrColor* dstColor) const {
506 *dstColor = SkGr::SkColor2GrColor(fColors[i]);
507 }
508private:
509 const SkColor* fColors;
510};
511
512class SkIndexSource {
513public:
514 SkIndexSource(const uint16_t* indices, int count)
515 : fIndices(indices), fCount(count) {
516 }
517
518 int count() const { return fCount; }
519
520 void writeValue(int i, uint16_t* dstIndex) const {
521 *dstIndex = fIndices[i];
522 }
523
524private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000525 const uint16_t* fIndices;
bsalomon@google.com19628322011-02-03 21:30:17 +0000526 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000527};
528
529///////////////////////////////////////////////////////////////////////////////
530
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000531#if 0 // not currently being used so don't compile,
532
bsalomon@google.com5782d712011-01-21 21:03:59 +0000533// can be used for positions or texture coordinates
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000534
bsalomon@google.com5782d712011-01-21 21:03:59 +0000535class SkRectFanSource {
536public:
537 SkRectFanSource(const SkRect& rect) : fRect(rect) {}
538
539 int count() const { return 4; }
540
541 void writeValue(int i, GrPoint* dstPoint) const {
542 SkASSERT(i < 4);
543 dstPoint->fX = SkScalarToGrScalar((i % 3) ? fRect.fRight :
544 fRect.fLeft);
545 dstPoint->fY = SkScalarToGrScalar((i < 2) ? fRect.fTop :
546 fRect.fBottom);
547 }
548private:
549 const SkRect& fRect;
550};
551
552class SkIRectFanSource {
553public:
554 SkIRectFanSource(const SkIRect& rect) : fRect(rect) {}
555
556 int count() const { return 4; }
557
558 void writeValue(int i, GrPoint* dstPoint) const {
559 SkASSERT(i < 4);
560 dstPoint->fX = (i % 3) ? GrIntToScalar(fRect.fRight) :
561 GrIntToScalar(fRect.fLeft);
562 dstPoint->fY = (i < 2) ? GrIntToScalar(fRect.fTop) :
563 GrIntToScalar(fRect.fBottom);
564 }
565private:
566 const SkIRect& fRect;
567};
568
569class SkMatRectFanSource {
570public:
571 SkMatRectFanSource(const SkRect& rect, const SkMatrix& matrix)
572 : fRect(rect), fMatrix(matrix) {}
573
574 int count() const { return 4; }
575
576 void writeValue(int i, GrPoint* dstPoint) const {
577 SkASSERT(i < 4);
578
579#if SK_SCALAR_IS_GR_SCALAR
580 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
581 (i < 2) ? fRect.fTop : fRect.fBottom,
582 (SkPoint*)dstPoint);
583#else
584 SkPoint dst;
585 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
586 (i < 2) ? fRect.fTop : fRect.fBottom,
587 &dst);
588 dstPoint->fX = SkScalarToGrScalar(dst.fX);
589 dstPoint->fY = SkScalarToGrScalar(dst.fY);
590#endif
591 }
592private:
593 const SkRect& fRect;
594 const SkMatrix& fMatrix;
595};
596
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000597#endif
598
reed@google.comac10a2d2010-12-22 21:39:39 +0000599///////////////////////////////////////////////////////////////////////////////
600
bsalomon@google.com398109c2011-04-14 18:40:27 +0000601void SkGpuDevice::clear(SkColor color) {
bsalomon@google.com31a58402011-04-27 21:00:02 +0000602 fContext->clear(NULL, color);
bsalomon@google.com398109c2011-04-14 18:40:27 +0000603}
604
reed@google.comac10a2d2010-12-22 21:39:39 +0000605void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
606 CHECK_SHOULD_DRAW(draw);
607
bsalomon@google.com5782d712011-01-21 21:03:59 +0000608 GrPaint grPaint;
609 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000610 if (!this->skPaint2GrPaintShader(paint,
611 &act,
612 *draw.fMatrix,
613 &grPaint,
614 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000615 return;
616 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000617
618 fContext->drawPaint(grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000619}
620
621// must be in SkCanvas::PointMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +0000622static const GrPrimitiveType gPointMode2PrimtiveType[] = {
623 kPoints_PrimitiveType,
624 kLines_PrimitiveType,
625 kLineStrip_PrimitiveType
reed@google.comac10a2d2010-12-22 21:39:39 +0000626};
627
628void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000629 size_t count, const SkPoint pts[], const SkPaint& paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000630 CHECK_SHOULD_DRAW(draw);
631
632 SkScalar width = paint.getStrokeWidth();
633 if (width < 0) {
634 return;
635 }
636
637 // we only handle hairlines here, else we let the SkDraw call our drawPath()
638 if (width > 0) {
639 draw.drawPoints(mode, count, pts, paint, true);
640 return;
641 }
642
bsalomon@google.com5782d712011-01-21 21:03:59 +0000643 GrPaint grPaint;
644 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000645 if (!this->skPaint2GrPaintShader(paint,
646 &act,
647 *draw.fMatrix,
648 &grPaint,
649 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000650 return;
651 }
652
reed@google.comac10a2d2010-12-22 21:39:39 +0000653#if SK_SCALAR_IS_GR_SCALAR
bsalomon@google.com5782d712011-01-21 21:03:59 +0000654 fContext->drawVertices(grPaint,
655 gPointMode2PrimtiveType[mode],
656 count,
657 (GrPoint*)pts,
658 NULL,
659 NULL,
660 NULL,
661 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000662#else
bsalomon@google.com5782d712011-01-21 21:03:59 +0000663 fContext->drawCustomVertices(grPaint,
664 gPointMode2PrimtiveType[mode],
665 SkPositionSource(pts, count));
reed@google.comac10a2d2010-12-22 21:39:39 +0000666#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000667}
668
reed@google.comc9aa5872011-04-05 21:05:37 +0000669///////////////////////////////////////////////////////////////////////////////
670
reed@google.comac10a2d2010-12-22 21:39:39 +0000671void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
672 const SkPaint& paint) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000673 CHECK_SHOULD_DRAW(draw);
674
675 bool doStroke = paint.getStyle() == SkPaint::kStroke_Style;
676 SkScalar width = paint.getStrokeWidth();
677
678 /*
679 We have special code for hairline strokes, miter-strokes, and fills.
680 Anything else we just call our path code.
681 */
682 bool usePath = doStroke && width > 0 &&
683 paint.getStrokeJoin() != SkPaint::kMiter_Join;
684 // another reason we might need to call drawPath...
685 if (paint.getMaskFilter()) {
686 usePath = true;
687 }
688
689 if (usePath) {
690 SkPath path;
691 path.addRect(rect);
692 this->drawPath(draw, path, paint, NULL, true);
693 return;
694 }
695
696 GrPaint grPaint;
697 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000698 if (!this->skPaint2GrPaintShader(paint,
699 &act,
700 *draw.fMatrix,
701 &grPaint,
702 true)) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000703 return;
704 }
reed@google.com20efde72011-05-09 17:00:02 +0000705 fContext->drawRect(grPaint, rect, doStroke ? width : -1);
reed@google.comac10a2d2010-12-22 21:39:39 +0000706}
707
reed@google.com69302852011-02-16 18:08:07 +0000708#include "SkMaskFilter.h"
709#include "SkBounder.h"
710
reed@google.com69302852011-02-16 18:08:07 +0000711static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
712 SkMaskFilter* filter, const SkMatrix& matrix,
713 const SkRegion& clip, SkBounder* bounder,
714 GrPaint* grp) {
715 SkMask srcM, dstM;
716
717 if (!SkDraw::DrawToMask(path, &clip.getBounds(), filter, &matrix, &srcM,
718 SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
719 return false;
720 }
721
722 SkAutoMaskImage autoSrc(&srcM, false);
723
724 if (!filter->filterMask(&dstM, srcM, matrix, NULL)) {
725 return false;
726 }
727 // this will free-up dstM when we're done (allocated in filterMask())
728 SkAutoMaskImage autoDst(&dstM, false);
729
730 if (clip.quickReject(dstM.fBounds)) {
731 return false;
732 }
733 if (bounder && !bounder->doIRect(dstM.fBounds)) {
734 return false;
735 }
736
737 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
738 // the current clip (and identity matrix) and grpaint settings
739
reed@google.com0c219b62011-02-16 21:31:18 +0000740 GrAutoMatrix avm(context, GrMatrix::I());
reed@google.com69302852011-02-16 18:08:07 +0000741
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000742 const GrTextureDesc desc = {
743 kNone_GrTextureFlags,
744 kNone_GrAALevel,
reed@google.com69302852011-02-16 18:08:07 +0000745 dstM.fBounds.width(),
746 dstM.fBounds.height(),
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000747 kAlpha_8_GrPixelConfig
reed@google.com69302852011-02-16 18:08:07 +0000748 };
749
750 GrTexture* texture = context->createUncachedTexture(desc, dstM.fImage,
751 dstM.fRowBytes);
752 if (NULL == texture) {
753 return false;
754 }
755
reed@google.com0c219b62011-02-16 21:31:18 +0000756 grp->setTexture(texture);
757 texture->unref();
758 grp->fSampler.setClampNoFilter();
reed@google.com69302852011-02-16 18:08:07 +0000759
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000760 GrRect d;
761 d.setLTRB(GrIntToScalar(dstM.fBounds.fLeft),
reed@google.com0c219b62011-02-16 21:31:18 +0000762 GrIntToScalar(dstM.fBounds.fTop),
763 GrIntToScalar(dstM.fBounds.fRight),
764 GrIntToScalar(dstM.fBounds.fBottom));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000765 GrRect s;
766 s.setLTRB(0, 0, GR_Scalar1, GR_Scalar1);
767 context->drawRectToRect(*grp, d, s);
reed@google.com69302852011-02-16 18:08:07 +0000768 return true;
769}
reed@google.com69302852011-02-16 18:08:07 +0000770
reed@google.com0c219b62011-02-16 21:31:18 +0000771void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
reed@google.comac10a2d2010-12-22 21:39:39 +0000772 const SkPaint& paint, const SkMatrix* prePathMatrix,
773 bool pathIsMutable) {
774 CHECK_SHOULD_DRAW(draw);
775
bsalomon@google.com5782d712011-01-21 21:03:59 +0000776 GrPaint grPaint;
777 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000778 if (!this->skPaint2GrPaintShader(paint,
779 &act,
780 *draw.fMatrix,
781 &grPaint,
782 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000783 return;
784 }
785
reed@google.com0c219b62011-02-16 21:31:18 +0000786 // BEGIN lift from SkDraw::drawPath()
787
788 SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
789 bool doFill = true;
790 SkPath tmpPath;
reed@google.comac10a2d2010-12-22 21:39:39 +0000791
792 if (prePathMatrix) {
reed@google.come3445642011-02-16 23:20:39 +0000793 SkPath* result = pathPtr;
reed@google.com0c219b62011-02-16 21:31:18 +0000794
reed@google.come3445642011-02-16 23:20:39 +0000795 if (!pathIsMutable) {
796 result = &tmpPath;
797 pathIsMutable = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000798 }
reed@google.come3445642011-02-16 23:20:39 +0000799 // should I push prePathMatrix on our MV stack temporarily, instead
800 // of applying it here? See SkDraw.cpp
801 pathPtr->transform(*prePathMatrix, result);
802 pathPtr = result;
reed@google.comac10a2d2010-12-22 21:39:39 +0000803 }
reed@google.com0c219b62011-02-16 21:31:18 +0000804 // at this point we're done with prePathMatrix
805 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
reed@google.comac10a2d2010-12-22 21:39:39 +0000806
bsalomon@google.com04de7822011-03-25 18:04:43 +0000807 // This "if" is not part of the SkDraw::drawPath() lift.
808 // When we get a 1.0 wide stroke we hairline stroke it instead of creating
809 // a new stroked-path. This is motivated by canvas2D sites that draw
810 // lines as 1.0 wide stroked paths. We can consider doing an alpha-modulated-
811 // hairline for width < 1.0 when AA is enabled.
812 static const int gMatrixMask = ~(SkMatrix::kIdentity_Mask |
813 SkMatrix::kTranslate_Mask);
814 if (!paint.getPathEffect() &&
815 SkPaint::kStroke_Style == paint.getStyle() &&
816 !(draw.fMatrix->getType() & gMatrixMask) &&
817 SK_Scalar1 == paint.getStrokeWidth()) {
818 doFill = false;
819 }
820
821 if (doFill && (paint.getPathEffect() ||
822 paint.getStyle() != SkPaint::kFill_Style)) {
reed@google.com0c219b62011-02-16 21:31:18 +0000823 doFill = paint.getFillPath(*pathPtr, &tmpPath);
824 pathPtr = &tmpPath;
825 }
826
827 // END lift from SkDraw::drawPath()
828
reed@google.com69302852011-02-16 18:08:07 +0000829 if (paint.getMaskFilter()) {
reed@google.com0c219b62011-02-16 21:31:18 +0000830 // avoid possibly allocating a new path in transform if we can
831 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
832
833 // transform the path into device space
reed@google.come3445642011-02-16 23:20:39 +0000834 pathPtr->transform(*draw.fMatrix, devPathPtr);
reed@google.com0c219b62011-02-16 21:31:18 +0000835
836 drawWithMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
reed@google.com69302852011-02-16 18:08:07 +0000837 *draw.fMatrix, *draw.fClip, draw.fBounder, &grPaint);
838 return;
839 }
reed@google.com69302852011-02-16 18:08:07 +0000840
bsalomon@google.comffca4002011-02-22 20:34:01 +0000841 GrPathFill fill = kHairLine_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000842
reed@google.com0c219b62011-02-16 21:31:18 +0000843 if (doFill) {
844 switch (pathPtr->getFillType()) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000845 case SkPath::kWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000846 fill = kWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000847 break;
848 case SkPath::kEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000849 fill = kEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000850 break;
851 case SkPath::kInverseWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000852 fill = kInverseWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000853 break;
854 case SkPath::kInverseEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000855 fill = kInverseEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000856 break;
857 default:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000858 SkDebugf("Unsupported path fill type\n");
reed@google.comac10a2d2010-12-22 21:39:39 +0000859 return;
860 }
861 }
862
reed@google.com0c219b62011-02-16 21:31:18 +0000863 SkGrPathIter iter(*pathPtr);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000864 fContext->drawPath(grPaint, &iter, fill);
reed@google.comac10a2d2010-12-22 21:39:39 +0000865}
866
reed@google.comac10a2d2010-12-22 21:39:39 +0000867void SkGpuDevice::drawBitmap(const SkDraw& draw,
868 const SkBitmap& bitmap,
869 const SkIRect* srcRectPtr,
870 const SkMatrix& m,
871 const SkPaint& paint) {
872 CHECK_SHOULD_DRAW(draw);
873
874 SkIRect srcRect;
875 if (NULL == srcRectPtr) {
876 srcRect.set(0, 0, bitmap.width(), bitmap.height());
877 } else {
878 srcRect = *srcRectPtr;
879 }
880
bsalomon@google.com5782d712011-01-21 21:03:59 +0000881 GrPaint grPaint;
Scroggod757df22011-05-16 13:11:16 +0000882 if (!this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000883 return;
884 }
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000885 if (paint.isFilterBitmap()) {
886 grPaint.fSampler.setFilter(GrSamplerState::kBilinear_Filter);
887 } else {
888 grPaint.fSampler.setFilter(GrSamplerState::kNearest_Filter);
889 }
890
bsalomon@google.com5782d712011-01-21 21:03:59 +0000891
reed@google.com02a7e6c2011-01-28 21:21:49 +0000892 const int maxTextureDim = fContext->getMaxTextureDimension();
893 if (bitmap.getTexture() || (bitmap.width() <= maxTextureDim &&
894 bitmap.height() <= maxTextureDim)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000895 // take the fast case
bsalomon@google.com5782d712011-01-21 21:03:59 +0000896 this->internalDrawBitmap(draw, bitmap, srcRect, m, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000897 return;
898 }
899
900 // undo the translate done by SkCanvas
901 int DX = SkMax32(0, srcRect.fLeft);
902 int DY = SkMax32(0, srcRect.fTop);
903 // compute clip bounds in local coordinates
904 SkIRect clipRect;
905 {
906 SkRect r;
907 r.set(draw.fClip->getBounds());
908 SkMatrix matrix, inverse;
909 matrix.setConcat(*draw.fMatrix, m);
910 if (!matrix.invert(&inverse)) {
911 return;
912 }
913 inverse.mapRect(&r);
914 r.roundOut(&clipRect);
915 // apply the canvas' translate to our local clip
916 clipRect.offset(DX, DY);
917 }
918
reed@google.com02a7e6c2011-01-28 21:21:49 +0000919 int nx = bitmap.width() / maxTextureDim;
920 int ny = bitmap.height() / maxTextureDim;
reed@google.comac10a2d2010-12-22 21:39:39 +0000921 for (int x = 0; x <= nx; x++) {
922 for (int y = 0; y <= ny; y++) {
923 SkIRect tileR;
reed@google.com02a7e6c2011-01-28 21:21:49 +0000924 tileR.set(x * maxTextureDim, y * maxTextureDim,
925 (x + 1) * maxTextureDim, (y + 1) * maxTextureDim);
reed@google.comac10a2d2010-12-22 21:39:39 +0000926 if (!SkIRect::Intersects(tileR, clipRect)) {
927 continue;
928 }
929
930 SkIRect srcR = tileR;
931 if (!srcR.intersect(srcRect)) {
932 continue;
933 }
934
935 SkBitmap tmpB;
936 if (bitmap.extractSubset(&tmpB, tileR)) {
937 // now offset it to make it "local" to our tmp bitmap
938 srcR.offset(-tileR.fLeft, -tileR.fTop);
939
940 SkMatrix tmpM(m);
941 {
942 int dx = tileR.fLeft - DX + SkMax32(0, srcR.fLeft);
943 int dy = tileR.fTop - DY + SkMax32(0, srcR.fTop);
944 tmpM.preTranslate(SkIntToScalar(dx), SkIntToScalar(dy));
945 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000946 this->internalDrawBitmap(draw, tmpB, srcR, tmpM, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000947 }
948 }
949 }
950}
951
952/*
953 * This is called by drawBitmap(), which has to handle images that may be too
954 * large to be represented by a single texture.
955 *
bsalomon@google.com5782d712011-01-21 21:03:59 +0000956 * internalDrawBitmap assumes that the specified bitmap will fit in a texture
957 * and that non-texture portion of the GrPaint has already been setup.
reed@google.comac10a2d2010-12-22 21:39:39 +0000958 */
959void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
960 const SkBitmap& bitmap,
961 const SkIRect& srcRect,
962 const SkMatrix& m,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000963 GrPaint* grPaint) {
reed@google.com02a7e6c2011-01-28 21:21:49 +0000964 SkASSERT(bitmap.width() <= fContext->getMaxTextureDimension() &&
965 bitmap.height() <= fContext->getMaxTextureDimension());
reed@google.comac10a2d2010-12-22 21:39:39 +0000966
967 SkAutoLockPixels alp(bitmap);
968 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
969 return;
970 }
971
bsalomon@google.com5782d712011-01-21 21:03:59 +0000972 grPaint->fSampler.setWrapX(GrSamplerState::kClamp_WrapMode);
973 grPaint->fSampler.setWrapY(GrSamplerState::kClamp_WrapMode);
974 grPaint->fSampler.setSampleMode(GrSamplerState::kNormal_SampleMode);
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000975 grPaint->fSampler.setMatrix(GrMatrix::I());
reed@google.comac10a2d2010-12-22 21:39:39 +0000976
977 GrTexture* texture;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000978 SkAutoCachedTexture act(this, bitmap, grPaint->fSampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000979 if (NULL == texture) {
980 return;
981 }
982
bsalomon@google.com5782d712011-01-21 21:03:59 +0000983 grPaint->setTexture(texture);
reed@google.com46799cd2011-02-22 20:56:26 +0000984
reed@google.com20efde72011-05-09 17:00:02 +0000985 GrRect dstRect = SkRect::MakeWH(GrIntToScalar(srcRect.width()),
986 GrIntToScalar(srcRect.height()));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000987 GrRect paintRect;
988 paintRect.setLTRB(GrFixedToScalar((srcRect.fLeft << 16) / bitmap.width()),
989 GrFixedToScalar((srcRect.fTop << 16) / bitmap.height()),
990 GrFixedToScalar((srcRect.fRight << 16) / bitmap.width()),
991 GrFixedToScalar((srcRect.fBottom << 16) / bitmap.height()));
reed@google.comac10a2d2010-12-22 21:39:39 +0000992
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000993 fContext->drawRectToRect(*grPaint, dstRect, paintRect, &m);
reed@google.comac10a2d2010-12-22 21:39:39 +0000994}
995
996void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
997 int left, int top, const SkPaint& paint) {
998 CHECK_SHOULD_DRAW(draw);
999
1000 SkAutoLockPixels alp(bitmap);
1001 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
1002 return;
1003 }
1004
bsalomon@google.com5782d712011-01-21 21:03:59 +00001005 GrPaint grPaint;
Scroggod757df22011-05-16 13:11:16 +00001006 if(!this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001007 return;
1008 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001009
bsalomon@google.com5782d712011-01-21 21:03:59 +00001010 GrAutoMatrix avm(fContext, GrMatrix::I());
1011
1012 GrTexture* texture;
1013 grPaint.fSampler.setClampNoFilter();
1014 SkAutoCachedTexture act(this, bitmap, grPaint.fSampler, &texture);
1015
bsalomon@google.com5782d712011-01-21 21:03:59 +00001016 grPaint.setTexture(texture);
1017
bsalomon@google.com5782d712011-01-21 21:03:59 +00001018 fContext->drawRectToRect(grPaint,
reed@google.com20efde72011-05-09 17:00:02 +00001019 GrRect::MakeXYWH(GrIntToScalar(left),
1020 GrIntToScalar(top),
1021 GrIntToScalar(bitmap.width()),
1022 GrIntToScalar(bitmap.height())),
1023 GrRect::MakeWH(GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001024}
1025
1026void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
1027 int x, int y, const SkPaint& paint) {
1028 CHECK_SHOULD_DRAW(draw);
1029
bsalomon@google.com5782d712011-01-21 21:03:59 +00001030 GrPaint grPaint;
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001031 if (!((SkGpuDevice*)dev)->bindDeviceAsTexture(&grPaint) ||
Scroggod757df22011-05-16 13:11:16 +00001032 !this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001033 return;
reed@google.comac10a2d2010-12-22 21:39:39 +00001034 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001035
1036 SkASSERT(NULL != grPaint.getTexture());
1037
1038 const SkBitmap& bm = dev->accessBitmap(false);
1039 int w = bm.width();
1040 int h = bm.height();
1041
1042 GrAutoMatrix avm(fContext, GrMatrix::I());
1043
1044 grPaint.fSampler.setClampNoFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +00001045
1046 fContext->drawRectToRect(grPaint,
reed@google.com20efde72011-05-09 17:00:02 +00001047 GrRect::MakeXYWH(GrIntToScalar(x),
1048 GrIntToScalar(y),
1049 GrIntToScalar(w),
1050 GrIntToScalar(h)),
1051 GrRect::MakeWH(GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001052}
1053
1054///////////////////////////////////////////////////////////////////////////////
1055
1056// must be in SkCanvas::VertexMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +00001057static const GrPrimitiveType gVertexMode2PrimitiveType[] = {
1058 kTriangles_PrimitiveType,
1059 kTriangleStrip_PrimitiveType,
1060 kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +00001061};
1062
1063void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
1064 int vertexCount, const SkPoint vertices[],
1065 const SkPoint texs[], const SkColor colors[],
1066 SkXfermode* xmode,
1067 const uint16_t indices[], int indexCount,
1068 const SkPaint& paint) {
1069 CHECK_SHOULD_DRAW(draw);
1070
bsalomon@google.com5782d712011-01-21 21:03:59 +00001071 GrPaint grPaint;
1072 SkAutoCachedTexture act;
1073 // we ignore the shader if texs is null.
1074 if (NULL == texs) {
Scroggod757df22011-05-16 13:11:16 +00001075 if (!this->skPaint2GrPaintNoShader(paint,
1076 false,
1077 &grPaint,
1078 NULL == colors)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001079 return;
1080 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001081 } else {
reed@google.com1a2e8d22011-01-21 22:08:29 +00001082 if (!this->skPaint2GrPaintShader(paint, &act,
1083 *draw.fMatrix,
Scroggod757df22011-05-16 13:11:16 +00001084 &grPaint,
1085 NULL == colors)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001086 return;
1087 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001088 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001089
1090 if (NULL != xmode && NULL != texs && NULL != colors) {
1091 SkXfermode::Mode mode;
1092 if (!SkXfermode::IsMode(xmode, &mode) ||
1093 SkXfermode::kMultiply_Mode != mode) {
1094 SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
1095#if 0
1096 return
1097#endif
1098 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001099 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001100
1101#if SK_SCALAR_IS_GR_SCALAR
1102 // even if GrColor and SkColor byte offsets match we need
1103 // to perform pre-multiply.
1104 if (NULL == colors) {
1105 fContext->drawVertices(grPaint,
1106 gVertexMode2PrimitiveType[vmode],
1107 vertexCount,
1108 (GrPoint*) vertices,
1109 (GrPoint*) texs,
1110 NULL,
1111 indices,
1112 indexCount);
1113 } else
1114#endif
1115 {
1116 SkTexCoordSource texSrc(texs);
1117 SkColorSource colSrc(colors);
1118 SkIndexSource idxSrc(indices, indexCount);
1119
1120 fContext->drawCustomVertices(grPaint,
1121 gVertexMode2PrimitiveType[vmode],
1122 SkPositionSource(vertices, vertexCount),
1123 (NULL == texs) ? NULL : &texSrc,
1124 (NULL == colors) ? NULL : &colSrc,
1125 (NULL == indices) ? NULL : &idxSrc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001126 }
1127}
1128
1129///////////////////////////////////////////////////////////////////////////////
1130
1131static void GlyphCacheAuxProc(void* data) {
1132 delete (GrFontScaler*)data;
1133}
1134
1135static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) {
1136 void* auxData;
1137 GrFontScaler* scaler = NULL;
1138 if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
1139 scaler = (GrFontScaler*)auxData;
1140 }
1141 if (NULL == scaler) {
1142 scaler = new SkGrFontScaler(cache);
1143 cache->setAuxProc(GlyphCacheAuxProc, scaler);
1144 }
1145 return scaler;
1146}
1147
1148static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
1149 SkFixed fx, SkFixed fy,
1150 const SkGlyph& glyph) {
1151 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1152
1153 GrSkDrawProcs* procs = (GrSkDrawProcs*)state.fDraw->fProcs;
1154
1155 if (NULL == procs->fFontScaler) {
1156 procs->fFontScaler = get_gr_font_scaler(state.fCache);
1157 }
reed@google.com39ce0ac2011-04-08 15:42:19 +00001158
1159 /*
1160 * Skia calls us with fx,fy already biased by 1/2. It does this to speed
1161 * up rounding these, so that all of its procs (like us) can just call
1162 * SkFixedFloor and get the "rounded" value.
1163 *
1164 * We take advantage of that for fx, where we pass a rounded value, but
1165 * we want the fractional fy, so we have to unbias it first.
1166 */
reed@google.comac10a2d2010-12-22 21:39:39 +00001167 procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0),
reed@google.com39ce0ac2011-04-08 15:42:19 +00001168 SkIntToFixed(SkFixedFloor(fx)),
1169 fy - SK_FixedHalf,
reed@google.comac10a2d2010-12-22 21:39:39 +00001170 procs->fFontScaler);
1171}
1172
bsalomon@google.com5782d712011-01-21 21:03:59 +00001173SkDrawProcs* SkGpuDevice::initDrawForText(GrTextContext* context) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001174
1175 // deferred allocation
1176 if (NULL == fDrawProcs) {
1177 fDrawProcs = new GrSkDrawProcs;
1178 fDrawProcs->fD1GProc = SkGPU_Draw1Glyph;
1179 fDrawProcs->fContext = fContext;
1180 }
1181
1182 // init our (and GL's) state
1183 fDrawProcs->fTextContext = context;
1184 fDrawProcs->fFontScaler = NULL;
1185 return fDrawProcs;
1186}
1187
1188void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
1189 size_t byteLength, SkScalar x, SkScalar y,
1190 const SkPaint& paint) {
1191 CHECK_SHOULD_DRAW(draw);
1192
1193 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1194 // this guy will just call our drawPath()
1195 draw.drawText((const char*)text, byteLength, x, y, paint);
1196 } else {
reed@google.comac10a2d2010-12-22 21:39:39 +00001197 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001198
1199 GrPaint grPaint;
1200 SkAutoCachedTexture act;
1201
Scroggod757df22011-05-16 13:11:16 +00001202 if (!this->skPaint2GrPaintShader(paint,
1203 &act,
1204 *draw.fMatrix,
1205 &grPaint,
1206 true)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001207 return;
1208 }
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001209 GrTextContext context(fContext, grPaint, draw.fExtMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001210 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001211 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
1212 }
1213}
1214
1215void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
1216 size_t byteLength, const SkScalar pos[],
1217 SkScalar constY, int scalarsPerPos,
1218 const SkPaint& paint) {
1219 CHECK_SHOULD_DRAW(draw);
1220
1221 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1222 // this guy will just call our drawPath()
1223 draw.drawPosText((const char*)text, byteLength, pos, constY,
1224 scalarsPerPos, paint);
1225 } else {
reed@google.comac10a2d2010-12-22 21:39:39 +00001226 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001227
1228 GrPaint grPaint;
1229 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +00001230 if (!this->skPaint2GrPaintShader(paint,
1231 &act,
1232 *draw.fMatrix,
1233 &grPaint,
1234 true)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001235 return;
1236 }
1237
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001238 GrTextContext context(fContext, grPaint, draw.fExtMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001239 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001240 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
1241 scalarsPerPos, paint);
1242 }
1243}
1244
1245void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
1246 size_t len, const SkPath& path,
1247 const SkMatrix* m, const SkPaint& paint) {
1248 CHECK_SHOULD_DRAW(draw);
1249
1250 SkASSERT(draw.fDevice == this);
1251 draw.drawTextOnPath((const char*)text, len, path, m, paint);
1252}
1253
1254///////////////////////////////////////////////////////////////////////////////
1255
reed@google.comf67e4cf2011-03-15 20:56:58 +00001256bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
1257 if (!paint.isLCDRenderText()) {
1258 // we're cool with the paint as is
1259 return false;
1260 }
1261
1262 if (paint.getShader() ||
1263 paint.getXfermode() || // unless its srcover
1264 paint.getMaskFilter() ||
1265 paint.getRasterizer() ||
1266 paint.getColorFilter() ||
1267 paint.getPathEffect() ||
1268 paint.isFakeBoldText() ||
1269 paint.getStyle() != SkPaint::kFill_Style) {
1270 // turn off lcd
1271 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
1272 flags->fHinting = paint.getHinting();
1273 return true;
1274 }
1275 // we're cool with the paint as is
1276 return false;
1277}
1278
1279///////////////////////////////////////////////////////////////////////////////
1280
reed@google.comac10a2d2010-12-22 21:39:39 +00001281SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001282 const GrSamplerState& sampler,
1283 GrTexture** texture,
1284 bool forDeviceRenderTarget) {
1285 GrTexture* newTexture = NULL;
1286 GrTextureEntry* entry = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +00001287 GrContext* ctx = this->context();
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001288
reed@google.comac10a2d2010-12-22 21:39:39 +00001289 if (forDeviceRenderTarget) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001290 const GrTextureDesc desc = {
1291 kRenderTarget_GrTextureFlagBit,
1292 kNone_GrAALevel,
1293 bitmap.width(),
1294 bitmap.height(),
1295 SkGr::Bitmap2PixelConfig(bitmap)
1296 };
bsalomon@google.coma39f4042011-04-26 13:18:16 +00001297 entry = ctx->lockKeylessTexture(desc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001298 } else {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001299 uint32_t p0, p1;
reed@google.comac10a2d2010-12-22 21:39:39 +00001300 p0 = bitmap.getGenerationID();
1301 p1 = bitmap.pixelRefOffset();
reed@google.comac10a2d2010-12-22 21:39:39 +00001302
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001303 GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
1304 entry = ctx->findAndLockTexture(&key, sampler);
reed@google.comac10a2d2010-12-22 21:39:39 +00001305
reed@google.comac10a2d2010-12-22 21:39:39 +00001306 if (NULL == entry) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001307 entry = sk_gr_create_bitmap_texture(ctx, &key, sampler, bitmap);
1308 if (NULL == entry) {
1309 GrPrintf("---- failed to create texture for cache [%d %d]\n",
1310 bitmap.width(), bitmap.height());
1311 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001312 }
1313 }
1314
1315 if (NULL != entry) {
1316 newTexture = entry->texture();
reed@google.comac10a2d2010-12-22 21:39:39 +00001317 if (texture) {
1318 *texture = newTexture;
1319 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001320 }
1321 return (TexCache*)entry;
1322}
1323
1324void SkGpuDevice::unlockCachedTexture(TexCache* cache) {
1325 this->context()->unlockTexture((GrTextureEntry*)cache);
1326}
1327
reed@google.com7b201d22011-01-11 18:59:23 +00001328///////////////////////////////////////////////////////////////////////////////
1329
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001330SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context,
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001331 GrRenderTarget* rootRenderTarget) {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001332 GrAssert(NULL != context);
1333 GrAssert(NULL != rootRenderTarget);
1334
1335 // check this now rather than passing this value to SkGpuDevice cons.
1336 // we want the rt that is bound *now* in the 3D API, not the one
1337 // at the time of newDevice.
1338 if (SkGpuDevice::Current3DApiRenderTarget() == rootRenderTarget) {
1339 fRootRenderTarget = context->createRenderTargetFrom3DApiState();
1340 } else {
1341 fRootRenderTarget = rootRenderTarget;
1342 rootRenderTarget->ref();
1343 }
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001344
1345 fContext = context;
reed@google.com7b201d22011-01-11 18:59:23 +00001346 context->ref();
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001347
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001348 fRootTexture = NULL;
1349}
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001350
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001351SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context, GrTexture* rootRenderTargetTexture) {
1352 GrAssert(NULL != context);
1353 GrAssert(NULL != rootRenderTargetTexture);
1354 GrAssert(NULL != rootRenderTargetTexture->asRenderTarget());
1355
1356 fRootTexture = rootRenderTargetTexture;
1357 rootRenderTargetTexture->ref();
1358
1359 fRootRenderTarget = rootRenderTargetTexture->asRenderTarget();
1360 fRootRenderTarget->ref();
1361
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001362 fContext = context;
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001363 context->ref();
reed@google.com7b201d22011-01-11 18:59:23 +00001364}
1365
1366SkGpuDeviceFactory::~SkGpuDeviceFactory() {
1367 fContext->unref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001368 fRootRenderTarget->unref();
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001369 GrSafeUnref(fRootTexture);
reed@google.com7b201d22011-01-11 18:59:23 +00001370}
1371
1372SkDevice* SkGpuDeviceFactory::newDevice(SkCanvas*, SkBitmap::Config config,
1373 int width, int height,
1374 bool isOpaque, bool isLayer) {
1375 SkBitmap bm;
1376 bm.setConfig(config, width, height);
1377 bm.setIsOpaque(isOpaque);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001378 return new SkGpuDevice(fContext, bm, isLayer ? NULL : fRootRenderTarget);
reed@google.com7b201d22011-01-11 18:59:23 +00001379}