blob: 2a501776e01eb6d8a902a2884dc088e88f7cc265 [file] [log] [blame]
reed@google.comac10a2d2010-12-22 21:39:39 +00001/*
bsalomon@google.com1da07462011-03-10 14:51:57 +00002 Copyright 2011 Google Inc.
reed@google.comac10a2d2010-12-22 21:39:39 +00003
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17
18#include "GrContext.h"
19#include "GrTextContext.h"
20
reed@google.comac10a2d2010-12-22 21:39:39 +000021#include "SkGpuDevice.h"
reed@google.com7b201d22011-01-11 18:59:23 +000022#include "SkGpuDeviceFactory.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000023#include "SkGrTexturePixelRef.h"
24
25#include "SkDrawProcs.h"
26#include "SkGlyphCache.h"
reed@google.comc9aa5872011-04-05 21:05:37 +000027#include "SkUtils.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000028
29#define CACHE_LAYER_TEXTURES 1
30
31#if 0
32 extern bool (*gShouldDrawProc)();
33 #define CHECK_SHOULD_DRAW(draw) \
34 do { \
35 if (gShouldDrawProc && !gShouldDrawProc()) return; \
36 this->prepareRenderTarget(draw); \
37 } while (0)
38#else
39 #define CHECK_SHOULD_DRAW(draw) this->prepareRenderTarget(draw)
40#endif
41
42class SkAutoExtMatrix {
43public:
44 SkAutoExtMatrix(const SkMatrix* extMatrix) {
45 if (extMatrix) {
46 SkGr::SkMatrix2GrMatrix(*extMatrix, &fMatrix);
47 fExtMatrix = &fMatrix;
48 } else {
49 fExtMatrix = NULL;
50 }
51 }
52 const GrMatrix* extMatrix() const { return fExtMatrix; }
53
54private:
55 GrMatrix fMatrix;
56 GrMatrix* fExtMatrix; // NULL or &fMatrix
57};
58
59///////////////////////////////////////////////////////////////////////////////
60
61SkGpuDevice::SkAutoCachedTexture::
62 SkAutoCachedTexture(SkGpuDevice* device,
63 const SkBitmap& bitmap,
64 const GrSamplerState& sampler,
65 GrTexture** texture) {
66 GrAssert(texture);
67 fTex = NULL;
68 *texture = this->set(device, bitmap, sampler);
69}
70
71SkGpuDevice::SkAutoCachedTexture::SkAutoCachedTexture() {
72 fTex = NULL;
73}
74
75GrTexture* SkGpuDevice::SkAutoCachedTexture::set(SkGpuDevice* device,
76 const SkBitmap& bitmap,
77 const GrSamplerState& sampler) {
78 if (fTex) {
79 fDevice->unlockCachedTexture(fTex);
80 }
81 fDevice = device;
82 GrTexture* texture = (GrTexture*)bitmap.getTexture();
83 if (texture) {
84 // return the native texture
85 fTex = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +000086 } else {
87 // look it up in our cache
88 fTex = device->lockCachedTexture(bitmap, sampler, &texture, false);
89 }
90 return texture;
91}
92
93SkGpuDevice::SkAutoCachedTexture::~SkAutoCachedTexture() {
94 if (fTex) {
95 fDevice->unlockCachedTexture(fTex);
96 }
97}
98
99///////////////////////////////////////////////////////////////////////////////
100
101bool gDoTraceDraw;
102
103struct GrSkDrawProcs : public SkDrawProcs {
104public:
105 GrContext* fContext;
106 GrTextContext* fTextContext;
107 GrFontScaler* fFontScaler; // cached in the skia glyphcache
108};
109
110///////////////////////////////////////////////////////////////////////////////
111
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000112GrRenderTarget* SkGpuDevice::Current3DApiRenderTarget() {
113 return (GrRenderTarget*) -1;
114}
115
116SkGpuDevice::SkGpuDevice(GrContext* context,
117 const SkBitmap& bitmap,
118 GrRenderTarget* renderTargetOrNull)
119 : SkDevice(NULL, bitmap, (NULL == renderTargetOrNull)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000120
121 fNeedPrepareRenderTarget = false;
122 fDrawProcs = NULL;
123
reed@google.com7b201d22011-01-11 18:59:23 +0000124 fContext = context;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000125 fContext->ref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000126
127 fCache = NULL;
128 fTexture = NULL;
129 fRenderTarget = NULL;
130 fNeedClear = false;
131
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000132 if (NULL == renderTargetOrNull) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000133 SkBitmap::Config c = bitmap.config();
134 if (c != SkBitmap::kRGB_565_Config) {
135 c = SkBitmap::kARGB_8888_Config;
136 }
137 SkBitmap bm;
138 bm.setConfig(c, this->width(), this->height());
139
140#if CACHE_LAYER_TEXTURES
141
142 fCache = this->lockCachedTexture(bm, GrSamplerState::ClampNoFilter(),
143 &fTexture, true);
144 if (fCache) {
145 SkASSERT(NULL != fTexture);
bsalomon@google.com1da07462011-03-10 14:51:57 +0000146 SkASSERT(NULL != fTexture->asRenderTarget());
reed@google.comac10a2d2010-12-22 21:39:39 +0000147 }
148#else
149 const GrGpu::TextureDesc desc = {
150 GrGpu::kRenderTarget_TextureFlag,
151 GrGpu::kNone_AALevel,
152 this->width(),
153 this->height(),
154 SkGr::Bitmap2PixelConfig(bm)
155 };
156
157 fTexture = fContext->createUncachedTexture(desc, NULL, 0);
158#endif
159 if (NULL != fTexture) {
160 fRenderTarget = fTexture->asRenderTarget();
161
162 GrAssert(NULL != fRenderTarget);
163
164 // we defer the actual clear until our gainFocus()
165 fNeedClear = true;
166
167 // wrap the bitmap with a pixelref to expose our texture
168 SkGrTexturePixelRef* pr = new SkGrTexturePixelRef(fTexture);
169 this->setPixelRef(pr, 0)->unref();
170 } else {
171 GrPrintf("--- failed to create gpu-offscreen [%d %d]\n",
172 this->width(), this->height());
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000173 GrAssert(false);
reed@google.comac10a2d2010-12-22 21:39:39 +0000174 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000175 } else {
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000176 if (Current3DApiRenderTarget() == renderTargetOrNull) {
177 fRenderTarget = fContext->createRenderTargetFrom3DApiState();
178 } else {
179 fRenderTarget = renderTargetOrNull;
180 fRenderTarget->ref();
181 }
182 SkGrRenderTargetPixelRef* pr = new SkGrRenderTargetPixelRef(fRenderTarget);
183 this->setPixelRef(pr, 0)->unref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000184 }
185}
186
187SkGpuDevice::~SkGpuDevice() {
188 if (fDrawProcs) {
189 delete fDrawProcs;
190 }
191
192 if (fCache) {
193 GrAssert(NULL != fTexture);
194 GrAssert(fRenderTarget == fTexture->asRenderTarget());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000195 fContext->unlockTexture((GrTextureEntry*)fCache);
reed@google.comac10a2d2010-12-22 21:39:39 +0000196 } else if (NULL != fTexture) {
197 GrAssert(!CACHE_LAYER_TEXTURES);
198 GrAssert(fRenderTarget == fTexture->asRenderTarget());
199 fTexture->unref();
200 } else if (NULL != fRenderTarget) {
201 fRenderTarget->unref();
202 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000203 fContext->unref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000204}
205
reed@google.comac10a2d2010-12-22 21:39:39 +0000206intptr_t SkGpuDevice::getLayerTextureHandle() const {
207 if (fTexture) {
208 return fTexture->getTextureHandle();
209 } else {
210 return 0;
211 }
212}
mike@reedtribe.orgea4ac972011-04-26 11:48:33 +0000213
214SkDeviceFactory* SkGpuDevice::onNewDeviceFactory() {
215 return SkNEW_ARGS(SkGpuDeviceFactory, (fContext, fRenderTarget));
216}
217
reed@google.comac10a2d2010-12-22 21:39:39 +0000218///////////////////////////////////////////////////////////////////////////////
219
220void SkGpuDevice::makeRenderTargetCurrent() {
221 fContext->setRenderTarget(fRenderTarget);
222 fContext->flush(true);
223 fNeedPrepareRenderTarget = true;
224}
225
226///////////////////////////////////////////////////////////////////////////////
227
228bool SkGpuDevice::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
229 SkIRect bounds;
230 bounds.set(0, 0, this->width(), this->height());
231 if (!bounds.intersect(srcRect)) {
232 return false;
233 }
234
235 const int w = bounds.width();
236 const int h = bounds.height();
237 SkBitmap tmp;
238 // note we explicitly specify our rowBytes to be snug (no gap between rows)
239 tmp.setConfig(SkBitmap::kARGB_8888_Config, w, h, w * 4);
240 if (!tmp.allocPixels()) {
241 return false;
242 }
243
Scroggo813c33c2011-04-07 20:56:21 +0000244 tmp.lockPixels();
reed@google.comac10a2d2010-12-22 21:39:39 +0000245
Scroggoeb176032011-04-07 21:11:49 +0000246 bool read = fContext->readRenderTargetPixels(fRenderTarget,
247 bounds.fLeft, bounds.fTop,
248 bounds.width(), bounds.height(),
249 kRGBA_8888_GrPixelConfig,
250 tmp.getPixels());
Scroggo813c33c2011-04-07 20:56:21 +0000251 tmp.unlockPixels();
252 if (!read) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000253 return false;
254 }
255
256 tmp.swap(*bitmap);
257 return true;
258}
259
260void SkGpuDevice::writePixels(const SkBitmap& bitmap, int x, int y) {
261 SkAutoLockPixels alp(bitmap);
262 if (!bitmap.readyToDraw()) {
263 return;
264 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000265 GrPixelConfig config = SkGr::BitmapConfig2PixelConfig(bitmap.config(),
266 bitmap.isOpaque());
reed@google.comac10a2d2010-12-22 21:39:39 +0000267 fContext->setRenderTarget(fRenderTarget);
268 // we aren't setting the clip or matrix, so mark as dirty
269 // we don't need to set them for this call and don't have them anyway
270 fNeedPrepareRenderTarget = true;
271
272 fContext->writePixels(x, y, bitmap.width(), bitmap.height(),
273 config, bitmap.getPixels(), bitmap.rowBytes());
274}
275
276///////////////////////////////////////////////////////////////////////////////
277
278static void convert_matrixclip(GrContext* context, const SkMatrix& matrix,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000279 const SkClipStack& clipStack,
reed@google.com6f8f2922011-03-04 22:27:10 +0000280 const SkRegion& clipRegion,
281 const SkIPoint& origin) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000282 GrMatrix grmat;
283 SkGr::SkMatrix2GrMatrix(matrix, &grmat);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000284 context->setMatrix(grmat);
reed@google.comac10a2d2010-12-22 21:39:39 +0000285
286 SkGrClipIterator iter;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000287 iter.reset(clipStack);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000288 const SkIRect& skBounds = clipRegion.getBounds();
289 GrRect bounds;
290 bounds.setLTRB(GrIntToScalar(skBounds.fLeft),
291 GrIntToScalar(skBounds.fTop),
292 GrIntToScalar(skBounds.fRight),
293 GrIntToScalar(skBounds.fBottom));
reed@google.com6f8f2922011-03-04 22:27:10 +0000294 GrClip grc(&iter, GrIntToScalar(-origin.x()), GrIntToScalar(-origin.y()),
295 &bounds);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000296 context->setClip(grc);
reed@google.comac10a2d2010-12-22 21:39:39 +0000297}
298
299// call this ever each draw call, to ensure that the context reflects our state,
300// and not the state from some other canvas/device
301void SkGpuDevice::prepareRenderTarget(const SkDraw& draw) {
302 if (fNeedPrepareRenderTarget ||
bsalomon@google.com5782d712011-01-21 21:03:59 +0000303 fContext->getRenderTarget() != fRenderTarget) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000304
305 fContext->setRenderTarget(fRenderTarget);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000306 SkASSERT(draw.fClipStack);
307 convert_matrixclip(fContext, *draw.fMatrix,
reed@google.com6f8f2922011-03-04 22:27:10 +0000308 *draw.fClipStack, *draw.fClip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000309 fNeedPrepareRenderTarget = false;
310 }
311}
312
reed@google.com46799cd2011-02-22 20:56:26 +0000313void SkGpuDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& clip,
314 const SkClipStack& clipStack) {
315 this->INHERITED::setMatrixClip(matrix, clip, clipStack);
bsalomon@google.coma7bf6e22011-04-11 19:20:46 +0000316 // We don't need to set them now because the context may not reflect this device.
317 fNeedPrepareRenderTarget = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000318}
319
320void SkGpuDevice::gainFocus(SkCanvas* canvas, const SkMatrix& matrix,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000321 const SkRegion& clip, const SkClipStack& clipStack) {
322
reed@google.comac10a2d2010-12-22 21:39:39 +0000323 fContext->setRenderTarget(fRenderTarget);
324
bsalomon@google.comd302f142011-03-03 13:54:13 +0000325 this->INHERITED::gainFocus(canvas, matrix, clip, clipStack);
reed@google.comac10a2d2010-12-22 21:39:39 +0000326
reed@google.com6f8f2922011-03-04 22:27:10 +0000327 convert_matrixclip(fContext, matrix, clipStack, clip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000328
329 if (fNeedClear) {
bsalomon@google.com31a58402011-04-27 21:00:02 +0000330 fContext->clear(NULL, 0x0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000331 fNeedClear = false;
332 }
333}
334
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000335bool SkGpuDevice::bindDeviceAsTexture(GrPaint* paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000336 if (NULL != fTexture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000337 paint->setTexture(fTexture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000338 return true;
339 }
340 return false;
341}
342
343///////////////////////////////////////////////////////////////////////////////
344
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000345SK_COMPILE_ASSERT(SkShader::kNone_BitmapType == 0, shader_type_mismatch);
346SK_COMPILE_ASSERT(SkShader::kDefault_BitmapType == 1, shader_type_mismatch);
347SK_COMPILE_ASSERT(SkShader::kRadial_BitmapType == 2, shader_type_mismatch);
348SK_COMPILE_ASSERT(SkShader::kSweep_BitmapType == 3, shader_type_mismatch);
349SK_COMPILE_ASSERT(SkShader::kTwoPointRadial_BitmapType == 4,
350 shader_type_mismatch);
351SK_COMPILE_ASSERT(SkShader::kLast_BitmapType == 4, shader_type_mismatch);
reed@google.comac10a2d2010-12-22 21:39:39 +0000352
bsalomon@google.com5782d712011-01-21 21:03:59 +0000353static const GrSamplerState::SampleMode sk_bmp_type_to_sample_mode[] = {
354 (GrSamplerState::SampleMode) -1, // kNone_BitmapType
355 GrSamplerState::kNormal_SampleMode, // kDefault_BitmapType
356 GrSamplerState::kRadial_SampleMode, // kRadial_BitmapType
357 GrSamplerState::kSweep_SampleMode, // kSweep_BitmapType
358 GrSamplerState::kRadial2_SampleMode, // kTwoPointRadial_BitmapType
359};
360
361bool SkGpuDevice::skPaint2GrPaintNoShader(const SkPaint& skPaint,
362 bool justAlpha,
363 GrPaint* grPaint) {
364
365 grPaint->fDither = skPaint.isDither();
366 grPaint->fAntiAlias = skPaint.isAntiAlias();
367
368 SkXfermode::Coeff sm = SkXfermode::kOne_Coeff;
369 SkXfermode::Coeff dm = SkXfermode::kISA_Coeff;
370
371 SkXfermode* mode = skPaint.getXfermode();
372 if (mode) {
373 if (!mode->asCoeff(&sm, &dm)) {
reed@google.com1a2e8d22011-01-21 22:08:29 +0000374 SkDEBUGCODE(SkDebugf("Unsupported xfer mode.\n");)
bsalomon@google.com5782d712011-01-21 21:03:59 +0000375#if 0
376 return false;
377#endif
378 }
379 }
380 grPaint->fSrcBlendCoeff = sk_blend_to_grblend(sm);
381 grPaint->fDstBlendCoeff = sk_blend_to_grblend(dm);
382
383 if (justAlpha) {
384 uint8_t alpha = skPaint.getAlpha();
385 grPaint->fColor = GrColorPackRGBA(alpha, alpha, alpha, alpha);
386 } else {
387 grPaint->fColor = SkGr::SkColor2GrColor(skPaint.getColor());
388 grPaint->setTexture(NULL);
389 }
390 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000391}
392
bsalomon@google.com5782d712011-01-21 21:03:59 +0000393bool SkGpuDevice::skPaint2GrPaintShader(const SkPaint& skPaint,
394 SkAutoCachedTexture* act,
395 const SkMatrix& ctm,
396 GrPaint* grPaint) {
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) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000402 return this->skPaint2GrPaintNoShader(skPaint, false, grPaint);
403 grPaint->setTexture(NULL);
404 return true;
405 } else if (!this->skPaint2GrPaintNoShader(skPaint, true, grPaint)) {
406 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000407 }
408
bsalomon@google.com5782d712011-01-21 21:03:59 +0000409 SkPaint noAlphaPaint(skPaint);
410 noAlphaPaint.setAlpha(255);
411 shader->setContext(this->accessBitmap(false), noAlphaPaint, ctm);
reed@google.comac10a2d2010-12-22 21:39:39 +0000412
reed@google.comac10a2d2010-12-22 21:39:39 +0000413 SkBitmap bitmap;
414 SkMatrix matrix;
415 SkShader::TileMode tileModes[2];
416 SkScalar twoPointParams[3];
417 SkShader::BitmapType bmptype = shader->asABitmap(&bitmap, &matrix,
418 tileModes, twoPointParams);
419
bsalomon@google.com5782d712011-01-21 21:03:59 +0000420 GrSamplerState::SampleMode sampleMode = sk_bmp_type_to_sample_mode[bmptype];
421 if (-1 == sampleMode) {
422 SkDebugf("shader->asABitmap() == kNone_BitmapType\n");
423 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000424 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000425 grPaint->fSampler.setSampleMode(sampleMode);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000426 if (skPaint.isFilterBitmap()) {
427 grPaint->fSampler.setFilter(GrSamplerState::kBilinear_Filter);
428 } else {
429 grPaint->fSampler.setFilter(GrSamplerState::kNearest_Filter);
430 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000431 grPaint->fSampler.setWrapX(sk_tile_mode_to_grwrap(tileModes[0]));
432 grPaint->fSampler.setWrapY(sk_tile_mode_to_grwrap(tileModes[1]));
reed@google.comac10a2d2010-12-22 21:39:39 +0000433 if (GrSamplerState::kRadial2_SampleMode == sampleMode) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000434 grPaint->fSampler.setRadial2Params(twoPointParams[0],
435 twoPointParams[1],
436 twoPointParams[2] < 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000437 }
438
bsalomon@google.com5782d712011-01-21 21:03:59 +0000439 GrTexture* texture = act->set(this, bitmap, grPaint->fSampler);
reed@google.comac10a2d2010-12-22 21:39:39 +0000440 if (NULL == texture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000441 SkDebugf("Couldn't convert bitmap to texture.\n");
442 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000443 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000444 grPaint->setTexture(texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000445
446 // since our texture coords will be in local space, we wack the texture
447 // matrix to map them back into 0...1 before we load it
448 SkMatrix localM;
449 if (shader->getLocalMatrix(&localM)) {
450 SkMatrix inverse;
451 if (localM.invert(&inverse)) {
452 matrix.preConcat(inverse);
453 }
454 }
455 if (SkShader::kDefault_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000456 GrScalar sx = GrFixedToScalar(GR_Fixed1 / bitmap.width());
457 GrScalar sy = GrFixedToScalar(GR_Fixed1 / bitmap.height());
reed@google.comac10a2d2010-12-22 21:39:39 +0000458 matrix.postScale(sx, sy);
reed@google.comac10a2d2010-12-22 21:39:39 +0000459 } else if (SkShader::kRadial_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000460 GrScalar s = GrFixedToScalar(GR_Fixed1 / bitmap.width());
reed@google.comac10a2d2010-12-22 21:39:39 +0000461 matrix.postScale(s, s);
462 }
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000463 GrMatrix grMat;
464 SkGr::SkMatrix2GrMatrix(matrix, &grMat);
465 grPaint->fSampler.setMatrix(grMat);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000466
467 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000468}
469
470///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com5782d712011-01-21 21:03:59 +0000471
472class SkPositionSource {
473public:
474 SkPositionSource(const SkPoint* points, int count)
475 : fPoints(points), fCount(count) {}
476
477 int count() const { return fCount; }
478
479 void writeValue(int i, GrPoint* dstPosition) const {
480 SkASSERT(i < fCount);
481 dstPosition->fX = SkScalarToGrScalar(fPoints[i].fX);
482 dstPosition->fY = SkScalarToGrScalar(fPoints[i].fY);
483 }
484private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000485 const SkPoint* fPoints;
bsalomon@google.com19628322011-02-03 21:30:17 +0000486 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000487};
488
489class SkTexCoordSource {
490public:
491 SkTexCoordSource(const SkPoint* coords)
492 : fCoords(coords) {}
493
494 void writeValue(int i, GrPoint* dstCoord) const {
495 dstCoord->fX = SkScalarToGrScalar(fCoords[i].fX);
496 dstCoord->fY = SkScalarToGrScalar(fCoords[i].fY);
497 }
498private:
499 const SkPoint* fCoords;
500};
501
502class SkColorSource {
503public:
504 SkColorSource(const SkColor* colors) : fColors(colors) {}
505
506 void writeValue(int i, GrColor* dstColor) const {
507 *dstColor = SkGr::SkColor2GrColor(fColors[i]);
508 }
509private:
510 const SkColor* fColors;
511};
512
513class SkIndexSource {
514public:
515 SkIndexSource(const uint16_t* indices, int count)
516 : fIndices(indices), fCount(count) {
517 }
518
519 int count() const { return fCount; }
520
521 void writeValue(int i, uint16_t* dstIndex) const {
522 *dstIndex = fIndices[i];
523 }
524
525private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000526 const uint16_t* fIndices;
bsalomon@google.com19628322011-02-03 21:30:17 +0000527 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000528};
529
530///////////////////////////////////////////////////////////////////////////////
531
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000532#if 0 // not currently being used so don't compile,
533
bsalomon@google.com5782d712011-01-21 21:03:59 +0000534// can be used for positions or texture coordinates
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000535
bsalomon@google.com5782d712011-01-21 21:03:59 +0000536class SkRectFanSource {
537public:
538 SkRectFanSource(const SkRect& rect) : fRect(rect) {}
539
540 int count() const { return 4; }
541
542 void writeValue(int i, GrPoint* dstPoint) const {
543 SkASSERT(i < 4);
544 dstPoint->fX = SkScalarToGrScalar((i % 3) ? fRect.fRight :
545 fRect.fLeft);
546 dstPoint->fY = SkScalarToGrScalar((i < 2) ? fRect.fTop :
547 fRect.fBottom);
548 }
549private:
550 const SkRect& fRect;
551};
552
553class SkIRectFanSource {
554public:
555 SkIRectFanSource(const SkIRect& rect) : fRect(rect) {}
556
557 int count() const { return 4; }
558
559 void writeValue(int i, GrPoint* dstPoint) const {
560 SkASSERT(i < 4);
561 dstPoint->fX = (i % 3) ? GrIntToScalar(fRect.fRight) :
562 GrIntToScalar(fRect.fLeft);
563 dstPoint->fY = (i < 2) ? GrIntToScalar(fRect.fTop) :
564 GrIntToScalar(fRect.fBottom);
565 }
566private:
567 const SkIRect& fRect;
568};
569
570class SkMatRectFanSource {
571public:
572 SkMatRectFanSource(const SkRect& rect, const SkMatrix& matrix)
573 : fRect(rect), fMatrix(matrix) {}
574
575 int count() const { return 4; }
576
577 void writeValue(int i, GrPoint* dstPoint) const {
578 SkASSERT(i < 4);
579
580#if SK_SCALAR_IS_GR_SCALAR
581 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
582 (i < 2) ? fRect.fTop : fRect.fBottom,
583 (SkPoint*)dstPoint);
584#else
585 SkPoint dst;
586 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
587 (i < 2) ? fRect.fTop : fRect.fBottom,
588 &dst);
589 dstPoint->fX = SkScalarToGrScalar(dst.fX);
590 dstPoint->fY = SkScalarToGrScalar(dst.fY);
591#endif
592 }
593private:
594 const SkRect& fRect;
595 const SkMatrix& fMatrix;
596};
597
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000598#endif
599
reed@google.comac10a2d2010-12-22 21:39:39 +0000600///////////////////////////////////////////////////////////////////////////////
601
bsalomon@google.com398109c2011-04-14 18:40:27 +0000602void SkGpuDevice::clear(SkColor color) {
bsalomon@google.com31a58402011-04-27 21:00:02 +0000603 fContext->clear(NULL, color);
bsalomon@google.com398109c2011-04-14 18:40:27 +0000604}
605
reed@google.comac10a2d2010-12-22 21:39:39 +0000606void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
607 CHECK_SHOULD_DRAW(draw);
608
bsalomon@google.com5782d712011-01-21 21:03:59 +0000609 GrPaint grPaint;
610 SkAutoCachedTexture act;
611 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000612 return;
613 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000614
615 fContext->drawPaint(grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000616}
617
618// must be in SkCanvas::PointMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +0000619static const GrPrimitiveType gPointMode2PrimtiveType[] = {
620 kPoints_PrimitiveType,
621 kLines_PrimitiveType,
622 kLineStrip_PrimitiveType
reed@google.comac10a2d2010-12-22 21:39:39 +0000623};
624
625void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000626 size_t count, const SkPoint pts[], const SkPaint& paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000627 CHECK_SHOULD_DRAW(draw);
628
629 SkScalar width = paint.getStrokeWidth();
630 if (width < 0) {
631 return;
632 }
633
634 // we only handle hairlines here, else we let the SkDraw call our drawPath()
635 if (width > 0) {
636 draw.drawPoints(mode, count, pts, paint, true);
637 return;
638 }
639
bsalomon@google.com5782d712011-01-21 21:03:59 +0000640 GrPaint grPaint;
641 SkAutoCachedTexture act;
642 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000643 return;
644 }
645
reed@google.comac10a2d2010-12-22 21:39:39 +0000646#if SK_SCALAR_IS_GR_SCALAR
bsalomon@google.com5782d712011-01-21 21:03:59 +0000647 fContext->drawVertices(grPaint,
648 gPointMode2PrimtiveType[mode],
649 count,
650 (GrPoint*)pts,
651 NULL,
652 NULL,
653 NULL,
654 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000655#else
bsalomon@google.com5782d712011-01-21 21:03:59 +0000656 fContext->drawCustomVertices(grPaint,
657 gPointMode2PrimtiveType[mode],
658 SkPositionSource(pts, count));
reed@google.comac10a2d2010-12-22 21:39:39 +0000659#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000660}
661
reed@google.comc9aa5872011-04-05 21:05:37 +0000662///////////////////////////////////////////////////////////////////////////////
663
reed@google.comac10a2d2010-12-22 21:39:39 +0000664void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
665 const SkPaint& paint) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000666 CHECK_SHOULD_DRAW(draw);
667
668 bool doStroke = paint.getStyle() == SkPaint::kStroke_Style;
669 SkScalar width = paint.getStrokeWidth();
670
671 /*
672 We have special code for hairline strokes, miter-strokes, and fills.
673 Anything else we just call our path code.
674 */
675 bool usePath = doStroke && width > 0 &&
676 paint.getStrokeJoin() != SkPaint::kMiter_Join;
677 // another reason we might need to call drawPath...
678 if (paint.getMaskFilter()) {
679 usePath = true;
680 }
681
682 if (usePath) {
683 SkPath path;
684 path.addRect(rect);
685 this->drawPath(draw, path, paint, NULL, true);
686 return;
687 }
688
689 GrPaint grPaint;
690 SkAutoCachedTexture act;
691 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
692 return;
693 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000694 fContext->drawRect(grPaint, Sk2Gr(rect), doStroke ? width : -1);
reed@google.comac10a2d2010-12-22 21:39:39 +0000695}
696
reed@google.com69302852011-02-16 18:08:07 +0000697#include "SkMaskFilter.h"
698#include "SkBounder.h"
699
reed@google.com69302852011-02-16 18:08:07 +0000700static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
701 SkMaskFilter* filter, const SkMatrix& matrix,
702 const SkRegion& clip, SkBounder* bounder,
703 GrPaint* grp) {
704 SkMask srcM, dstM;
705
706 if (!SkDraw::DrawToMask(path, &clip.getBounds(), filter, &matrix, &srcM,
707 SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
708 return false;
709 }
710
711 SkAutoMaskImage autoSrc(&srcM, false);
712
713 if (!filter->filterMask(&dstM, srcM, matrix, NULL)) {
714 return false;
715 }
716 // this will free-up dstM when we're done (allocated in filterMask())
717 SkAutoMaskImage autoDst(&dstM, false);
718
719 if (clip.quickReject(dstM.fBounds)) {
720 return false;
721 }
722 if (bounder && !bounder->doIRect(dstM.fBounds)) {
723 return false;
724 }
725
726 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
727 // the current clip (and identity matrix) and grpaint settings
728
reed@google.com0c219b62011-02-16 21:31:18 +0000729 GrAutoMatrix avm(context, GrMatrix::I());
reed@google.com69302852011-02-16 18:08:07 +0000730
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000731 const GrTextureDesc desc = {
732 kNone_GrTextureFlags,
733 kNone_GrAALevel,
reed@google.com69302852011-02-16 18:08:07 +0000734 dstM.fBounds.width(),
735 dstM.fBounds.height(),
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000736 kAlpha_8_GrPixelConfig
reed@google.com69302852011-02-16 18:08:07 +0000737 };
738
739 GrTexture* texture = context->createUncachedTexture(desc, dstM.fImage,
740 dstM.fRowBytes);
741 if (NULL == texture) {
742 return false;
743 }
744
reed@google.com0c219b62011-02-16 21:31:18 +0000745 grp->setTexture(texture);
746 texture->unref();
747 grp->fSampler.setClampNoFilter();
reed@google.com69302852011-02-16 18:08:07 +0000748
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000749 GrRect d;
750 d.setLTRB(GrIntToScalar(dstM.fBounds.fLeft),
reed@google.com0c219b62011-02-16 21:31:18 +0000751 GrIntToScalar(dstM.fBounds.fTop),
752 GrIntToScalar(dstM.fBounds.fRight),
753 GrIntToScalar(dstM.fBounds.fBottom));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000754 GrRect s;
755 s.setLTRB(0, 0, GR_Scalar1, GR_Scalar1);
756 context->drawRectToRect(*grp, d, s);
reed@google.com69302852011-02-16 18:08:07 +0000757 return true;
758}
reed@google.com69302852011-02-16 18:08:07 +0000759
reed@google.com0c219b62011-02-16 21:31:18 +0000760void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
reed@google.comac10a2d2010-12-22 21:39:39 +0000761 const SkPaint& paint, const SkMatrix* prePathMatrix,
762 bool pathIsMutable) {
763 CHECK_SHOULD_DRAW(draw);
764
bsalomon@google.com5782d712011-01-21 21:03:59 +0000765 GrPaint grPaint;
766 SkAutoCachedTexture act;
767 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000768 return;
769 }
770
reed@google.com0c219b62011-02-16 21:31:18 +0000771 // BEGIN lift from SkDraw::drawPath()
772
773 SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
774 bool doFill = true;
775 SkPath tmpPath;
reed@google.comac10a2d2010-12-22 21:39:39 +0000776
777 if (prePathMatrix) {
reed@google.come3445642011-02-16 23:20:39 +0000778 SkPath* result = pathPtr;
reed@google.com0c219b62011-02-16 21:31:18 +0000779
reed@google.come3445642011-02-16 23:20:39 +0000780 if (!pathIsMutable) {
781 result = &tmpPath;
782 pathIsMutable = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000783 }
reed@google.come3445642011-02-16 23:20:39 +0000784 // should I push prePathMatrix on our MV stack temporarily, instead
785 // of applying it here? See SkDraw.cpp
786 pathPtr->transform(*prePathMatrix, result);
787 pathPtr = result;
reed@google.comac10a2d2010-12-22 21:39:39 +0000788 }
reed@google.com0c219b62011-02-16 21:31:18 +0000789 // at this point we're done with prePathMatrix
790 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
reed@google.comac10a2d2010-12-22 21:39:39 +0000791
bsalomon@google.com04de7822011-03-25 18:04:43 +0000792 // This "if" is not part of the SkDraw::drawPath() lift.
793 // When we get a 1.0 wide stroke we hairline stroke it instead of creating
794 // a new stroked-path. This is motivated by canvas2D sites that draw
795 // lines as 1.0 wide stroked paths. We can consider doing an alpha-modulated-
796 // hairline for width < 1.0 when AA is enabled.
797 static const int gMatrixMask = ~(SkMatrix::kIdentity_Mask |
798 SkMatrix::kTranslate_Mask);
799 if (!paint.getPathEffect() &&
800 SkPaint::kStroke_Style == paint.getStyle() &&
801 !(draw.fMatrix->getType() & gMatrixMask) &&
802 SK_Scalar1 == paint.getStrokeWidth()) {
803 doFill = false;
804 }
805
806 if (doFill && (paint.getPathEffect() ||
807 paint.getStyle() != SkPaint::kFill_Style)) {
reed@google.com0c219b62011-02-16 21:31:18 +0000808 doFill = paint.getFillPath(*pathPtr, &tmpPath);
809 pathPtr = &tmpPath;
810 }
811
812 // END lift from SkDraw::drawPath()
813
reed@google.com69302852011-02-16 18:08:07 +0000814 if (paint.getMaskFilter()) {
reed@google.com0c219b62011-02-16 21:31:18 +0000815 // avoid possibly allocating a new path in transform if we can
816 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
817
818 // transform the path into device space
reed@google.come3445642011-02-16 23:20:39 +0000819 pathPtr->transform(*draw.fMatrix, devPathPtr);
reed@google.com0c219b62011-02-16 21:31:18 +0000820
821 drawWithMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
reed@google.com69302852011-02-16 18:08:07 +0000822 *draw.fMatrix, *draw.fClip, draw.fBounder, &grPaint);
823 return;
824 }
reed@google.com69302852011-02-16 18:08:07 +0000825
bsalomon@google.comffca4002011-02-22 20:34:01 +0000826 GrPathFill fill = kHairLine_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000827
reed@google.com0c219b62011-02-16 21:31:18 +0000828 if (doFill) {
829 switch (pathPtr->getFillType()) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000830 case SkPath::kWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000831 fill = kWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000832 break;
833 case SkPath::kEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000834 fill = kEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000835 break;
836 case SkPath::kInverseWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000837 fill = kInverseWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000838 break;
839 case SkPath::kInverseEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000840 fill = kInverseEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000841 break;
842 default:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000843 SkDebugf("Unsupported path fill type\n");
reed@google.comac10a2d2010-12-22 21:39:39 +0000844 return;
845 }
846 }
847
reed@google.com0c219b62011-02-16 21:31:18 +0000848 SkGrPathIter iter(*pathPtr);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000849 fContext->drawPath(grPaint, &iter, fill);
reed@google.comac10a2d2010-12-22 21:39:39 +0000850}
851
reed@google.comac10a2d2010-12-22 21:39:39 +0000852void SkGpuDevice::drawBitmap(const SkDraw& draw,
853 const SkBitmap& bitmap,
854 const SkIRect* srcRectPtr,
855 const SkMatrix& m,
856 const SkPaint& paint) {
857 CHECK_SHOULD_DRAW(draw);
858
859 SkIRect srcRect;
860 if (NULL == srcRectPtr) {
861 srcRect.set(0, 0, bitmap.width(), bitmap.height());
862 } else {
863 srcRect = *srcRectPtr;
864 }
865
bsalomon@google.com5782d712011-01-21 21:03:59 +0000866 GrPaint grPaint;
867 if (!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
868 return;
869 }
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000870 if (paint.isFilterBitmap()) {
871 grPaint.fSampler.setFilter(GrSamplerState::kBilinear_Filter);
872 } else {
873 grPaint.fSampler.setFilter(GrSamplerState::kNearest_Filter);
874 }
875
bsalomon@google.com5782d712011-01-21 21:03:59 +0000876
reed@google.com02a7e6c2011-01-28 21:21:49 +0000877 const int maxTextureDim = fContext->getMaxTextureDimension();
878 if (bitmap.getTexture() || (bitmap.width() <= maxTextureDim &&
879 bitmap.height() <= maxTextureDim)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000880 // take the fast case
bsalomon@google.com5782d712011-01-21 21:03:59 +0000881 this->internalDrawBitmap(draw, bitmap, srcRect, m, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000882 return;
883 }
884
885 // undo the translate done by SkCanvas
886 int DX = SkMax32(0, srcRect.fLeft);
887 int DY = SkMax32(0, srcRect.fTop);
888 // compute clip bounds in local coordinates
889 SkIRect clipRect;
890 {
891 SkRect r;
892 r.set(draw.fClip->getBounds());
893 SkMatrix matrix, inverse;
894 matrix.setConcat(*draw.fMatrix, m);
895 if (!matrix.invert(&inverse)) {
896 return;
897 }
898 inverse.mapRect(&r);
899 r.roundOut(&clipRect);
900 // apply the canvas' translate to our local clip
901 clipRect.offset(DX, DY);
902 }
903
reed@google.com02a7e6c2011-01-28 21:21:49 +0000904 int nx = bitmap.width() / maxTextureDim;
905 int ny = bitmap.height() / maxTextureDim;
reed@google.comac10a2d2010-12-22 21:39:39 +0000906 for (int x = 0; x <= nx; x++) {
907 for (int y = 0; y <= ny; y++) {
908 SkIRect tileR;
reed@google.com02a7e6c2011-01-28 21:21:49 +0000909 tileR.set(x * maxTextureDim, y * maxTextureDim,
910 (x + 1) * maxTextureDim, (y + 1) * maxTextureDim);
reed@google.comac10a2d2010-12-22 21:39:39 +0000911 if (!SkIRect::Intersects(tileR, clipRect)) {
912 continue;
913 }
914
915 SkIRect srcR = tileR;
916 if (!srcR.intersect(srcRect)) {
917 continue;
918 }
919
920 SkBitmap tmpB;
921 if (bitmap.extractSubset(&tmpB, tileR)) {
922 // now offset it to make it "local" to our tmp bitmap
923 srcR.offset(-tileR.fLeft, -tileR.fTop);
924
925 SkMatrix tmpM(m);
926 {
927 int dx = tileR.fLeft - DX + SkMax32(0, srcR.fLeft);
928 int dy = tileR.fTop - DY + SkMax32(0, srcR.fTop);
929 tmpM.preTranslate(SkIntToScalar(dx), SkIntToScalar(dy));
930 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000931 this->internalDrawBitmap(draw, tmpB, srcR, tmpM, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000932 }
933 }
934 }
935}
936
937/*
938 * This is called by drawBitmap(), which has to handle images that may be too
939 * large to be represented by a single texture.
940 *
bsalomon@google.com5782d712011-01-21 21:03:59 +0000941 * internalDrawBitmap assumes that the specified bitmap will fit in a texture
942 * and that non-texture portion of the GrPaint has already been setup.
reed@google.comac10a2d2010-12-22 21:39:39 +0000943 */
944void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
945 const SkBitmap& bitmap,
946 const SkIRect& srcRect,
947 const SkMatrix& m,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000948 GrPaint* grPaint) {
reed@google.com02a7e6c2011-01-28 21:21:49 +0000949 SkASSERT(bitmap.width() <= fContext->getMaxTextureDimension() &&
950 bitmap.height() <= fContext->getMaxTextureDimension());
reed@google.comac10a2d2010-12-22 21:39:39 +0000951
952 SkAutoLockPixels alp(bitmap);
953 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
954 return;
955 }
956
bsalomon@google.com5782d712011-01-21 21:03:59 +0000957 grPaint->fSampler.setWrapX(GrSamplerState::kClamp_WrapMode);
958 grPaint->fSampler.setWrapY(GrSamplerState::kClamp_WrapMode);
959 grPaint->fSampler.setSampleMode(GrSamplerState::kNormal_SampleMode);
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000960 grPaint->fSampler.setMatrix(GrMatrix::I());
reed@google.comac10a2d2010-12-22 21:39:39 +0000961
962 GrTexture* texture;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000963 SkAutoCachedTexture act(this, bitmap, grPaint->fSampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000964 if (NULL == texture) {
965 return;
966 }
967
bsalomon@google.com5782d712011-01-21 21:03:59 +0000968 grPaint->setTexture(texture);
reed@google.com46799cd2011-02-22 20:56:26 +0000969
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000970 GrRect dstRect(0, 0, GrIntToScalar(srcRect.width()), GrIntToScalar(srcRect.height()));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000971 GrRect paintRect;
972 paintRect.setLTRB(GrFixedToScalar((srcRect.fLeft << 16) / bitmap.width()),
973 GrFixedToScalar((srcRect.fTop << 16) / bitmap.height()),
974 GrFixedToScalar((srcRect.fRight << 16) / bitmap.width()),
975 GrFixedToScalar((srcRect.fBottom << 16) / bitmap.height()));
reed@google.comac10a2d2010-12-22 21:39:39 +0000976
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000977 GrMatrix grMat;
978 SkGr::SkMatrix2GrMatrix(m, &grMat);
reed@google.comac10a2d2010-12-22 21:39:39 +0000979
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000980 fContext->drawRectToRect(*grPaint, dstRect, paintRect, &grMat);
reed@google.comac10a2d2010-12-22 21:39:39 +0000981}
982
983void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
984 int left, int top, const SkPaint& paint) {
985 CHECK_SHOULD_DRAW(draw);
986
987 SkAutoLockPixels alp(bitmap);
988 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
989 return;
990 }
991
bsalomon@google.com5782d712011-01-21 21:03:59 +0000992 GrPaint grPaint;
993 if(!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
994 return;
995 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000996
bsalomon@google.com5782d712011-01-21 21:03:59 +0000997 GrAutoMatrix avm(fContext, GrMatrix::I());
998
999 GrTexture* texture;
1000 grPaint.fSampler.setClampNoFilter();
1001 SkAutoCachedTexture act(this, bitmap, grPaint.fSampler, &texture);
1002
bsalomon@google.com5782d712011-01-21 21:03:59 +00001003 grPaint.setTexture(texture);
1004
bsalomon@google.com5782d712011-01-21 21:03:59 +00001005 fContext->drawRectToRect(grPaint,
1006 GrRect(GrIntToScalar(left), GrIntToScalar(top),
1007 GrIntToScalar(left + bitmap.width()),
1008 GrIntToScalar(top + bitmap.height())),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001009 GrRect(0, 0, GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001010}
1011
1012void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
1013 int x, int y, const SkPaint& paint) {
1014 CHECK_SHOULD_DRAW(draw);
1015
bsalomon@google.com5782d712011-01-21 21:03:59 +00001016 GrPaint grPaint;
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001017 if (!((SkGpuDevice*)dev)->bindDeviceAsTexture(&grPaint) ||
bsalomon@google.com5782d712011-01-21 21:03:59 +00001018 !this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
1019 return;
reed@google.comac10a2d2010-12-22 21:39:39 +00001020 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001021
1022 SkASSERT(NULL != grPaint.getTexture());
1023
1024 const SkBitmap& bm = dev->accessBitmap(false);
1025 int w = bm.width();
1026 int h = bm.height();
1027
1028 GrAutoMatrix avm(fContext, GrMatrix::I());
1029
1030 grPaint.fSampler.setClampNoFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +00001031
1032 fContext->drawRectToRect(grPaint,
reed@google.com1a2e8d22011-01-21 22:08:29 +00001033 GrRect(GrIntToScalar(x),
1034 GrIntToScalar(y),
1035 GrIntToScalar(x + w),
bsalomon@google.com5782d712011-01-21 21:03:59 +00001036 GrIntToScalar(y + h)),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001037 GrRect(0, 0, GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001038}
1039
1040///////////////////////////////////////////////////////////////////////////////
1041
1042// must be in SkCanvas::VertexMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +00001043static const GrPrimitiveType gVertexMode2PrimitiveType[] = {
1044 kTriangles_PrimitiveType,
1045 kTriangleStrip_PrimitiveType,
1046 kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +00001047};
1048
1049void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
1050 int vertexCount, const SkPoint vertices[],
1051 const SkPoint texs[], const SkColor colors[],
1052 SkXfermode* xmode,
1053 const uint16_t indices[], int indexCount,
1054 const SkPaint& paint) {
1055 CHECK_SHOULD_DRAW(draw);
1056
bsalomon@google.com5782d712011-01-21 21:03:59 +00001057 GrPaint grPaint;
1058 SkAutoCachedTexture act;
1059 // we ignore the shader if texs is null.
1060 if (NULL == texs) {
1061 if (!this->skPaint2GrPaintNoShader(paint, false, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001062 return;
1063 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001064 } else {
reed@google.com1a2e8d22011-01-21 22:08:29 +00001065 if (!this->skPaint2GrPaintShader(paint, &act,
1066 *draw.fMatrix,
bsalomon@google.com5782d712011-01-21 21:03:59 +00001067 &grPaint)) {
1068 return;
1069 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001070 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001071
1072 if (NULL != xmode && NULL != texs && NULL != colors) {
1073 SkXfermode::Mode mode;
1074 if (!SkXfermode::IsMode(xmode, &mode) ||
1075 SkXfermode::kMultiply_Mode != mode) {
1076 SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
1077#if 0
1078 return
1079#endif
1080 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001081 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001082
1083#if SK_SCALAR_IS_GR_SCALAR
1084 // even if GrColor and SkColor byte offsets match we need
1085 // to perform pre-multiply.
1086 if (NULL == colors) {
1087 fContext->drawVertices(grPaint,
1088 gVertexMode2PrimitiveType[vmode],
1089 vertexCount,
1090 (GrPoint*) vertices,
1091 (GrPoint*) texs,
1092 NULL,
1093 indices,
1094 indexCount);
1095 } else
1096#endif
1097 {
1098 SkTexCoordSource texSrc(texs);
1099 SkColorSource colSrc(colors);
1100 SkIndexSource idxSrc(indices, indexCount);
1101
1102 fContext->drawCustomVertices(grPaint,
1103 gVertexMode2PrimitiveType[vmode],
1104 SkPositionSource(vertices, vertexCount),
1105 (NULL == texs) ? NULL : &texSrc,
1106 (NULL == colors) ? NULL : &colSrc,
1107 (NULL == indices) ? NULL : &idxSrc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001108 }
1109}
1110
1111///////////////////////////////////////////////////////////////////////////////
1112
1113static void GlyphCacheAuxProc(void* data) {
1114 delete (GrFontScaler*)data;
1115}
1116
1117static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) {
1118 void* auxData;
1119 GrFontScaler* scaler = NULL;
1120 if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
1121 scaler = (GrFontScaler*)auxData;
1122 }
1123 if (NULL == scaler) {
1124 scaler = new SkGrFontScaler(cache);
1125 cache->setAuxProc(GlyphCacheAuxProc, scaler);
1126 }
1127 return scaler;
1128}
1129
1130static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
1131 SkFixed fx, SkFixed fy,
1132 const SkGlyph& glyph) {
1133 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1134
1135 GrSkDrawProcs* procs = (GrSkDrawProcs*)state.fDraw->fProcs;
1136
1137 if (NULL == procs->fFontScaler) {
1138 procs->fFontScaler = get_gr_font_scaler(state.fCache);
1139 }
reed@google.com39ce0ac2011-04-08 15:42:19 +00001140
1141 /*
1142 * Skia calls us with fx,fy already biased by 1/2. It does this to speed
1143 * up rounding these, so that all of its procs (like us) can just call
1144 * SkFixedFloor and get the "rounded" value.
1145 *
1146 * We take advantage of that for fx, where we pass a rounded value, but
1147 * we want the fractional fy, so we have to unbias it first.
1148 */
reed@google.comac10a2d2010-12-22 21:39:39 +00001149 procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0),
reed@google.com39ce0ac2011-04-08 15:42:19 +00001150 SkIntToFixed(SkFixedFloor(fx)),
1151 fy - SK_FixedHalf,
reed@google.comac10a2d2010-12-22 21:39:39 +00001152 procs->fFontScaler);
1153}
1154
bsalomon@google.com5782d712011-01-21 21:03:59 +00001155SkDrawProcs* SkGpuDevice::initDrawForText(GrTextContext* context) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001156
1157 // deferred allocation
1158 if (NULL == fDrawProcs) {
1159 fDrawProcs = new GrSkDrawProcs;
1160 fDrawProcs->fD1GProc = SkGPU_Draw1Glyph;
1161 fDrawProcs->fContext = fContext;
1162 }
1163
1164 // init our (and GL's) state
1165 fDrawProcs->fTextContext = context;
1166 fDrawProcs->fFontScaler = NULL;
1167 return fDrawProcs;
1168}
1169
1170void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
1171 size_t byteLength, SkScalar x, SkScalar y,
1172 const SkPaint& paint) {
1173 CHECK_SHOULD_DRAW(draw);
1174
1175 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1176 // this guy will just call our drawPath()
1177 draw.drawText((const char*)text, byteLength, x, y, paint);
1178 } else {
1179 SkAutoExtMatrix aem(draw.fExtMatrix);
1180 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001181
1182 GrPaint grPaint;
1183 SkAutoCachedTexture act;
1184
1185 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1186 return;
1187 }
1188 GrTextContext context(fContext, grPaint, aem.extMatrix());
1189 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001190 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
1191 }
1192}
1193
1194void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
1195 size_t byteLength, const SkScalar pos[],
1196 SkScalar constY, int scalarsPerPos,
1197 const SkPaint& paint) {
1198 CHECK_SHOULD_DRAW(draw);
1199
1200 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1201 // this guy will just call our drawPath()
1202 draw.drawPosText((const char*)text, byteLength, pos, constY,
1203 scalarsPerPos, paint);
1204 } else {
1205 SkAutoExtMatrix aem(draw.fExtMatrix);
1206 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001207
1208 GrPaint grPaint;
1209 SkAutoCachedTexture act;
1210 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1211 return;
1212 }
1213
1214 GrTextContext context(fContext, grPaint, aem.extMatrix());
1215 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001216 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
1217 scalarsPerPos, paint);
1218 }
1219}
1220
1221void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
1222 size_t len, const SkPath& path,
1223 const SkMatrix* m, const SkPaint& paint) {
1224 CHECK_SHOULD_DRAW(draw);
1225
1226 SkASSERT(draw.fDevice == this);
1227 draw.drawTextOnPath((const char*)text, len, path, m, paint);
1228}
1229
1230///////////////////////////////////////////////////////////////////////////////
1231
reed@google.comf67e4cf2011-03-15 20:56:58 +00001232bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
1233 if (!paint.isLCDRenderText()) {
1234 // we're cool with the paint as is
1235 return false;
1236 }
1237
1238 if (paint.getShader() ||
1239 paint.getXfermode() || // unless its srcover
1240 paint.getMaskFilter() ||
1241 paint.getRasterizer() ||
1242 paint.getColorFilter() ||
1243 paint.getPathEffect() ||
1244 paint.isFakeBoldText() ||
1245 paint.getStyle() != SkPaint::kFill_Style) {
1246 // turn off lcd
1247 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
1248 flags->fHinting = paint.getHinting();
1249 return true;
1250 }
1251 // we're cool with the paint as is
1252 return false;
1253}
1254
1255///////////////////////////////////////////////////////////////////////////////
1256
reed@google.comac10a2d2010-12-22 21:39:39 +00001257SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001258 const GrSamplerState& sampler,
1259 GrTexture** texture,
1260 bool forDeviceRenderTarget) {
1261 GrTexture* newTexture = NULL;
1262 GrTextureEntry* entry = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +00001263 GrContext* ctx = this->context();
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001264
reed@google.comac10a2d2010-12-22 21:39:39 +00001265 if (forDeviceRenderTarget) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001266 const GrTextureDesc desc = {
1267 kRenderTarget_GrTextureFlagBit,
1268 kNone_GrAALevel,
1269 bitmap.width(),
1270 bitmap.height(),
1271 SkGr::Bitmap2PixelConfig(bitmap)
1272 };
bsalomon@google.coma39f4042011-04-26 13:18:16 +00001273 entry = ctx->lockKeylessTexture(desc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001274 } else {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001275 uint32_t p0, p1;
reed@google.comac10a2d2010-12-22 21:39:39 +00001276 p0 = bitmap.getGenerationID();
1277 p1 = bitmap.pixelRefOffset();
reed@google.comac10a2d2010-12-22 21:39:39 +00001278
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001279 GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
1280 entry = ctx->findAndLockTexture(&key, sampler);
reed@google.comac10a2d2010-12-22 21:39:39 +00001281
reed@google.comac10a2d2010-12-22 21:39:39 +00001282 if (NULL == entry) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001283 entry = sk_gr_create_bitmap_texture(ctx, &key, sampler, bitmap);
1284 if (NULL == entry) {
1285 GrPrintf("---- failed to create texture for cache [%d %d]\n",
1286 bitmap.width(), bitmap.height());
1287 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001288 }
1289 }
1290
1291 if (NULL != entry) {
1292 newTexture = entry->texture();
reed@google.comac10a2d2010-12-22 21:39:39 +00001293 if (texture) {
1294 *texture = newTexture;
1295 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001296 }
1297 return (TexCache*)entry;
1298}
1299
1300void SkGpuDevice::unlockCachedTexture(TexCache* cache) {
1301 this->context()->unlockTexture((GrTextureEntry*)cache);
1302}
1303
reed@google.com7b201d22011-01-11 18:59:23 +00001304///////////////////////////////////////////////////////////////////////////////
1305
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001306SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context,
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001307 GrRenderTarget* rootRenderTarget) {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001308 GrAssert(NULL != context);
1309 GrAssert(NULL != rootRenderTarget);
1310
1311 // check this now rather than passing this value to SkGpuDevice cons.
1312 // we want the rt that is bound *now* in the 3D API, not the one
1313 // at the time of newDevice.
1314 if (SkGpuDevice::Current3DApiRenderTarget() == rootRenderTarget) {
1315 fRootRenderTarget = context->createRenderTargetFrom3DApiState();
1316 } else {
1317 fRootRenderTarget = rootRenderTarget;
1318 rootRenderTarget->ref();
1319 }
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001320
1321 fContext = context;
reed@google.com7b201d22011-01-11 18:59:23 +00001322 context->ref();
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001323
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001324 fRootTexture = NULL;
1325}
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001326
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001327SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context, GrTexture* rootRenderTargetTexture) {
1328 GrAssert(NULL != context);
1329 GrAssert(NULL != rootRenderTargetTexture);
1330 GrAssert(NULL != rootRenderTargetTexture->asRenderTarget());
1331
1332 fRootTexture = rootRenderTargetTexture;
1333 rootRenderTargetTexture->ref();
1334
1335 fRootRenderTarget = rootRenderTargetTexture->asRenderTarget();
1336 fRootRenderTarget->ref();
1337
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001338 fContext = context;
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001339 context->ref();
reed@google.com7b201d22011-01-11 18:59:23 +00001340}
1341
1342SkGpuDeviceFactory::~SkGpuDeviceFactory() {
1343 fContext->unref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001344 fRootRenderTarget->unref();
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001345 GrSafeUnref(fRootTexture);
reed@google.com7b201d22011-01-11 18:59:23 +00001346}
1347
1348SkDevice* SkGpuDeviceFactory::newDevice(SkCanvas*, SkBitmap::Config config,
1349 int width, int height,
1350 bool isOpaque, bool isLayer) {
1351 SkBitmap bm;
1352 bm.setConfig(config, width, height);
1353 bm.setIsOpaque(isOpaque);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001354 return new SkGpuDevice(fContext, bm, isLayer ? NULL : fRootRenderTarget);
reed@google.com7b201d22011-01-11 18:59:23 +00001355}