blob: 563dde74e2d2bbaacc2e380a80d4ed8706a933c8 [file] [log] [blame]
reed@google.comac10a2d2010-12-22 21:39:39 +00001/*
bsalomon@google.com1da07462011-03-10 14:51:57 +00002 Copyright 2011 Google Inc.
reed@google.comac10a2d2010-12-22 21:39:39 +00003
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17
18#include "GrContext.h"
19#include "GrTextContext.h"
20
reed@google.comac10a2d2010-12-22 21:39:39 +000021#include "SkGpuDevice.h"
reed@google.com7b201d22011-01-11 18:59:23 +000022#include "SkGpuDeviceFactory.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000023#include "SkGrTexturePixelRef.h"
24
Scroggo97c88c22011-05-11 14:05:25 +000025#include "SkColorFilter.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000026#include "SkDrawProcs.h"
27#include "SkGlyphCache.h"
reed@google.comc9aa5872011-04-05 21:05:37 +000028#include "SkUtils.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000029
30#define CACHE_LAYER_TEXTURES 1
31
32#if 0
33 extern bool (*gShouldDrawProc)();
34 #define CHECK_SHOULD_DRAW(draw) \
35 do { \
36 if (gShouldDrawProc && !gShouldDrawProc()) return; \
37 this->prepareRenderTarget(draw); \
38 } while (0)
39#else
40 #define CHECK_SHOULD_DRAW(draw) this->prepareRenderTarget(draw)
41#endif
42
reed@google.comac10a2d2010-12-22 21:39:39 +000043///////////////////////////////////////////////////////////////////////////////
44
45SkGpuDevice::SkAutoCachedTexture::
46 SkAutoCachedTexture(SkGpuDevice* device,
47 const SkBitmap& bitmap,
48 const GrSamplerState& sampler,
49 GrTexture** texture) {
50 GrAssert(texture);
51 fTex = NULL;
52 *texture = this->set(device, bitmap, sampler);
53}
54
55SkGpuDevice::SkAutoCachedTexture::SkAutoCachedTexture() {
56 fTex = NULL;
57}
58
59GrTexture* SkGpuDevice::SkAutoCachedTexture::set(SkGpuDevice* device,
60 const SkBitmap& bitmap,
61 const GrSamplerState& sampler) {
62 if (fTex) {
63 fDevice->unlockCachedTexture(fTex);
64 }
65 fDevice = device;
66 GrTexture* texture = (GrTexture*)bitmap.getTexture();
67 if (texture) {
68 // return the native texture
69 fTex = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +000070 } else {
71 // look it up in our cache
72 fTex = device->lockCachedTexture(bitmap, sampler, &texture, false);
73 }
74 return texture;
75}
76
77SkGpuDevice::SkAutoCachedTexture::~SkAutoCachedTexture() {
78 if (fTex) {
79 fDevice->unlockCachedTexture(fTex);
80 }
81}
82
83///////////////////////////////////////////////////////////////////////////////
84
85bool gDoTraceDraw;
86
87struct GrSkDrawProcs : public SkDrawProcs {
88public:
89 GrContext* fContext;
90 GrTextContext* fTextContext;
91 GrFontScaler* fFontScaler; // cached in the skia glyphcache
92};
93
94///////////////////////////////////////////////////////////////////////////////
95
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +000096GrRenderTarget* SkGpuDevice::Current3DApiRenderTarget() {
97 return (GrRenderTarget*) -1;
98}
99
100SkGpuDevice::SkGpuDevice(GrContext* context,
101 const SkBitmap& bitmap,
102 GrRenderTarget* renderTargetOrNull)
103 : SkDevice(NULL, bitmap, (NULL == renderTargetOrNull)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000104
105 fNeedPrepareRenderTarget = false;
106 fDrawProcs = NULL;
107
reed@google.com7b201d22011-01-11 18:59:23 +0000108 fContext = context;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000109 fContext->ref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000110
111 fCache = NULL;
112 fTexture = NULL;
113 fRenderTarget = NULL;
114 fNeedClear = false;
115
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000116 if (NULL == renderTargetOrNull) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000117 SkBitmap::Config c = bitmap.config();
118 if (c != SkBitmap::kRGB_565_Config) {
119 c = SkBitmap::kARGB_8888_Config;
120 }
121 SkBitmap bm;
122 bm.setConfig(c, this->width(), this->height());
123
124#if CACHE_LAYER_TEXTURES
125
126 fCache = this->lockCachedTexture(bm, GrSamplerState::ClampNoFilter(),
127 &fTexture, true);
128 if (fCache) {
129 SkASSERT(NULL != fTexture);
bsalomon@google.com1da07462011-03-10 14:51:57 +0000130 SkASSERT(NULL != fTexture->asRenderTarget());
reed@google.comac10a2d2010-12-22 21:39:39 +0000131 }
132#else
133 const GrGpu::TextureDesc desc = {
134 GrGpu::kRenderTarget_TextureFlag,
135 GrGpu::kNone_AALevel,
136 this->width(),
137 this->height(),
138 SkGr::Bitmap2PixelConfig(bm)
139 };
140
141 fTexture = fContext->createUncachedTexture(desc, NULL, 0);
142#endif
143 if (NULL != fTexture) {
144 fRenderTarget = fTexture->asRenderTarget();
145
146 GrAssert(NULL != fRenderTarget);
147
148 // we defer the actual clear until our gainFocus()
149 fNeedClear = true;
150
151 // wrap the bitmap with a pixelref to expose our texture
152 SkGrTexturePixelRef* pr = new SkGrTexturePixelRef(fTexture);
153 this->setPixelRef(pr, 0)->unref();
154 } else {
155 GrPrintf("--- failed to create gpu-offscreen [%d %d]\n",
156 this->width(), this->height());
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000157 GrAssert(false);
reed@google.comac10a2d2010-12-22 21:39:39 +0000158 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000159 } else {
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000160 if (Current3DApiRenderTarget() == renderTargetOrNull) {
161 fRenderTarget = fContext->createRenderTargetFrom3DApiState();
162 } else {
163 fRenderTarget = renderTargetOrNull;
164 fRenderTarget->ref();
165 }
166 SkGrRenderTargetPixelRef* pr = new SkGrRenderTargetPixelRef(fRenderTarget);
167 this->setPixelRef(pr, 0)->unref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000168 }
169}
170
171SkGpuDevice::~SkGpuDevice() {
172 if (fDrawProcs) {
173 delete fDrawProcs;
174 }
175
176 if (fCache) {
177 GrAssert(NULL != fTexture);
178 GrAssert(fRenderTarget == fTexture->asRenderTarget());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000179 fContext->unlockTexture((GrTextureEntry*)fCache);
reed@google.comac10a2d2010-12-22 21:39:39 +0000180 } else if (NULL != fTexture) {
181 GrAssert(!CACHE_LAYER_TEXTURES);
182 GrAssert(fRenderTarget == fTexture->asRenderTarget());
183 fTexture->unref();
184 } else if (NULL != fRenderTarget) {
185 fRenderTarget->unref();
186 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000187 fContext->unref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000188}
189
reed@google.comac10a2d2010-12-22 21:39:39 +0000190intptr_t SkGpuDevice::getLayerTextureHandle() const {
191 if (fTexture) {
192 return fTexture->getTextureHandle();
193 } else {
194 return 0;
195 }
196}
mike@reedtribe.orgea4ac972011-04-26 11:48:33 +0000197
198SkDeviceFactory* SkGpuDevice::onNewDeviceFactory() {
199 return SkNEW_ARGS(SkGpuDeviceFactory, (fContext, fRenderTarget));
200}
201
reed@google.comac10a2d2010-12-22 21:39:39 +0000202///////////////////////////////////////////////////////////////////////////////
203
204void SkGpuDevice::makeRenderTargetCurrent() {
205 fContext->setRenderTarget(fRenderTarget);
206 fContext->flush(true);
207 fNeedPrepareRenderTarget = true;
208}
209
210///////////////////////////////////////////////////////////////////////////////
211
212bool SkGpuDevice::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
213 SkIRect bounds;
214 bounds.set(0, 0, this->width(), this->height());
215 if (!bounds.intersect(srcRect)) {
216 return false;
217 }
218
219 const int w = bounds.width();
220 const int h = bounds.height();
221 SkBitmap tmp;
222 // note we explicitly specify our rowBytes to be snug (no gap between rows)
223 tmp.setConfig(SkBitmap::kARGB_8888_Config, w, h, w * 4);
224 if (!tmp.allocPixels()) {
225 return false;
226 }
227
Scroggo813c33c2011-04-07 20:56:21 +0000228 tmp.lockPixels();
reed@google.comac10a2d2010-12-22 21:39:39 +0000229
Scroggoeb176032011-04-07 21:11:49 +0000230 bool read = fContext->readRenderTargetPixels(fRenderTarget,
231 bounds.fLeft, bounds.fTop,
232 bounds.width(), bounds.height(),
233 kRGBA_8888_GrPixelConfig,
234 tmp.getPixels());
Scroggo813c33c2011-04-07 20:56:21 +0000235 tmp.unlockPixels();
236 if (!read) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000237 return false;
238 }
239
240 tmp.swap(*bitmap);
241 return true;
242}
243
244void SkGpuDevice::writePixels(const SkBitmap& bitmap, int x, int y) {
245 SkAutoLockPixels alp(bitmap);
246 if (!bitmap.readyToDraw()) {
247 return;
248 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000249 GrPixelConfig config = SkGr::BitmapConfig2PixelConfig(bitmap.config(),
250 bitmap.isOpaque());
reed@google.comac10a2d2010-12-22 21:39:39 +0000251 fContext->setRenderTarget(fRenderTarget);
252 // we aren't setting the clip or matrix, so mark as dirty
253 // we don't need to set them for this call and don't have them anyway
254 fNeedPrepareRenderTarget = true;
255
256 fContext->writePixels(x, y, bitmap.width(), bitmap.height(),
257 config, bitmap.getPixels(), bitmap.rowBytes());
258}
259
260///////////////////////////////////////////////////////////////////////////////
261
262static void convert_matrixclip(GrContext* context, const SkMatrix& matrix,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000263 const SkClipStack& clipStack,
reed@google.com6f8f2922011-03-04 22:27:10 +0000264 const SkRegion& clipRegion,
265 const SkIPoint& origin) {
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000266 context->setMatrix(matrix);
reed@google.comac10a2d2010-12-22 21:39:39 +0000267
268 SkGrClipIterator iter;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000269 iter.reset(clipStack);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000270 const SkIRect& skBounds = clipRegion.getBounds();
271 GrRect bounds;
272 bounds.setLTRB(GrIntToScalar(skBounds.fLeft),
273 GrIntToScalar(skBounds.fTop),
274 GrIntToScalar(skBounds.fRight),
275 GrIntToScalar(skBounds.fBottom));
reed@google.com6f8f2922011-03-04 22:27:10 +0000276 GrClip grc(&iter, GrIntToScalar(-origin.x()), GrIntToScalar(-origin.y()),
277 &bounds);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000278 context->setClip(grc);
reed@google.comac10a2d2010-12-22 21:39:39 +0000279}
280
281// call this ever each draw call, to ensure that the context reflects our state,
282// and not the state from some other canvas/device
283void SkGpuDevice::prepareRenderTarget(const SkDraw& draw) {
284 if (fNeedPrepareRenderTarget ||
bsalomon@google.com5782d712011-01-21 21:03:59 +0000285 fContext->getRenderTarget() != fRenderTarget) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000286
287 fContext->setRenderTarget(fRenderTarget);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000288 SkASSERT(draw.fClipStack);
289 convert_matrixclip(fContext, *draw.fMatrix,
reed@google.com6f8f2922011-03-04 22:27:10 +0000290 *draw.fClipStack, *draw.fClip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000291 fNeedPrepareRenderTarget = false;
292 }
293}
294
reed@google.com46799cd2011-02-22 20:56:26 +0000295void SkGpuDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& clip,
296 const SkClipStack& clipStack) {
297 this->INHERITED::setMatrixClip(matrix, clip, clipStack);
bsalomon@google.coma7bf6e22011-04-11 19:20:46 +0000298 // We don't need to set them now because the context may not reflect this device.
299 fNeedPrepareRenderTarget = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000300}
301
302void SkGpuDevice::gainFocus(SkCanvas* canvas, const SkMatrix& matrix,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000303 const SkRegion& clip, const SkClipStack& clipStack) {
304
reed@google.comac10a2d2010-12-22 21:39:39 +0000305 fContext->setRenderTarget(fRenderTarget);
306
bsalomon@google.comd302f142011-03-03 13:54:13 +0000307 this->INHERITED::gainFocus(canvas, matrix, clip, clipStack);
reed@google.comac10a2d2010-12-22 21:39:39 +0000308
reed@google.com6f8f2922011-03-04 22:27:10 +0000309 convert_matrixclip(fContext, matrix, clipStack, clip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000310
311 if (fNeedClear) {
bsalomon@google.com31a58402011-04-27 21:00:02 +0000312 fContext->clear(NULL, 0x0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000313 fNeedClear = false;
314 }
315}
316
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000317bool SkGpuDevice::bindDeviceAsTexture(GrPaint* paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000318 if (NULL != fTexture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000319 paint->setTexture(fTexture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000320 return true;
321 }
322 return false;
323}
324
325///////////////////////////////////////////////////////////////////////////////
326
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000327SK_COMPILE_ASSERT(SkShader::kNone_BitmapType == 0, shader_type_mismatch);
328SK_COMPILE_ASSERT(SkShader::kDefault_BitmapType == 1, shader_type_mismatch);
329SK_COMPILE_ASSERT(SkShader::kRadial_BitmapType == 2, shader_type_mismatch);
330SK_COMPILE_ASSERT(SkShader::kSweep_BitmapType == 3, shader_type_mismatch);
331SK_COMPILE_ASSERT(SkShader::kTwoPointRadial_BitmapType == 4,
332 shader_type_mismatch);
333SK_COMPILE_ASSERT(SkShader::kLast_BitmapType == 4, shader_type_mismatch);
reed@google.comac10a2d2010-12-22 21:39:39 +0000334
bsalomon@google.com5782d712011-01-21 21:03:59 +0000335static const GrSamplerState::SampleMode sk_bmp_type_to_sample_mode[] = {
336 (GrSamplerState::SampleMode) -1, // kNone_BitmapType
337 GrSamplerState::kNormal_SampleMode, // kDefault_BitmapType
338 GrSamplerState::kRadial_SampleMode, // kRadial_BitmapType
339 GrSamplerState::kSweep_SampleMode, // kSweep_BitmapType
340 GrSamplerState::kRadial2_SampleMode, // kTwoPointRadial_BitmapType
341};
342
343bool SkGpuDevice::skPaint2GrPaintNoShader(const SkPaint& skPaint,
344 bool justAlpha,
345 GrPaint* grPaint) {
346
347 grPaint->fDither = skPaint.isDither();
348 grPaint->fAntiAlias = skPaint.isAntiAlias();
349
350 SkXfermode::Coeff sm = SkXfermode::kOne_Coeff;
351 SkXfermode::Coeff dm = SkXfermode::kISA_Coeff;
352
353 SkXfermode* mode = skPaint.getXfermode();
354 if (mode) {
355 if (!mode->asCoeff(&sm, &dm)) {
reed@google.com1a2e8d22011-01-21 22:08:29 +0000356 SkDEBUGCODE(SkDebugf("Unsupported xfer mode.\n");)
bsalomon@google.com5782d712011-01-21 21:03:59 +0000357#if 0
358 return false;
359#endif
360 }
361 }
362 grPaint->fSrcBlendCoeff = sk_blend_to_grblend(sm);
363 grPaint->fDstBlendCoeff = sk_blend_to_grblend(dm);
364
365 if (justAlpha) {
366 uint8_t alpha = skPaint.getAlpha();
367 grPaint->fColor = GrColorPackRGBA(alpha, alpha, alpha, alpha);
368 } else {
369 grPaint->fColor = SkGr::SkColor2GrColor(skPaint.getColor());
370 grPaint->setTexture(NULL);
371 }
Scroggo97c88c22011-05-11 14:05:25 +0000372 SkColorFilter* colorFilter = skPaint.getColorFilter();
373 SkColor color;
374 SkXfermode::Mode filterMode;
375 if (colorFilter != NULL && colorFilter->asColorMode(&color, &filterMode)) {
376 grPaint->fColorFilterColor = SkGr::SkColor2GrColor(color);
377 grPaint->fColorFilterXfermode = filterMode;
378 } else {
379 grPaint->resetColorFilter();
380 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000381 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000382}
383
bsalomon@google.com5782d712011-01-21 21:03:59 +0000384bool SkGpuDevice::skPaint2GrPaintShader(const SkPaint& skPaint,
385 SkAutoCachedTexture* act,
386 const SkMatrix& ctm,
387 GrPaint* grPaint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000388
bsalomon@google.com5782d712011-01-21 21:03:59 +0000389 SkASSERT(NULL != act);
reed@google.comac10a2d2010-12-22 21:39:39 +0000390
bsalomon@google.com5782d712011-01-21 21:03:59 +0000391 SkShader* shader = skPaint.getShader();
reed@google.comac10a2d2010-12-22 21:39:39 +0000392 if (NULL == shader) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000393 return this->skPaint2GrPaintNoShader(skPaint, false, grPaint);
394 grPaint->setTexture(NULL);
395 return true;
396 } else if (!this->skPaint2GrPaintNoShader(skPaint, true, grPaint)) {
397 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000398 }
399
bsalomon@google.com5782d712011-01-21 21:03:59 +0000400 SkPaint noAlphaPaint(skPaint);
401 noAlphaPaint.setAlpha(255);
402 shader->setContext(this->accessBitmap(false), noAlphaPaint, ctm);
reed@google.comac10a2d2010-12-22 21:39:39 +0000403
reed@google.comac10a2d2010-12-22 21:39:39 +0000404 SkBitmap bitmap;
405 SkMatrix matrix;
406 SkShader::TileMode tileModes[2];
407 SkScalar twoPointParams[3];
408 SkShader::BitmapType bmptype = shader->asABitmap(&bitmap, &matrix,
409 tileModes, twoPointParams);
410
bsalomon@google.com5782d712011-01-21 21:03:59 +0000411 GrSamplerState::SampleMode sampleMode = sk_bmp_type_to_sample_mode[bmptype];
412 if (-1 == sampleMode) {
413 SkDebugf("shader->asABitmap() == kNone_BitmapType\n");
414 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000415 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000416 grPaint->fSampler.setSampleMode(sampleMode);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000417 if (skPaint.isFilterBitmap()) {
418 grPaint->fSampler.setFilter(GrSamplerState::kBilinear_Filter);
419 } else {
420 grPaint->fSampler.setFilter(GrSamplerState::kNearest_Filter);
421 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000422 grPaint->fSampler.setWrapX(sk_tile_mode_to_grwrap(tileModes[0]));
423 grPaint->fSampler.setWrapY(sk_tile_mode_to_grwrap(tileModes[1]));
reed@google.comac10a2d2010-12-22 21:39:39 +0000424 if (GrSamplerState::kRadial2_SampleMode == sampleMode) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000425 grPaint->fSampler.setRadial2Params(twoPointParams[0],
426 twoPointParams[1],
427 twoPointParams[2] < 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000428 }
429
bsalomon@google.com5782d712011-01-21 21:03:59 +0000430 GrTexture* texture = act->set(this, bitmap, grPaint->fSampler);
reed@google.comac10a2d2010-12-22 21:39:39 +0000431 if (NULL == texture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000432 SkDebugf("Couldn't convert bitmap to texture.\n");
433 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000434 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000435 grPaint->setTexture(texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000436
437 // since our texture coords will be in local space, we wack the texture
438 // matrix to map them back into 0...1 before we load it
439 SkMatrix localM;
440 if (shader->getLocalMatrix(&localM)) {
441 SkMatrix inverse;
442 if (localM.invert(&inverse)) {
443 matrix.preConcat(inverse);
444 }
445 }
446 if (SkShader::kDefault_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000447 GrScalar sx = GrFixedToScalar(GR_Fixed1 / bitmap.width());
448 GrScalar sy = GrFixedToScalar(GR_Fixed1 / bitmap.height());
reed@google.comac10a2d2010-12-22 21:39:39 +0000449 matrix.postScale(sx, sy);
reed@google.comac10a2d2010-12-22 21:39:39 +0000450 } else if (SkShader::kRadial_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000451 GrScalar s = GrFixedToScalar(GR_Fixed1 / bitmap.width());
reed@google.comac10a2d2010-12-22 21:39:39 +0000452 matrix.postScale(s, s);
453 }
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000454 grPaint->fSampler.setMatrix(matrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000455
456 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000457}
458
459///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com5782d712011-01-21 21:03:59 +0000460
461class SkPositionSource {
462public:
463 SkPositionSource(const SkPoint* points, int count)
464 : fPoints(points), fCount(count) {}
465
466 int count() const { return fCount; }
467
468 void writeValue(int i, GrPoint* dstPosition) const {
469 SkASSERT(i < fCount);
470 dstPosition->fX = SkScalarToGrScalar(fPoints[i].fX);
471 dstPosition->fY = SkScalarToGrScalar(fPoints[i].fY);
472 }
473private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000474 const SkPoint* fPoints;
bsalomon@google.com19628322011-02-03 21:30:17 +0000475 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000476};
477
478class SkTexCoordSource {
479public:
480 SkTexCoordSource(const SkPoint* coords)
481 : fCoords(coords) {}
482
483 void writeValue(int i, GrPoint* dstCoord) const {
484 dstCoord->fX = SkScalarToGrScalar(fCoords[i].fX);
485 dstCoord->fY = SkScalarToGrScalar(fCoords[i].fY);
486 }
487private:
488 const SkPoint* fCoords;
489};
490
491class SkColorSource {
492public:
493 SkColorSource(const SkColor* colors) : fColors(colors) {}
494
495 void writeValue(int i, GrColor* dstColor) const {
496 *dstColor = SkGr::SkColor2GrColor(fColors[i]);
497 }
498private:
499 const SkColor* fColors;
500};
501
502class SkIndexSource {
503public:
504 SkIndexSource(const uint16_t* indices, int count)
505 : fIndices(indices), fCount(count) {
506 }
507
508 int count() const { return fCount; }
509
510 void writeValue(int i, uint16_t* dstIndex) const {
511 *dstIndex = fIndices[i];
512 }
513
514private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000515 const uint16_t* fIndices;
bsalomon@google.com19628322011-02-03 21:30:17 +0000516 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000517};
518
519///////////////////////////////////////////////////////////////////////////////
520
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000521#if 0 // not currently being used so don't compile,
522
bsalomon@google.com5782d712011-01-21 21:03:59 +0000523// can be used for positions or texture coordinates
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000524
bsalomon@google.com5782d712011-01-21 21:03:59 +0000525class SkRectFanSource {
526public:
527 SkRectFanSource(const SkRect& rect) : fRect(rect) {}
528
529 int count() const { return 4; }
530
531 void writeValue(int i, GrPoint* dstPoint) const {
532 SkASSERT(i < 4);
533 dstPoint->fX = SkScalarToGrScalar((i % 3) ? fRect.fRight :
534 fRect.fLeft);
535 dstPoint->fY = SkScalarToGrScalar((i < 2) ? fRect.fTop :
536 fRect.fBottom);
537 }
538private:
539 const SkRect& fRect;
540};
541
542class SkIRectFanSource {
543public:
544 SkIRectFanSource(const SkIRect& rect) : fRect(rect) {}
545
546 int count() const { return 4; }
547
548 void writeValue(int i, GrPoint* dstPoint) const {
549 SkASSERT(i < 4);
550 dstPoint->fX = (i % 3) ? GrIntToScalar(fRect.fRight) :
551 GrIntToScalar(fRect.fLeft);
552 dstPoint->fY = (i < 2) ? GrIntToScalar(fRect.fTop) :
553 GrIntToScalar(fRect.fBottom);
554 }
555private:
556 const SkIRect& fRect;
557};
558
559class SkMatRectFanSource {
560public:
561 SkMatRectFanSource(const SkRect& rect, const SkMatrix& matrix)
562 : fRect(rect), fMatrix(matrix) {}
563
564 int count() const { return 4; }
565
566 void writeValue(int i, GrPoint* dstPoint) const {
567 SkASSERT(i < 4);
568
569#if SK_SCALAR_IS_GR_SCALAR
570 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
571 (i < 2) ? fRect.fTop : fRect.fBottom,
572 (SkPoint*)dstPoint);
573#else
574 SkPoint dst;
575 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
576 (i < 2) ? fRect.fTop : fRect.fBottom,
577 &dst);
578 dstPoint->fX = SkScalarToGrScalar(dst.fX);
579 dstPoint->fY = SkScalarToGrScalar(dst.fY);
580#endif
581 }
582private:
583 const SkRect& fRect;
584 const SkMatrix& fMatrix;
585};
586
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000587#endif
588
reed@google.comac10a2d2010-12-22 21:39:39 +0000589///////////////////////////////////////////////////////////////////////////////
590
bsalomon@google.com398109c2011-04-14 18:40:27 +0000591void SkGpuDevice::clear(SkColor color) {
bsalomon@google.com31a58402011-04-27 21:00:02 +0000592 fContext->clear(NULL, color);
bsalomon@google.com398109c2011-04-14 18:40:27 +0000593}
594
reed@google.comac10a2d2010-12-22 21:39:39 +0000595void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
596 CHECK_SHOULD_DRAW(draw);
597
bsalomon@google.com5782d712011-01-21 21:03:59 +0000598 GrPaint grPaint;
599 SkAutoCachedTexture act;
600 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000601 return;
602 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000603
604 fContext->drawPaint(grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000605}
606
607// must be in SkCanvas::PointMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +0000608static const GrPrimitiveType gPointMode2PrimtiveType[] = {
609 kPoints_PrimitiveType,
610 kLines_PrimitiveType,
611 kLineStrip_PrimitiveType
reed@google.comac10a2d2010-12-22 21:39:39 +0000612};
613
614void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000615 size_t count, const SkPoint pts[], const SkPaint& paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000616 CHECK_SHOULD_DRAW(draw);
617
618 SkScalar width = paint.getStrokeWidth();
619 if (width < 0) {
620 return;
621 }
622
623 // we only handle hairlines here, else we let the SkDraw call our drawPath()
624 if (width > 0) {
625 draw.drawPoints(mode, count, pts, paint, true);
626 return;
627 }
628
bsalomon@google.com5782d712011-01-21 21:03:59 +0000629 GrPaint grPaint;
630 SkAutoCachedTexture act;
631 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000632 return;
633 }
634
reed@google.comac10a2d2010-12-22 21:39:39 +0000635#if SK_SCALAR_IS_GR_SCALAR
bsalomon@google.com5782d712011-01-21 21:03:59 +0000636 fContext->drawVertices(grPaint,
637 gPointMode2PrimtiveType[mode],
638 count,
639 (GrPoint*)pts,
640 NULL,
641 NULL,
642 NULL,
643 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000644#else
bsalomon@google.com5782d712011-01-21 21:03:59 +0000645 fContext->drawCustomVertices(grPaint,
646 gPointMode2PrimtiveType[mode],
647 SkPositionSource(pts, count));
reed@google.comac10a2d2010-12-22 21:39:39 +0000648#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000649}
650
reed@google.comc9aa5872011-04-05 21:05:37 +0000651///////////////////////////////////////////////////////////////////////////////
652
reed@google.comac10a2d2010-12-22 21:39:39 +0000653void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
654 const SkPaint& paint) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000655 CHECK_SHOULD_DRAW(draw);
656
657 bool doStroke = paint.getStyle() == SkPaint::kStroke_Style;
658 SkScalar width = paint.getStrokeWidth();
659
660 /*
661 We have special code for hairline strokes, miter-strokes, and fills.
662 Anything else we just call our path code.
663 */
664 bool usePath = doStroke && width > 0 &&
665 paint.getStrokeJoin() != SkPaint::kMiter_Join;
666 // another reason we might need to call drawPath...
667 if (paint.getMaskFilter()) {
668 usePath = true;
669 }
670
671 if (usePath) {
672 SkPath path;
673 path.addRect(rect);
674 this->drawPath(draw, path, paint, NULL, true);
675 return;
676 }
677
678 GrPaint grPaint;
679 SkAutoCachedTexture act;
680 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
681 return;
682 }
reed@google.com20efde72011-05-09 17:00:02 +0000683 fContext->drawRect(grPaint, rect, doStroke ? width : -1);
reed@google.comac10a2d2010-12-22 21:39:39 +0000684}
685
reed@google.com69302852011-02-16 18:08:07 +0000686#include "SkMaskFilter.h"
687#include "SkBounder.h"
688
reed@google.com69302852011-02-16 18:08:07 +0000689static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
690 SkMaskFilter* filter, const SkMatrix& matrix,
691 const SkRegion& clip, SkBounder* bounder,
692 GrPaint* grp) {
693 SkMask srcM, dstM;
694
695 if (!SkDraw::DrawToMask(path, &clip.getBounds(), filter, &matrix, &srcM,
696 SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
697 return false;
698 }
699
700 SkAutoMaskImage autoSrc(&srcM, false);
701
702 if (!filter->filterMask(&dstM, srcM, matrix, NULL)) {
703 return false;
704 }
705 // this will free-up dstM when we're done (allocated in filterMask())
706 SkAutoMaskImage autoDst(&dstM, false);
707
708 if (clip.quickReject(dstM.fBounds)) {
709 return false;
710 }
711 if (bounder && !bounder->doIRect(dstM.fBounds)) {
712 return false;
713 }
714
715 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
716 // the current clip (and identity matrix) and grpaint settings
717
reed@google.com0c219b62011-02-16 21:31:18 +0000718 GrAutoMatrix avm(context, GrMatrix::I());
reed@google.com69302852011-02-16 18:08:07 +0000719
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000720 const GrTextureDesc desc = {
721 kNone_GrTextureFlags,
722 kNone_GrAALevel,
reed@google.com69302852011-02-16 18:08:07 +0000723 dstM.fBounds.width(),
724 dstM.fBounds.height(),
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000725 kAlpha_8_GrPixelConfig
reed@google.com69302852011-02-16 18:08:07 +0000726 };
727
728 GrTexture* texture = context->createUncachedTexture(desc, dstM.fImage,
729 dstM.fRowBytes);
730 if (NULL == texture) {
731 return false;
732 }
733
reed@google.com0c219b62011-02-16 21:31:18 +0000734 grp->setTexture(texture);
735 texture->unref();
736 grp->fSampler.setClampNoFilter();
reed@google.com69302852011-02-16 18:08:07 +0000737
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000738 GrRect d;
739 d.setLTRB(GrIntToScalar(dstM.fBounds.fLeft),
reed@google.com0c219b62011-02-16 21:31:18 +0000740 GrIntToScalar(dstM.fBounds.fTop),
741 GrIntToScalar(dstM.fBounds.fRight),
742 GrIntToScalar(dstM.fBounds.fBottom));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000743 GrRect s;
744 s.setLTRB(0, 0, GR_Scalar1, GR_Scalar1);
745 context->drawRectToRect(*grp, d, s);
reed@google.com69302852011-02-16 18:08:07 +0000746 return true;
747}
reed@google.com69302852011-02-16 18:08:07 +0000748
reed@google.com0c219b62011-02-16 21:31:18 +0000749void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
reed@google.comac10a2d2010-12-22 21:39:39 +0000750 const SkPaint& paint, const SkMatrix* prePathMatrix,
751 bool pathIsMutable) {
752 CHECK_SHOULD_DRAW(draw);
753
bsalomon@google.com5782d712011-01-21 21:03:59 +0000754 GrPaint grPaint;
755 SkAutoCachedTexture act;
756 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000757 return;
758 }
759
reed@google.com0c219b62011-02-16 21:31:18 +0000760 // BEGIN lift from SkDraw::drawPath()
761
762 SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
763 bool doFill = true;
764 SkPath tmpPath;
reed@google.comac10a2d2010-12-22 21:39:39 +0000765
766 if (prePathMatrix) {
reed@google.come3445642011-02-16 23:20:39 +0000767 SkPath* result = pathPtr;
reed@google.com0c219b62011-02-16 21:31:18 +0000768
reed@google.come3445642011-02-16 23:20:39 +0000769 if (!pathIsMutable) {
770 result = &tmpPath;
771 pathIsMutable = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000772 }
reed@google.come3445642011-02-16 23:20:39 +0000773 // should I push prePathMatrix on our MV stack temporarily, instead
774 // of applying it here? See SkDraw.cpp
775 pathPtr->transform(*prePathMatrix, result);
776 pathPtr = result;
reed@google.comac10a2d2010-12-22 21:39:39 +0000777 }
reed@google.com0c219b62011-02-16 21:31:18 +0000778 // at this point we're done with prePathMatrix
779 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
reed@google.comac10a2d2010-12-22 21:39:39 +0000780
bsalomon@google.com04de7822011-03-25 18:04:43 +0000781 // This "if" is not part of the SkDraw::drawPath() lift.
782 // When we get a 1.0 wide stroke we hairline stroke it instead of creating
783 // a new stroked-path. This is motivated by canvas2D sites that draw
784 // lines as 1.0 wide stroked paths. We can consider doing an alpha-modulated-
785 // hairline for width < 1.0 when AA is enabled.
786 static const int gMatrixMask = ~(SkMatrix::kIdentity_Mask |
787 SkMatrix::kTranslate_Mask);
788 if (!paint.getPathEffect() &&
789 SkPaint::kStroke_Style == paint.getStyle() &&
790 !(draw.fMatrix->getType() & gMatrixMask) &&
791 SK_Scalar1 == paint.getStrokeWidth()) {
792 doFill = false;
793 }
794
795 if (doFill && (paint.getPathEffect() ||
796 paint.getStyle() != SkPaint::kFill_Style)) {
reed@google.com0c219b62011-02-16 21:31:18 +0000797 doFill = paint.getFillPath(*pathPtr, &tmpPath);
798 pathPtr = &tmpPath;
799 }
800
801 // END lift from SkDraw::drawPath()
802
reed@google.com69302852011-02-16 18:08:07 +0000803 if (paint.getMaskFilter()) {
reed@google.com0c219b62011-02-16 21:31:18 +0000804 // avoid possibly allocating a new path in transform if we can
805 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
806
807 // transform the path into device space
reed@google.come3445642011-02-16 23:20:39 +0000808 pathPtr->transform(*draw.fMatrix, devPathPtr);
reed@google.com0c219b62011-02-16 21:31:18 +0000809
810 drawWithMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
reed@google.com69302852011-02-16 18:08:07 +0000811 *draw.fMatrix, *draw.fClip, draw.fBounder, &grPaint);
812 return;
813 }
reed@google.com69302852011-02-16 18:08:07 +0000814
bsalomon@google.comffca4002011-02-22 20:34:01 +0000815 GrPathFill fill = kHairLine_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000816
reed@google.com0c219b62011-02-16 21:31:18 +0000817 if (doFill) {
818 switch (pathPtr->getFillType()) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000819 case SkPath::kWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000820 fill = kWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000821 break;
822 case SkPath::kEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000823 fill = kEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000824 break;
825 case SkPath::kInverseWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000826 fill = kInverseWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000827 break;
828 case SkPath::kInverseEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000829 fill = kInverseEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000830 break;
831 default:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000832 SkDebugf("Unsupported path fill type\n");
reed@google.comac10a2d2010-12-22 21:39:39 +0000833 return;
834 }
835 }
836
reed@google.com0c219b62011-02-16 21:31:18 +0000837 SkGrPathIter iter(*pathPtr);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000838 fContext->drawPath(grPaint, &iter, fill);
reed@google.comac10a2d2010-12-22 21:39:39 +0000839}
840
reed@google.comac10a2d2010-12-22 21:39:39 +0000841void SkGpuDevice::drawBitmap(const SkDraw& draw,
842 const SkBitmap& bitmap,
843 const SkIRect* srcRectPtr,
844 const SkMatrix& m,
845 const SkPaint& paint) {
846 CHECK_SHOULD_DRAW(draw);
847
848 SkIRect srcRect;
849 if (NULL == srcRectPtr) {
850 srcRect.set(0, 0, bitmap.width(), bitmap.height());
851 } else {
852 srcRect = *srcRectPtr;
853 }
854
bsalomon@google.com5782d712011-01-21 21:03:59 +0000855 GrPaint grPaint;
856 if (!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
857 return;
858 }
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000859 if (paint.isFilterBitmap()) {
860 grPaint.fSampler.setFilter(GrSamplerState::kBilinear_Filter);
861 } else {
862 grPaint.fSampler.setFilter(GrSamplerState::kNearest_Filter);
863 }
864
bsalomon@google.com5782d712011-01-21 21:03:59 +0000865
reed@google.com02a7e6c2011-01-28 21:21:49 +0000866 const int maxTextureDim = fContext->getMaxTextureDimension();
867 if (bitmap.getTexture() || (bitmap.width() <= maxTextureDim &&
868 bitmap.height() <= maxTextureDim)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000869 // take the fast case
bsalomon@google.com5782d712011-01-21 21:03:59 +0000870 this->internalDrawBitmap(draw, bitmap, srcRect, m, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000871 return;
872 }
873
874 // undo the translate done by SkCanvas
875 int DX = SkMax32(0, srcRect.fLeft);
876 int DY = SkMax32(0, srcRect.fTop);
877 // compute clip bounds in local coordinates
878 SkIRect clipRect;
879 {
880 SkRect r;
881 r.set(draw.fClip->getBounds());
882 SkMatrix matrix, inverse;
883 matrix.setConcat(*draw.fMatrix, m);
884 if (!matrix.invert(&inverse)) {
885 return;
886 }
887 inverse.mapRect(&r);
888 r.roundOut(&clipRect);
889 // apply the canvas' translate to our local clip
890 clipRect.offset(DX, DY);
891 }
892
reed@google.com02a7e6c2011-01-28 21:21:49 +0000893 int nx = bitmap.width() / maxTextureDim;
894 int ny = bitmap.height() / maxTextureDim;
reed@google.comac10a2d2010-12-22 21:39:39 +0000895 for (int x = 0; x <= nx; x++) {
896 for (int y = 0; y <= ny; y++) {
897 SkIRect tileR;
reed@google.com02a7e6c2011-01-28 21:21:49 +0000898 tileR.set(x * maxTextureDim, y * maxTextureDim,
899 (x + 1) * maxTextureDim, (y + 1) * maxTextureDim);
reed@google.comac10a2d2010-12-22 21:39:39 +0000900 if (!SkIRect::Intersects(tileR, clipRect)) {
901 continue;
902 }
903
904 SkIRect srcR = tileR;
905 if (!srcR.intersect(srcRect)) {
906 continue;
907 }
908
909 SkBitmap tmpB;
910 if (bitmap.extractSubset(&tmpB, tileR)) {
911 // now offset it to make it "local" to our tmp bitmap
912 srcR.offset(-tileR.fLeft, -tileR.fTop);
913
914 SkMatrix tmpM(m);
915 {
916 int dx = tileR.fLeft - DX + SkMax32(0, srcR.fLeft);
917 int dy = tileR.fTop - DY + SkMax32(0, srcR.fTop);
918 tmpM.preTranslate(SkIntToScalar(dx), SkIntToScalar(dy));
919 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000920 this->internalDrawBitmap(draw, tmpB, srcR, tmpM, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000921 }
922 }
923 }
924}
925
926/*
927 * This is called by drawBitmap(), which has to handle images that may be too
928 * large to be represented by a single texture.
929 *
bsalomon@google.com5782d712011-01-21 21:03:59 +0000930 * internalDrawBitmap assumes that the specified bitmap will fit in a texture
931 * and that non-texture portion of the GrPaint has already been setup.
reed@google.comac10a2d2010-12-22 21:39:39 +0000932 */
933void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
934 const SkBitmap& bitmap,
935 const SkIRect& srcRect,
936 const SkMatrix& m,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000937 GrPaint* grPaint) {
reed@google.com02a7e6c2011-01-28 21:21:49 +0000938 SkASSERT(bitmap.width() <= fContext->getMaxTextureDimension() &&
939 bitmap.height() <= fContext->getMaxTextureDimension());
reed@google.comac10a2d2010-12-22 21:39:39 +0000940
941 SkAutoLockPixels alp(bitmap);
942 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
943 return;
944 }
945
bsalomon@google.com5782d712011-01-21 21:03:59 +0000946 grPaint->fSampler.setWrapX(GrSamplerState::kClamp_WrapMode);
947 grPaint->fSampler.setWrapY(GrSamplerState::kClamp_WrapMode);
948 grPaint->fSampler.setSampleMode(GrSamplerState::kNormal_SampleMode);
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000949 grPaint->fSampler.setMatrix(GrMatrix::I());
reed@google.comac10a2d2010-12-22 21:39:39 +0000950
951 GrTexture* texture;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000952 SkAutoCachedTexture act(this, bitmap, grPaint->fSampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000953 if (NULL == texture) {
954 return;
955 }
956
bsalomon@google.com5782d712011-01-21 21:03:59 +0000957 grPaint->setTexture(texture);
reed@google.com46799cd2011-02-22 20:56:26 +0000958
reed@google.com20efde72011-05-09 17:00:02 +0000959 GrRect dstRect = SkRect::MakeWH(GrIntToScalar(srcRect.width()),
960 GrIntToScalar(srcRect.height()));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000961 GrRect paintRect;
962 paintRect.setLTRB(GrFixedToScalar((srcRect.fLeft << 16) / bitmap.width()),
963 GrFixedToScalar((srcRect.fTop << 16) / bitmap.height()),
964 GrFixedToScalar((srcRect.fRight << 16) / bitmap.width()),
965 GrFixedToScalar((srcRect.fBottom << 16) / bitmap.height()));
reed@google.comac10a2d2010-12-22 21:39:39 +0000966
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000967 fContext->drawRectToRect(*grPaint, dstRect, paintRect, &m);
reed@google.comac10a2d2010-12-22 21:39:39 +0000968}
969
970void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
971 int left, int top, const SkPaint& paint) {
972 CHECK_SHOULD_DRAW(draw);
973
974 SkAutoLockPixels alp(bitmap);
975 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
976 return;
977 }
978
bsalomon@google.com5782d712011-01-21 21:03:59 +0000979 GrPaint grPaint;
980 if(!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
981 return;
982 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000983
bsalomon@google.com5782d712011-01-21 21:03:59 +0000984 GrAutoMatrix avm(fContext, GrMatrix::I());
985
986 GrTexture* texture;
987 grPaint.fSampler.setClampNoFilter();
988 SkAutoCachedTexture act(this, bitmap, grPaint.fSampler, &texture);
989
bsalomon@google.com5782d712011-01-21 21:03:59 +0000990 grPaint.setTexture(texture);
991
bsalomon@google.com5782d712011-01-21 21:03:59 +0000992 fContext->drawRectToRect(grPaint,
reed@google.com20efde72011-05-09 17:00:02 +0000993 GrRect::MakeXYWH(GrIntToScalar(left),
994 GrIntToScalar(top),
995 GrIntToScalar(bitmap.width()),
996 GrIntToScalar(bitmap.height())),
997 GrRect::MakeWH(GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +0000998}
999
1000void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
1001 int x, int y, const SkPaint& paint) {
1002 CHECK_SHOULD_DRAW(draw);
1003
bsalomon@google.com5782d712011-01-21 21:03:59 +00001004 GrPaint grPaint;
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001005 if (!((SkGpuDevice*)dev)->bindDeviceAsTexture(&grPaint) ||
bsalomon@google.com5782d712011-01-21 21:03:59 +00001006 !this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
1007 return;
reed@google.comac10a2d2010-12-22 21:39:39 +00001008 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001009
1010 SkASSERT(NULL != grPaint.getTexture());
1011
1012 const SkBitmap& bm = dev->accessBitmap(false);
1013 int w = bm.width();
1014 int h = bm.height();
1015
1016 GrAutoMatrix avm(fContext, GrMatrix::I());
1017
1018 grPaint.fSampler.setClampNoFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +00001019
1020 fContext->drawRectToRect(grPaint,
reed@google.com20efde72011-05-09 17:00:02 +00001021 GrRect::MakeXYWH(GrIntToScalar(x),
1022 GrIntToScalar(y),
1023 GrIntToScalar(w),
1024 GrIntToScalar(h)),
1025 GrRect::MakeWH(GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001026}
1027
1028///////////////////////////////////////////////////////////////////////////////
1029
1030// must be in SkCanvas::VertexMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +00001031static const GrPrimitiveType gVertexMode2PrimitiveType[] = {
1032 kTriangles_PrimitiveType,
1033 kTriangleStrip_PrimitiveType,
1034 kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +00001035};
1036
1037void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
1038 int vertexCount, const SkPoint vertices[],
1039 const SkPoint texs[], const SkColor colors[],
1040 SkXfermode* xmode,
1041 const uint16_t indices[], int indexCount,
1042 const SkPaint& paint) {
1043 CHECK_SHOULD_DRAW(draw);
1044
bsalomon@google.com5782d712011-01-21 21:03:59 +00001045 GrPaint grPaint;
1046 SkAutoCachedTexture act;
1047 // we ignore the shader if texs is null.
1048 if (NULL == texs) {
1049 if (!this->skPaint2GrPaintNoShader(paint, false, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001050 return;
1051 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001052 } else {
reed@google.com1a2e8d22011-01-21 22:08:29 +00001053 if (!this->skPaint2GrPaintShader(paint, &act,
1054 *draw.fMatrix,
bsalomon@google.com5782d712011-01-21 21:03:59 +00001055 &grPaint)) {
1056 return;
1057 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001058 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001059
1060 if (NULL != xmode && NULL != texs && NULL != colors) {
1061 SkXfermode::Mode mode;
1062 if (!SkXfermode::IsMode(xmode, &mode) ||
1063 SkXfermode::kMultiply_Mode != mode) {
1064 SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
1065#if 0
1066 return
1067#endif
1068 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001069 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001070
1071#if SK_SCALAR_IS_GR_SCALAR
1072 // even if GrColor and SkColor byte offsets match we need
1073 // to perform pre-multiply.
1074 if (NULL == colors) {
1075 fContext->drawVertices(grPaint,
1076 gVertexMode2PrimitiveType[vmode],
1077 vertexCount,
1078 (GrPoint*) vertices,
1079 (GrPoint*) texs,
1080 NULL,
1081 indices,
1082 indexCount);
1083 } else
1084#endif
1085 {
1086 SkTexCoordSource texSrc(texs);
1087 SkColorSource colSrc(colors);
1088 SkIndexSource idxSrc(indices, indexCount);
1089
1090 fContext->drawCustomVertices(grPaint,
1091 gVertexMode2PrimitiveType[vmode],
1092 SkPositionSource(vertices, vertexCount),
1093 (NULL == texs) ? NULL : &texSrc,
1094 (NULL == colors) ? NULL : &colSrc,
1095 (NULL == indices) ? NULL : &idxSrc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001096 }
1097}
1098
1099///////////////////////////////////////////////////////////////////////////////
1100
1101static void GlyphCacheAuxProc(void* data) {
1102 delete (GrFontScaler*)data;
1103}
1104
1105static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) {
1106 void* auxData;
1107 GrFontScaler* scaler = NULL;
1108 if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
1109 scaler = (GrFontScaler*)auxData;
1110 }
1111 if (NULL == scaler) {
1112 scaler = new SkGrFontScaler(cache);
1113 cache->setAuxProc(GlyphCacheAuxProc, scaler);
1114 }
1115 return scaler;
1116}
1117
1118static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
1119 SkFixed fx, SkFixed fy,
1120 const SkGlyph& glyph) {
1121 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1122
1123 GrSkDrawProcs* procs = (GrSkDrawProcs*)state.fDraw->fProcs;
1124
1125 if (NULL == procs->fFontScaler) {
1126 procs->fFontScaler = get_gr_font_scaler(state.fCache);
1127 }
reed@google.com39ce0ac2011-04-08 15:42:19 +00001128
1129 /*
1130 * Skia calls us with fx,fy already biased by 1/2. It does this to speed
1131 * up rounding these, so that all of its procs (like us) can just call
1132 * SkFixedFloor and get the "rounded" value.
1133 *
1134 * We take advantage of that for fx, where we pass a rounded value, but
1135 * we want the fractional fy, so we have to unbias it first.
1136 */
reed@google.comac10a2d2010-12-22 21:39:39 +00001137 procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0),
reed@google.com39ce0ac2011-04-08 15:42:19 +00001138 SkIntToFixed(SkFixedFloor(fx)),
1139 fy - SK_FixedHalf,
reed@google.comac10a2d2010-12-22 21:39:39 +00001140 procs->fFontScaler);
1141}
1142
bsalomon@google.com5782d712011-01-21 21:03:59 +00001143SkDrawProcs* SkGpuDevice::initDrawForText(GrTextContext* context) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001144
1145 // deferred allocation
1146 if (NULL == fDrawProcs) {
1147 fDrawProcs = new GrSkDrawProcs;
1148 fDrawProcs->fD1GProc = SkGPU_Draw1Glyph;
1149 fDrawProcs->fContext = fContext;
1150 }
1151
1152 // init our (and GL's) state
1153 fDrawProcs->fTextContext = context;
1154 fDrawProcs->fFontScaler = NULL;
1155 return fDrawProcs;
1156}
1157
1158void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
1159 size_t byteLength, SkScalar x, SkScalar y,
1160 const SkPaint& paint) {
1161 CHECK_SHOULD_DRAW(draw);
1162
1163 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1164 // this guy will just call our drawPath()
1165 draw.drawText((const char*)text, byteLength, x, y, paint);
1166 } else {
reed@google.comac10a2d2010-12-22 21:39:39 +00001167 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001168
1169 GrPaint grPaint;
1170 SkAutoCachedTexture act;
1171
1172 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1173 return;
1174 }
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001175 GrTextContext context(fContext, grPaint, draw.fExtMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001176 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001177 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
1178 }
1179}
1180
1181void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
1182 size_t byteLength, const SkScalar pos[],
1183 SkScalar constY, int scalarsPerPos,
1184 const SkPaint& paint) {
1185 CHECK_SHOULD_DRAW(draw);
1186
1187 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1188 // this guy will just call our drawPath()
1189 draw.drawPosText((const char*)text, byteLength, pos, constY,
1190 scalarsPerPos, paint);
1191 } else {
reed@google.comac10a2d2010-12-22 21:39:39 +00001192 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001193
1194 GrPaint grPaint;
1195 SkAutoCachedTexture act;
1196 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1197 return;
1198 }
1199
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001200 GrTextContext context(fContext, grPaint, draw.fExtMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001201 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001202 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
1203 scalarsPerPos, paint);
1204 }
1205}
1206
1207void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
1208 size_t len, const SkPath& path,
1209 const SkMatrix* m, const SkPaint& paint) {
1210 CHECK_SHOULD_DRAW(draw);
1211
1212 SkASSERT(draw.fDevice == this);
1213 draw.drawTextOnPath((const char*)text, len, path, m, paint);
1214}
1215
1216///////////////////////////////////////////////////////////////////////////////
1217
reed@google.comf67e4cf2011-03-15 20:56:58 +00001218bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
1219 if (!paint.isLCDRenderText()) {
1220 // we're cool with the paint as is
1221 return false;
1222 }
1223
1224 if (paint.getShader() ||
1225 paint.getXfermode() || // unless its srcover
1226 paint.getMaskFilter() ||
1227 paint.getRasterizer() ||
1228 paint.getColorFilter() ||
1229 paint.getPathEffect() ||
1230 paint.isFakeBoldText() ||
1231 paint.getStyle() != SkPaint::kFill_Style) {
1232 // turn off lcd
1233 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
1234 flags->fHinting = paint.getHinting();
1235 return true;
1236 }
1237 // we're cool with the paint as is
1238 return false;
1239}
1240
1241///////////////////////////////////////////////////////////////////////////////
1242
reed@google.comac10a2d2010-12-22 21:39:39 +00001243SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001244 const GrSamplerState& sampler,
1245 GrTexture** texture,
1246 bool forDeviceRenderTarget) {
1247 GrTexture* newTexture = NULL;
1248 GrTextureEntry* entry = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +00001249 GrContext* ctx = this->context();
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001250
reed@google.comac10a2d2010-12-22 21:39:39 +00001251 if (forDeviceRenderTarget) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001252 const GrTextureDesc desc = {
1253 kRenderTarget_GrTextureFlagBit,
1254 kNone_GrAALevel,
1255 bitmap.width(),
1256 bitmap.height(),
1257 SkGr::Bitmap2PixelConfig(bitmap)
1258 };
bsalomon@google.coma39f4042011-04-26 13:18:16 +00001259 entry = ctx->lockKeylessTexture(desc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001260 } else {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001261 uint32_t p0, p1;
reed@google.comac10a2d2010-12-22 21:39:39 +00001262 p0 = bitmap.getGenerationID();
1263 p1 = bitmap.pixelRefOffset();
reed@google.comac10a2d2010-12-22 21:39:39 +00001264
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001265 GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
1266 entry = ctx->findAndLockTexture(&key, sampler);
reed@google.comac10a2d2010-12-22 21:39:39 +00001267
reed@google.comac10a2d2010-12-22 21:39:39 +00001268 if (NULL == entry) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001269 entry = sk_gr_create_bitmap_texture(ctx, &key, sampler, bitmap);
1270 if (NULL == entry) {
1271 GrPrintf("---- failed to create texture for cache [%d %d]\n",
1272 bitmap.width(), bitmap.height());
1273 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001274 }
1275 }
1276
1277 if (NULL != entry) {
1278 newTexture = entry->texture();
reed@google.comac10a2d2010-12-22 21:39:39 +00001279 if (texture) {
1280 *texture = newTexture;
1281 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001282 }
1283 return (TexCache*)entry;
1284}
1285
1286void SkGpuDevice::unlockCachedTexture(TexCache* cache) {
1287 this->context()->unlockTexture((GrTextureEntry*)cache);
1288}
1289
reed@google.com7b201d22011-01-11 18:59:23 +00001290///////////////////////////////////////////////////////////////////////////////
1291
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001292SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context,
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001293 GrRenderTarget* rootRenderTarget) {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001294 GrAssert(NULL != context);
1295 GrAssert(NULL != rootRenderTarget);
1296
1297 // check this now rather than passing this value to SkGpuDevice cons.
1298 // we want the rt that is bound *now* in the 3D API, not the one
1299 // at the time of newDevice.
1300 if (SkGpuDevice::Current3DApiRenderTarget() == rootRenderTarget) {
1301 fRootRenderTarget = context->createRenderTargetFrom3DApiState();
1302 } else {
1303 fRootRenderTarget = rootRenderTarget;
1304 rootRenderTarget->ref();
1305 }
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001306
1307 fContext = context;
reed@google.com7b201d22011-01-11 18:59:23 +00001308 context->ref();
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001309
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001310 fRootTexture = NULL;
1311}
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001312
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001313SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context, GrTexture* rootRenderTargetTexture) {
1314 GrAssert(NULL != context);
1315 GrAssert(NULL != rootRenderTargetTexture);
1316 GrAssert(NULL != rootRenderTargetTexture->asRenderTarget());
1317
1318 fRootTexture = rootRenderTargetTexture;
1319 rootRenderTargetTexture->ref();
1320
1321 fRootRenderTarget = rootRenderTargetTexture->asRenderTarget();
1322 fRootRenderTarget->ref();
1323
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001324 fContext = context;
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001325 context->ref();
reed@google.com7b201d22011-01-11 18:59:23 +00001326}
1327
1328SkGpuDeviceFactory::~SkGpuDeviceFactory() {
1329 fContext->unref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001330 fRootRenderTarget->unref();
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001331 GrSafeUnref(fRootTexture);
reed@google.com7b201d22011-01-11 18:59:23 +00001332}
1333
1334SkDevice* SkGpuDeviceFactory::newDevice(SkCanvas*, SkBitmap::Config config,
1335 int width, int height,
1336 bool isOpaque, bool isLayer) {
1337 SkBitmap bm;
1338 bm.setConfig(config, width, height);
1339 bm.setIsOpaque(isOpaque);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001340 return new SkGpuDevice(fContext, bm, isLayer ? NULL : fRootRenderTarget);
reed@google.com7b201d22011-01-11 18:59:23 +00001341}