blob: afd5bd37abc3eb96f397f2bff6ab796a4f315d44 [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 }
reed@google.com20efde72011-05-09 17:00:02 +0000694 fContext->drawRect(grPaint, 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
reed@google.com20efde72011-05-09 17:00:02 +0000970 GrRect dstRect = SkRect::MakeWH(GrIntToScalar(srcRect.width()),
971 GrIntToScalar(srcRect.height()));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000972 GrRect paintRect;
973 paintRect.setLTRB(GrFixedToScalar((srcRect.fLeft << 16) / bitmap.width()),
974 GrFixedToScalar((srcRect.fTop << 16) / bitmap.height()),
975 GrFixedToScalar((srcRect.fRight << 16) / bitmap.width()),
976 GrFixedToScalar((srcRect.fBottom << 16) / bitmap.height()));
reed@google.comac10a2d2010-12-22 21:39:39 +0000977
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000978 GrMatrix grMat;
979 SkGr::SkMatrix2GrMatrix(m, &grMat);
reed@google.comac10a2d2010-12-22 21:39:39 +0000980
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000981 fContext->drawRectToRect(*grPaint, dstRect, paintRect, &grMat);
reed@google.comac10a2d2010-12-22 21:39:39 +0000982}
983
984void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
985 int left, int top, const SkPaint& paint) {
986 CHECK_SHOULD_DRAW(draw);
987
988 SkAutoLockPixels alp(bitmap);
989 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
990 return;
991 }
992
bsalomon@google.com5782d712011-01-21 21:03:59 +0000993 GrPaint grPaint;
994 if(!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
995 return;
996 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000997
bsalomon@google.com5782d712011-01-21 21:03:59 +0000998 GrAutoMatrix avm(fContext, GrMatrix::I());
999
1000 GrTexture* texture;
1001 grPaint.fSampler.setClampNoFilter();
1002 SkAutoCachedTexture act(this, bitmap, grPaint.fSampler, &texture);
1003
bsalomon@google.com5782d712011-01-21 21:03:59 +00001004 grPaint.setTexture(texture);
1005
bsalomon@google.com5782d712011-01-21 21:03:59 +00001006 fContext->drawRectToRect(grPaint,
reed@google.com20efde72011-05-09 17:00:02 +00001007 GrRect::MakeXYWH(GrIntToScalar(left),
1008 GrIntToScalar(top),
1009 GrIntToScalar(bitmap.width()),
1010 GrIntToScalar(bitmap.height())),
1011 GrRect::MakeWH(GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001012}
1013
1014void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
1015 int x, int y, const SkPaint& paint) {
1016 CHECK_SHOULD_DRAW(draw);
1017
bsalomon@google.com5782d712011-01-21 21:03:59 +00001018 GrPaint grPaint;
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001019 if (!((SkGpuDevice*)dev)->bindDeviceAsTexture(&grPaint) ||
bsalomon@google.com5782d712011-01-21 21:03:59 +00001020 !this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
1021 return;
reed@google.comac10a2d2010-12-22 21:39:39 +00001022 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001023
1024 SkASSERT(NULL != grPaint.getTexture());
1025
1026 const SkBitmap& bm = dev->accessBitmap(false);
1027 int w = bm.width();
1028 int h = bm.height();
1029
1030 GrAutoMatrix avm(fContext, GrMatrix::I());
1031
1032 grPaint.fSampler.setClampNoFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +00001033
1034 fContext->drawRectToRect(grPaint,
reed@google.com20efde72011-05-09 17:00:02 +00001035 GrRect::MakeXYWH(GrIntToScalar(x),
1036 GrIntToScalar(y),
1037 GrIntToScalar(w),
1038 GrIntToScalar(h)),
1039 GrRect::MakeWH(GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001040}
1041
1042///////////////////////////////////////////////////////////////////////////////
1043
1044// must be in SkCanvas::VertexMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +00001045static const GrPrimitiveType gVertexMode2PrimitiveType[] = {
1046 kTriangles_PrimitiveType,
1047 kTriangleStrip_PrimitiveType,
1048 kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +00001049};
1050
1051void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
1052 int vertexCount, const SkPoint vertices[],
1053 const SkPoint texs[], const SkColor colors[],
1054 SkXfermode* xmode,
1055 const uint16_t indices[], int indexCount,
1056 const SkPaint& paint) {
1057 CHECK_SHOULD_DRAW(draw);
1058
bsalomon@google.com5782d712011-01-21 21:03:59 +00001059 GrPaint grPaint;
1060 SkAutoCachedTexture act;
1061 // we ignore the shader if texs is null.
1062 if (NULL == texs) {
1063 if (!this->skPaint2GrPaintNoShader(paint, false, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001064 return;
1065 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001066 } else {
reed@google.com1a2e8d22011-01-21 22:08:29 +00001067 if (!this->skPaint2GrPaintShader(paint, &act,
1068 *draw.fMatrix,
bsalomon@google.com5782d712011-01-21 21:03:59 +00001069 &grPaint)) {
1070 return;
1071 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001072 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001073
1074 if (NULL != xmode && NULL != texs && NULL != colors) {
1075 SkXfermode::Mode mode;
1076 if (!SkXfermode::IsMode(xmode, &mode) ||
1077 SkXfermode::kMultiply_Mode != mode) {
1078 SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
1079#if 0
1080 return
1081#endif
1082 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001083 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001084
1085#if SK_SCALAR_IS_GR_SCALAR
1086 // even if GrColor and SkColor byte offsets match we need
1087 // to perform pre-multiply.
1088 if (NULL == colors) {
1089 fContext->drawVertices(grPaint,
1090 gVertexMode2PrimitiveType[vmode],
1091 vertexCount,
1092 (GrPoint*) vertices,
1093 (GrPoint*) texs,
1094 NULL,
1095 indices,
1096 indexCount);
1097 } else
1098#endif
1099 {
1100 SkTexCoordSource texSrc(texs);
1101 SkColorSource colSrc(colors);
1102 SkIndexSource idxSrc(indices, indexCount);
1103
1104 fContext->drawCustomVertices(grPaint,
1105 gVertexMode2PrimitiveType[vmode],
1106 SkPositionSource(vertices, vertexCount),
1107 (NULL == texs) ? NULL : &texSrc,
1108 (NULL == colors) ? NULL : &colSrc,
1109 (NULL == indices) ? NULL : &idxSrc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001110 }
1111}
1112
1113///////////////////////////////////////////////////////////////////////////////
1114
1115static void GlyphCacheAuxProc(void* data) {
1116 delete (GrFontScaler*)data;
1117}
1118
1119static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) {
1120 void* auxData;
1121 GrFontScaler* scaler = NULL;
1122 if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
1123 scaler = (GrFontScaler*)auxData;
1124 }
1125 if (NULL == scaler) {
1126 scaler = new SkGrFontScaler(cache);
1127 cache->setAuxProc(GlyphCacheAuxProc, scaler);
1128 }
1129 return scaler;
1130}
1131
1132static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
1133 SkFixed fx, SkFixed fy,
1134 const SkGlyph& glyph) {
1135 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1136
1137 GrSkDrawProcs* procs = (GrSkDrawProcs*)state.fDraw->fProcs;
1138
1139 if (NULL == procs->fFontScaler) {
1140 procs->fFontScaler = get_gr_font_scaler(state.fCache);
1141 }
reed@google.com39ce0ac2011-04-08 15:42:19 +00001142
1143 /*
1144 * Skia calls us with fx,fy already biased by 1/2. It does this to speed
1145 * up rounding these, so that all of its procs (like us) can just call
1146 * SkFixedFloor and get the "rounded" value.
1147 *
1148 * We take advantage of that for fx, where we pass a rounded value, but
1149 * we want the fractional fy, so we have to unbias it first.
1150 */
reed@google.comac10a2d2010-12-22 21:39:39 +00001151 procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0),
reed@google.com39ce0ac2011-04-08 15:42:19 +00001152 SkIntToFixed(SkFixedFloor(fx)),
1153 fy - SK_FixedHalf,
reed@google.comac10a2d2010-12-22 21:39:39 +00001154 procs->fFontScaler);
1155}
1156
bsalomon@google.com5782d712011-01-21 21:03:59 +00001157SkDrawProcs* SkGpuDevice::initDrawForText(GrTextContext* context) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001158
1159 // deferred allocation
1160 if (NULL == fDrawProcs) {
1161 fDrawProcs = new GrSkDrawProcs;
1162 fDrawProcs->fD1GProc = SkGPU_Draw1Glyph;
1163 fDrawProcs->fContext = fContext;
1164 }
1165
1166 // init our (and GL's) state
1167 fDrawProcs->fTextContext = context;
1168 fDrawProcs->fFontScaler = NULL;
1169 return fDrawProcs;
1170}
1171
1172void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
1173 size_t byteLength, SkScalar x, SkScalar y,
1174 const SkPaint& paint) {
1175 CHECK_SHOULD_DRAW(draw);
1176
1177 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1178 // this guy will just call our drawPath()
1179 draw.drawText((const char*)text, byteLength, x, y, paint);
1180 } else {
1181 SkAutoExtMatrix aem(draw.fExtMatrix);
1182 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001183
1184 GrPaint grPaint;
1185 SkAutoCachedTexture act;
1186
1187 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1188 return;
1189 }
1190 GrTextContext context(fContext, grPaint, aem.extMatrix());
1191 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001192 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
1193 }
1194}
1195
1196void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
1197 size_t byteLength, const SkScalar pos[],
1198 SkScalar constY, int scalarsPerPos,
1199 const SkPaint& paint) {
1200 CHECK_SHOULD_DRAW(draw);
1201
1202 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1203 // this guy will just call our drawPath()
1204 draw.drawPosText((const char*)text, byteLength, pos, constY,
1205 scalarsPerPos, paint);
1206 } else {
1207 SkAutoExtMatrix aem(draw.fExtMatrix);
1208 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001209
1210 GrPaint grPaint;
1211 SkAutoCachedTexture act;
1212 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1213 return;
1214 }
1215
1216 GrTextContext context(fContext, grPaint, aem.extMatrix());
1217 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001218 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
1219 scalarsPerPos, paint);
1220 }
1221}
1222
1223void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
1224 size_t len, const SkPath& path,
1225 const SkMatrix* m, const SkPaint& paint) {
1226 CHECK_SHOULD_DRAW(draw);
1227
1228 SkASSERT(draw.fDevice == this);
1229 draw.drawTextOnPath((const char*)text, len, path, m, paint);
1230}
1231
1232///////////////////////////////////////////////////////////////////////////////
1233
reed@google.comf67e4cf2011-03-15 20:56:58 +00001234bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
1235 if (!paint.isLCDRenderText()) {
1236 // we're cool with the paint as is
1237 return false;
1238 }
1239
1240 if (paint.getShader() ||
1241 paint.getXfermode() || // unless its srcover
1242 paint.getMaskFilter() ||
1243 paint.getRasterizer() ||
1244 paint.getColorFilter() ||
1245 paint.getPathEffect() ||
1246 paint.isFakeBoldText() ||
1247 paint.getStyle() != SkPaint::kFill_Style) {
1248 // turn off lcd
1249 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
1250 flags->fHinting = paint.getHinting();
1251 return true;
1252 }
1253 // we're cool with the paint as is
1254 return false;
1255}
1256
1257///////////////////////////////////////////////////////////////////////////////
1258
reed@google.comac10a2d2010-12-22 21:39:39 +00001259SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001260 const GrSamplerState& sampler,
1261 GrTexture** texture,
1262 bool forDeviceRenderTarget) {
1263 GrTexture* newTexture = NULL;
1264 GrTextureEntry* entry = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +00001265 GrContext* ctx = this->context();
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001266
reed@google.comac10a2d2010-12-22 21:39:39 +00001267 if (forDeviceRenderTarget) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001268 const GrTextureDesc desc = {
1269 kRenderTarget_GrTextureFlagBit,
1270 kNone_GrAALevel,
1271 bitmap.width(),
1272 bitmap.height(),
1273 SkGr::Bitmap2PixelConfig(bitmap)
1274 };
bsalomon@google.coma39f4042011-04-26 13:18:16 +00001275 entry = ctx->lockKeylessTexture(desc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001276 } else {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001277 uint32_t p0, p1;
reed@google.comac10a2d2010-12-22 21:39:39 +00001278 p0 = bitmap.getGenerationID();
1279 p1 = bitmap.pixelRefOffset();
reed@google.comac10a2d2010-12-22 21:39:39 +00001280
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001281 GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
1282 entry = ctx->findAndLockTexture(&key, sampler);
reed@google.comac10a2d2010-12-22 21:39:39 +00001283
reed@google.comac10a2d2010-12-22 21:39:39 +00001284 if (NULL == entry) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001285 entry = sk_gr_create_bitmap_texture(ctx, &key, sampler, bitmap);
1286 if (NULL == entry) {
1287 GrPrintf("---- failed to create texture for cache [%d %d]\n",
1288 bitmap.width(), bitmap.height());
1289 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001290 }
1291 }
1292
1293 if (NULL != entry) {
1294 newTexture = entry->texture();
reed@google.comac10a2d2010-12-22 21:39:39 +00001295 if (texture) {
1296 *texture = newTexture;
1297 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001298 }
1299 return (TexCache*)entry;
1300}
1301
1302void SkGpuDevice::unlockCachedTexture(TexCache* cache) {
1303 this->context()->unlockTexture((GrTextureEntry*)cache);
1304}
1305
reed@google.com7b201d22011-01-11 18:59:23 +00001306///////////////////////////////////////////////////////////////////////////////
1307
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001308SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context,
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001309 GrRenderTarget* rootRenderTarget) {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001310 GrAssert(NULL != context);
1311 GrAssert(NULL != rootRenderTarget);
1312
1313 // check this now rather than passing this value to SkGpuDevice cons.
1314 // we want the rt that is bound *now* in the 3D API, not the one
1315 // at the time of newDevice.
1316 if (SkGpuDevice::Current3DApiRenderTarget() == rootRenderTarget) {
1317 fRootRenderTarget = context->createRenderTargetFrom3DApiState();
1318 } else {
1319 fRootRenderTarget = rootRenderTarget;
1320 rootRenderTarget->ref();
1321 }
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001322
1323 fContext = context;
reed@google.com7b201d22011-01-11 18:59:23 +00001324 context->ref();
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001325
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001326 fRootTexture = NULL;
1327}
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001328
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001329SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context, GrTexture* rootRenderTargetTexture) {
1330 GrAssert(NULL != context);
1331 GrAssert(NULL != rootRenderTargetTexture);
1332 GrAssert(NULL != rootRenderTargetTexture->asRenderTarget());
1333
1334 fRootTexture = rootRenderTargetTexture;
1335 rootRenderTargetTexture->ref();
1336
1337 fRootRenderTarget = rootRenderTargetTexture->asRenderTarget();
1338 fRootRenderTarget->ref();
1339
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001340 fContext = context;
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001341 context->ref();
reed@google.com7b201d22011-01-11 18:59:23 +00001342}
1343
1344SkGpuDeviceFactory::~SkGpuDeviceFactory() {
1345 fContext->unref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001346 fRootRenderTarget->unref();
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001347 GrSafeUnref(fRootTexture);
reed@google.com7b201d22011-01-11 18:59:23 +00001348}
1349
1350SkDevice* SkGpuDeviceFactory::newDevice(SkCanvas*, SkBitmap::Config config,
1351 int width, int height,
1352 bool isOpaque, bool isLayer) {
1353 SkBitmap bm;
1354 bm.setConfig(config, width, height);
1355 bm.setIsOpaque(isOpaque);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001356 return new SkGpuDevice(fContext, bm, isLayer ? NULL : fRootRenderTarget);
reed@google.com7b201d22011-01-11 18:59:23 +00001357}