blob: a0153478d39bcd154c6766be9260a22f680acdfd [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.com07f3ee12011-05-16 17:21:57 +0000863 fContext->drawPath(grPaint, *pathPtr, fill);
reed@google.comac10a2d2010-12-22 21:39:39 +0000864}
865
reed@google.comac10a2d2010-12-22 21:39:39 +0000866void SkGpuDevice::drawBitmap(const SkDraw& draw,
867 const SkBitmap& bitmap,
868 const SkIRect* srcRectPtr,
869 const SkMatrix& m,
870 const SkPaint& paint) {
871 CHECK_SHOULD_DRAW(draw);
872
873 SkIRect srcRect;
874 if (NULL == srcRectPtr) {
875 srcRect.set(0, 0, bitmap.width(), bitmap.height());
876 } else {
877 srcRect = *srcRectPtr;
878 }
879
bsalomon@google.com5782d712011-01-21 21:03:59 +0000880 GrPaint grPaint;
Scroggod757df22011-05-16 13:11:16 +0000881 if (!this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000882 return;
883 }
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000884 if (paint.isFilterBitmap()) {
885 grPaint.fSampler.setFilter(GrSamplerState::kBilinear_Filter);
886 } else {
887 grPaint.fSampler.setFilter(GrSamplerState::kNearest_Filter);
888 }
889
bsalomon@google.com5782d712011-01-21 21:03:59 +0000890
reed@google.com02a7e6c2011-01-28 21:21:49 +0000891 const int maxTextureDim = fContext->getMaxTextureDimension();
892 if (bitmap.getTexture() || (bitmap.width() <= maxTextureDim &&
893 bitmap.height() <= maxTextureDim)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000894 // take the fast case
bsalomon@google.com5782d712011-01-21 21:03:59 +0000895 this->internalDrawBitmap(draw, bitmap, srcRect, m, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000896 return;
897 }
898
899 // undo the translate done by SkCanvas
900 int DX = SkMax32(0, srcRect.fLeft);
901 int DY = SkMax32(0, srcRect.fTop);
902 // compute clip bounds in local coordinates
903 SkIRect clipRect;
904 {
905 SkRect r;
906 r.set(draw.fClip->getBounds());
907 SkMatrix matrix, inverse;
908 matrix.setConcat(*draw.fMatrix, m);
909 if (!matrix.invert(&inverse)) {
910 return;
911 }
912 inverse.mapRect(&r);
913 r.roundOut(&clipRect);
914 // apply the canvas' translate to our local clip
915 clipRect.offset(DX, DY);
916 }
917
reed@google.com02a7e6c2011-01-28 21:21:49 +0000918 int nx = bitmap.width() / maxTextureDim;
919 int ny = bitmap.height() / maxTextureDim;
reed@google.comac10a2d2010-12-22 21:39:39 +0000920 for (int x = 0; x <= nx; x++) {
921 for (int y = 0; y <= ny; y++) {
922 SkIRect tileR;
reed@google.com02a7e6c2011-01-28 21:21:49 +0000923 tileR.set(x * maxTextureDim, y * maxTextureDim,
924 (x + 1) * maxTextureDim, (y + 1) * maxTextureDim);
reed@google.comac10a2d2010-12-22 21:39:39 +0000925 if (!SkIRect::Intersects(tileR, clipRect)) {
926 continue;
927 }
928
929 SkIRect srcR = tileR;
930 if (!srcR.intersect(srcRect)) {
931 continue;
932 }
933
934 SkBitmap tmpB;
935 if (bitmap.extractSubset(&tmpB, tileR)) {
936 // now offset it to make it "local" to our tmp bitmap
937 srcR.offset(-tileR.fLeft, -tileR.fTop);
938
939 SkMatrix tmpM(m);
940 {
941 int dx = tileR.fLeft - DX + SkMax32(0, srcR.fLeft);
942 int dy = tileR.fTop - DY + SkMax32(0, srcR.fTop);
943 tmpM.preTranslate(SkIntToScalar(dx), SkIntToScalar(dy));
944 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000945 this->internalDrawBitmap(draw, tmpB, srcR, tmpM, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000946 }
947 }
948 }
949}
950
951/*
952 * This is called by drawBitmap(), which has to handle images that may be too
953 * large to be represented by a single texture.
954 *
bsalomon@google.com5782d712011-01-21 21:03:59 +0000955 * internalDrawBitmap assumes that the specified bitmap will fit in a texture
956 * and that non-texture portion of the GrPaint has already been setup.
reed@google.comac10a2d2010-12-22 21:39:39 +0000957 */
958void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
959 const SkBitmap& bitmap,
960 const SkIRect& srcRect,
961 const SkMatrix& m,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000962 GrPaint* grPaint) {
reed@google.com02a7e6c2011-01-28 21:21:49 +0000963 SkASSERT(bitmap.width() <= fContext->getMaxTextureDimension() &&
964 bitmap.height() <= fContext->getMaxTextureDimension());
reed@google.comac10a2d2010-12-22 21:39:39 +0000965
966 SkAutoLockPixels alp(bitmap);
967 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
968 return;
969 }
970
bsalomon@google.com5782d712011-01-21 21:03:59 +0000971 grPaint->fSampler.setWrapX(GrSamplerState::kClamp_WrapMode);
972 grPaint->fSampler.setWrapY(GrSamplerState::kClamp_WrapMode);
973 grPaint->fSampler.setSampleMode(GrSamplerState::kNormal_SampleMode);
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000974 grPaint->fSampler.setMatrix(GrMatrix::I());
reed@google.comac10a2d2010-12-22 21:39:39 +0000975
976 GrTexture* texture;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000977 SkAutoCachedTexture act(this, bitmap, grPaint->fSampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000978 if (NULL == texture) {
979 return;
980 }
981
bsalomon@google.com5782d712011-01-21 21:03:59 +0000982 grPaint->setTexture(texture);
reed@google.com46799cd2011-02-22 20:56:26 +0000983
reed@google.com20efde72011-05-09 17:00:02 +0000984 GrRect dstRect = SkRect::MakeWH(GrIntToScalar(srcRect.width()),
985 GrIntToScalar(srcRect.height()));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000986 GrRect paintRect;
987 paintRect.setLTRB(GrFixedToScalar((srcRect.fLeft << 16) / bitmap.width()),
988 GrFixedToScalar((srcRect.fTop << 16) / bitmap.height()),
989 GrFixedToScalar((srcRect.fRight << 16) / bitmap.width()),
990 GrFixedToScalar((srcRect.fBottom << 16) / bitmap.height()));
reed@google.comac10a2d2010-12-22 21:39:39 +0000991
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000992 fContext->drawRectToRect(*grPaint, dstRect, paintRect, &m);
reed@google.comac10a2d2010-12-22 21:39:39 +0000993}
994
995void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
996 int left, int top, const SkPaint& paint) {
997 CHECK_SHOULD_DRAW(draw);
998
999 SkAutoLockPixels alp(bitmap);
1000 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
1001 return;
1002 }
1003
bsalomon@google.com5782d712011-01-21 21:03:59 +00001004 GrPaint grPaint;
Scroggod757df22011-05-16 13:11:16 +00001005 if(!this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001006 return;
1007 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001008
bsalomon@google.com5782d712011-01-21 21:03:59 +00001009 GrAutoMatrix avm(fContext, GrMatrix::I());
1010
1011 GrTexture* texture;
1012 grPaint.fSampler.setClampNoFilter();
1013 SkAutoCachedTexture act(this, bitmap, grPaint.fSampler, &texture);
1014
bsalomon@google.com5782d712011-01-21 21:03:59 +00001015 grPaint.setTexture(texture);
1016
bsalomon@google.com5782d712011-01-21 21:03:59 +00001017 fContext->drawRectToRect(grPaint,
reed@google.com20efde72011-05-09 17:00:02 +00001018 GrRect::MakeXYWH(GrIntToScalar(left),
1019 GrIntToScalar(top),
1020 GrIntToScalar(bitmap.width()),
1021 GrIntToScalar(bitmap.height())),
1022 GrRect::MakeWH(GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001023}
1024
1025void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
1026 int x, int y, const SkPaint& paint) {
1027 CHECK_SHOULD_DRAW(draw);
1028
bsalomon@google.com5782d712011-01-21 21:03:59 +00001029 GrPaint grPaint;
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001030 if (!((SkGpuDevice*)dev)->bindDeviceAsTexture(&grPaint) ||
Scroggod757df22011-05-16 13:11:16 +00001031 !this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001032 return;
reed@google.comac10a2d2010-12-22 21:39:39 +00001033 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001034
1035 SkASSERT(NULL != grPaint.getTexture());
1036
1037 const SkBitmap& bm = dev->accessBitmap(false);
1038 int w = bm.width();
1039 int h = bm.height();
1040
1041 GrAutoMatrix avm(fContext, GrMatrix::I());
1042
1043 grPaint.fSampler.setClampNoFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +00001044
1045 fContext->drawRectToRect(grPaint,
reed@google.com20efde72011-05-09 17:00:02 +00001046 GrRect::MakeXYWH(GrIntToScalar(x),
1047 GrIntToScalar(y),
1048 GrIntToScalar(w),
1049 GrIntToScalar(h)),
1050 GrRect::MakeWH(GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001051}
1052
1053///////////////////////////////////////////////////////////////////////////////
1054
1055// must be in SkCanvas::VertexMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +00001056static const GrPrimitiveType gVertexMode2PrimitiveType[] = {
1057 kTriangles_PrimitiveType,
1058 kTriangleStrip_PrimitiveType,
1059 kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +00001060};
1061
1062void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
1063 int vertexCount, const SkPoint vertices[],
1064 const SkPoint texs[], const SkColor colors[],
1065 SkXfermode* xmode,
1066 const uint16_t indices[], int indexCount,
1067 const SkPaint& paint) {
1068 CHECK_SHOULD_DRAW(draw);
1069
bsalomon@google.com5782d712011-01-21 21:03:59 +00001070 GrPaint grPaint;
1071 SkAutoCachedTexture act;
1072 // we ignore the shader if texs is null.
1073 if (NULL == texs) {
Scroggod757df22011-05-16 13:11:16 +00001074 if (!this->skPaint2GrPaintNoShader(paint,
1075 false,
1076 &grPaint,
1077 NULL == colors)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001078 return;
1079 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001080 } else {
reed@google.com1a2e8d22011-01-21 22:08:29 +00001081 if (!this->skPaint2GrPaintShader(paint, &act,
1082 *draw.fMatrix,
Scroggod757df22011-05-16 13:11:16 +00001083 &grPaint,
1084 NULL == colors)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001085 return;
1086 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001087 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001088
1089 if (NULL != xmode && NULL != texs && NULL != colors) {
1090 SkXfermode::Mode mode;
1091 if (!SkXfermode::IsMode(xmode, &mode) ||
1092 SkXfermode::kMultiply_Mode != mode) {
1093 SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
1094#if 0
1095 return
1096#endif
1097 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001098 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001099
1100#if SK_SCALAR_IS_GR_SCALAR
1101 // even if GrColor and SkColor byte offsets match we need
1102 // to perform pre-multiply.
1103 if (NULL == colors) {
1104 fContext->drawVertices(grPaint,
1105 gVertexMode2PrimitiveType[vmode],
1106 vertexCount,
1107 (GrPoint*) vertices,
1108 (GrPoint*) texs,
1109 NULL,
1110 indices,
1111 indexCount);
1112 } else
1113#endif
1114 {
1115 SkTexCoordSource texSrc(texs);
1116 SkColorSource colSrc(colors);
1117 SkIndexSource idxSrc(indices, indexCount);
1118
1119 fContext->drawCustomVertices(grPaint,
1120 gVertexMode2PrimitiveType[vmode],
1121 SkPositionSource(vertices, vertexCount),
1122 (NULL == texs) ? NULL : &texSrc,
1123 (NULL == colors) ? NULL : &colSrc,
1124 (NULL == indices) ? NULL : &idxSrc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001125 }
1126}
1127
1128///////////////////////////////////////////////////////////////////////////////
1129
1130static void GlyphCacheAuxProc(void* data) {
1131 delete (GrFontScaler*)data;
1132}
1133
1134static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) {
1135 void* auxData;
1136 GrFontScaler* scaler = NULL;
1137 if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
1138 scaler = (GrFontScaler*)auxData;
1139 }
1140 if (NULL == scaler) {
1141 scaler = new SkGrFontScaler(cache);
1142 cache->setAuxProc(GlyphCacheAuxProc, scaler);
1143 }
1144 return scaler;
1145}
1146
1147static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
1148 SkFixed fx, SkFixed fy,
1149 const SkGlyph& glyph) {
1150 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1151
1152 GrSkDrawProcs* procs = (GrSkDrawProcs*)state.fDraw->fProcs;
1153
1154 if (NULL == procs->fFontScaler) {
1155 procs->fFontScaler = get_gr_font_scaler(state.fCache);
1156 }
reed@google.com39ce0ac2011-04-08 15:42:19 +00001157
1158 /*
1159 * Skia calls us with fx,fy already biased by 1/2. It does this to speed
1160 * up rounding these, so that all of its procs (like us) can just call
1161 * SkFixedFloor and get the "rounded" value.
1162 *
1163 * We take advantage of that for fx, where we pass a rounded value, but
1164 * we want the fractional fy, so we have to unbias it first.
1165 */
reed@google.comac10a2d2010-12-22 21:39:39 +00001166 procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0),
reed@google.com39ce0ac2011-04-08 15:42:19 +00001167 SkIntToFixed(SkFixedFloor(fx)),
1168 fy - SK_FixedHalf,
reed@google.comac10a2d2010-12-22 21:39:39 +00001169 procs->fFontScaler);
1170}
1171
bsalomon@google.com5782d712011-01-21 21:03:59 +00001172SkDrawProcs* SkGpuDevice::initDrawForText(GrTextContext* context) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001173
1174 // deferred allocation
1175 if (NULL == fDrawProcs) {
1176 fDrawProcs = new GrSkDrawProcs;
1177 fDrawProcs->fD1GProc = SkGPU_Draw1Glyph;
1178 fDrawProcs->fContext = fContext;
1179 }
1180
1181 // init our (and GL's) state
1182 fDrawProcs->fTextContext = context;
1183 fDrawProcs->fFontScaler = NULL;
1184 return fDrawProcs;
1185}
1186
1187void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
1188 size_t byteLength, SkScalar x, SkScalar y,
1189 const SkPaint& paint) {
1190 CHECK_SHOULD_DRAW(draw);
1191
1192 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1193 // this guy will just call our drawPath()
1194 draw.drawText((const char*)text, byteLength, x, y, paint);
1195 } else {
reed@google.comac10a2d2010-12-22 21:39:39 +00001196 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001197
1198 GrPaint grPaint;
1199 SkAutoCachedTexture act;
1200
Scroggod757df22011-05-16 13:11:16 +00001201 if (!this->skPaint2GrPaintShader(paint,
1202 &act,
1203 *draw.fMatrix,
1204 &grPaint,
1205 true)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001206 return;
1207 }
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001208 GrTextContext context(fContext, grPaint, draw.fExtMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001209 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001210 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
1211 }
1212}
1213
1214void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
1215 size_t byteLength, const SkScalar pos[],
1216 SkScalar constY, int scalarsPerPos,
1217 const SkPaint& paint) {
1218 CHECK_SHOULD_DRAW(draw);
1219
1220 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1221 // this guy will just call our drawPath()
1222 draw.drawPosText((const char*)text, byteLength, pos, constY,
1223 scalarsPerPos, paint);
1224 } else {
reed@google.comac10a2d2010-12-22 21:39:39 +00001225 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001226
1227 GrPaint grPaint;
1228 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +00001229 if (!this->skPaint2GrPaintShader(paint,
1230 &act,
1231 *draw.fMatrix,
1232 &grPaint,
1233 true)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001234 return;
1235 }
1236
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001237 GrTextContext context(fContext, grPaint, draw.fExtMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001238 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001239 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
1240 scalarsPerPos, paint);
1241 }
1242}
1243
1244void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
1245 size_t len, const SkPath& path,
1246 const SkMatrix* m, const SkPaint& paint) {
1247 CHECK_SHOULD_DRAW(draw);
1248
1249 SkASSERT(draw.fDevice == this);
1250 draw.drawTextOnPath((const char*)text, len, path, m, paint);
1251}
1252
1253///////////////////////////////////////////////////////////////////////////////
1254
reed@google.comf67e4cf2011-03-15 20:56:58 +00001255bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
1256 if (!paint.isLCDRenderText()) {
1257 // we're cool with the paint as is
1258 return false;
1259 }
1260
1261 if (paint.getShader() ||
1262 paint.getXfermode() || // unless its srcover
1263 paint.getMaskFilter() ||
1264 paint.getRasterizer() ||
1265 paint.getColorFilter() ||
1266 paint.getPathEffect() ||
1267 paint.isFakeBoldText() ||
1268 paint.getStyle() != SkPaint::kFill_Style) {
1269 // turn off lcd
1270 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
1271 flags->fHinting = paint.getHinting();
1272 return true;
1273 }
1274 // we're cool with the paint as is
1275 return false;
1276}
1277
1278///////////////////////////////////////////////////////////////////////////////
1279
reed@google.comac10a2d2010-12-22 21:39:39 +00001280SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001281 const GrSamplerState& sampler,
1282 GrTexture** texture,
1283 bool forDeviceRenderTarget) {
1284 GrTexture* newTexture = NULL;
1285 GrTextureEntry* entry = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +00001286 GrContext* ctx = this->context();
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001287
reed@google.comac10a2d2010-12-22 21:39:39 +00001288 if (forDeviceRenderTarget) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001289 const GrTextureDesc desc = {
1290 kRenderTarget_GrTextureFlagBit,
1291 kNone_GrAALevel,
1292 bitmap.width(),
1293 bitmap.height(),
1294 SkGr::Bitmap2PixelConfig(bitmap)
1295 };
bsalomon@google.coma39f4042011-04-26 13:18:16 +00001296 entry = ctx->lockKeylessTexture(desc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001297 } else {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001298 uint32_t p0, p1;
reed@google.comac10a2d2010-12-22 21:39:39 +00001299 p0 = bitmap.getGenerationID();
1300 p1 = bitmap.pixelRefOffset();
reed@google.comac10a2d2010-12-22 21:39:39 +00001301
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001302 GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
1303 entry = ctx->findAndLockTexture(&key, sampler);
reed@google.comac10a2d2010-12-22 21:39:39 +00001304
reed@google.comac10a2d2010-12-22 21:39:39 +00001305 if (NULL == entry) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001306 entry = sk_gr_create_bitmap_texture(ctx, &key, sampler, bitmap);
1307 if (NULL == entry) {
1308 GrPrintf("---- failed to create texture for cache [%d %d]\n",
1309 bitmap.width(), bitmap.height());
1310 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001311 }
1312 }
1313
1314 if (NULL != entry) {
1315 newTexture = entry->texture();
reed@google.comac10a2d2010-12-22 21:39:39 +00001316 if (texture) {
1317 *texture = newTexture;
1318 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001319 }
1320 return (TexCache*)entry;
1321}
1322
1323void SkGpuDevice::unlockCachedTexture(TexCache* cache) {
1324 this->context()->unlockTexture((GrTextureEntry*)cache);
1325}
1326
reed@google.com7b201d22011-01-11 18:59:23 +00001327///////////////////////////////////////////////////////////////////////////////
1328
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001329SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context,
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001330 GrRenderTarget* rootRenderTarget) {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001331 GrAssert(NULL != context);
1332 GrAssert(NULL != rootRenderTarget);
1333
1334 // check this now rather than passing this value to SkGpuDevice cons.
1335 // we want the rt that is bound *now* in the 3D API, not the one
1336 // at the time of newDevice.
1337 if (SkGpuDevice::Current3DApiRenderTarget() == rootRenderTarget) {
1338 fRootRenderTarget = context->createRenderTargetFrom3DApiState();
1339 } else {
1340 fRootRenderTarget = rootRenderTarget;
1341 rootRenderTarget->ref();
1342 }
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001343
1344 fContext = context;
reed@google.com7b201d22011-01-11 18:59:23 +00001345 context->ref();
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001346
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001347 fRootTexture = NULL;
1348}
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001349
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001350SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context, GrTexture* rootRenderTargetTexture) {
1351 GrAssert(NULL != context);
1352 GrAssert(NULL != rootRenderTargetTexture);
1353 GrAssert(NULL != rootRenderTargetTexture->asRenderTarget());
1354
1355 fRootTexture = rootRenderTargetTexture;
1356 rootRenderTargetTexture->ref();
1357
1358 fRootRenderTarget = rootRenderTargetTexture->asRenderTarget();
1359 fRootRenderTarget->ref();
1360
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001361 fContext = context;
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001362 context->ref();
reed@google.com7b201d22011-01-11 18:59:23 +00001363}
1364
1365SkGpuDeviceFactory::~SkGpuDeviceFactory() {
1366 fContext->unref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001367 fRootRenderTarget->unref();
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001368 GrSafeUnref(fRootTexture);
reed@google.com7b201d22011-01-11 18:59:23 +00001369}
1370
1371SkDevice* SkGpuDeviceFactory::newDevice(SkCanvas*, SkBitmap::Config config,
1372 int width, int height,
1373 bool isOpaque, bool isLayer) {
1374 SkBitmap bm;
1375 bm.setConfig(config, width, height);
1376 bm.setIsOpaque(isOpaque);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001377 return new SkGpuDevice(fContext, bm, isLayer ? NULL : fRootRenderTarget);
reed@google.com7b201d22011-01-11 18:59:23 +00001378}