blob: 1c70513245367d334f3c816e20ce35d6172117ac [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.com398109c2011-04-14 18:40:27 +0000330 fContext->clear(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.com0748f212011-02-01 22:56:16 +0000426 grPaint->fSampler.setFilter(skPaint.isFilterBitmap());
bsalomon@google.com5782d712011-01-21 21:03:59 +0000427 grPaint->fSampler.setWrapX(sk_tile_mode_to_grwrap(tileModes[0]));
428 grPaint->fSampler.setWrapY(sk_tile_mode_to_grwrap(tileModes[1]));
reed@google.comac10a2d2010-12-22 21:39:39 +0000429 if (GrSamplerState::kRadial2_SampleMode == sampleMode) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000430 grPaint->fSampler.setRadial2Params(twoPointParams[0],
431 twoPointParams[1],
432 twoPointParams[2] < 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000433 }
434
bsalomon@google.com5782d712011-01-21 21:03:59 +0000435 GrTexture* texture = act->set(this, bitmap, grPaint->fSampler);
reed@google.comac10a2d2010-12-22 21:39:39 +0000436 if (NULL == texture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000437 SkDebugf("Couldn't convert bitmap to texture.\n");
438 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000439 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000440 grPaint->setTexture(texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000441
442 // since our texture coords will be in local space, we wack the texture
443 // matrix to map them back into 0...1 before we load it
444 SkMatrix localM;
445 if (shader->getLocalMatrix(&localM)) {
446 SkMatrix inverse;
447 if (localM.invert(&inverse)) {
448 matrix.preConcat(inverse);
449 }
450 }
451 if (SkShader::kDefault_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000452 GrScalar sx = GrFixedToScalar(GR_Fixed1 / bitmap.width());
453 GrScalar sy = GrFixedToScalar(GR_Fixed1 / bitmap.height());
reed@google.comac10a2d2010-12-22 21:39:39 +0000454 matrix.postScale(sx, sy);
reed@google.comac10a2d2010-12-22 21:39:39 +0000455 } else if (SkShader::kRadial_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000456 GrScalar s = GrFixedToScalar(GR_Fixed1 / bitmap.width());
reed@google.comac10a2d2010-12-22 21:39:39 +0000457 matrix.postScale(s, s);
458 }
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000459 GrMatrix grMat;
460 SkGr::SkMatrix2GrMatrix(matrix, &grMat);
461 grPaint->fSampler.setMatrix(grMat);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000462
463 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000464}
465
466///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com5782d712011-01-21 21:03:59 +0000467
468class SkPositionSource {
469public:
470 SkPositionSource(const SkPoint* points, int count)
471 : fPoints(points), fCount(count) {}
472
473 int count() const { return fCount; }
474
475 void writeValue(int i, GrPoint* dstPosition) const {
476 SkASSERT(i < fCount);
477 dstPosition->fX = SkScalarToGrScalar(fPoints[i].fX);
478 dstPosition->fY = SkScalarToGrScalar(fPoints[i].fY);
479 }
480private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000481 const SkPoint* fPoints;
bsalomon@google.com19628322011-02-03 21:30:17 +0000482 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000483};
484
485class SkTexCoordSource {
486public:
487 SkTexCoordSource(const SkPoint* coords)
488 : fCoords(coords) {}
489
490 void writeValue(int i, GrPoint* dstCoord) const {
491 dstCoord->fX = SkScalarToGrScalar(fCoords[i].fX);
492 dstCoord->fY = SkScalarToGrScalar(fCoords[i].fY);
493 }
494private:
495 const SkPoint* fCoords;
496};
497
498class SkColorSource {
499public:
500 SkColorSource(const SkColor* colors) : fColors(colors) {}
501
502 void writeValue(int i, GrColor* dstColor) const {
503 *dstColor = SkGr::SkColor2GrColor(fColors[i]);
504 }
505private:
506 const SkColor* fColors;
507};
508
509class SkIndexSource {
510public:
511 SkIndexSource(const uint16_t* indices, int count)
512 : fIndices(indices), fCount(count) {
513 }
514
515 int count() const { return fCount; }
516
517 void writeValue(int i, uint16_t* dstIndex) const {
518 *dstIndex = fIndices[i];
519 }
520
521private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000522 const uint16_t* fIndices;
bsalomon@google.com19628322011-02-03 21:30:17 +0000523 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000524};
525
526///////////////////////////////////////////////////////////////////////////////
527
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000528#if 0 // not currently being used so don't compile,
529
bsalomon@google.com5782d712011-01-21 21:03:59 +0000530// can be used for positions or texture coordinates
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000531
bsalomon@google.com5782d712011-01-21 21:03:59 +0000532class SkRectFanSource {
533public:
534 SkRectFanSource(const SkRect& rect) : fRect(rect) {}
535
536 int count() const { return 4; }
537
538 void writeValue(int i, GrPoint* dstPoint) const {
539 SkASSERT(i < 4);
540 dstPoint->fX = SkScalarToGrScalar((i % 3) ? fRect.fRight :
541 fRect.fLeft);
542 dstPoint->fY = SkScalarToGrScalar((i < 2) ? fRect.fTop :
543 fRect.fBottom);
544 }
545private:
546 const SkRect& fRect;
547};
548
549class SkIRectFanSource {
550public:
551 SkIRectFanSource(const SkIRect& rect) : fRect(rect) {}
552
553 int count() const { return 4; }
554
555 void writeValue(int i, GrPoint* dstPoint) const {
556 SkASSERT(i < 4);
557 dstPoint->fX = (i % 3) ? GrIntToScalar(fRect.fRight) :
558 GrIntToScalar(fRect.fLeft);
559 dstPoint->fY = (i < 2) ? GrIntToScalar(fRect.fTop) :
560 GrIntToScalar(fRect.fBottom);
561 }
562private:
563 const SkIRect& fRect;
564};
565
566class SkMatRectFanSource {
567public:
568 SkMatRectFanSource(const SkRect& rect, const SkMatrix& matrix)
569 : fRect(rect), fMatrix(matrix) {}
570
571 int count() const { return 4; }
572
573 void writeValue(int i, GrPoint* dstPoint) const {
574 SkASSERT(i < 4);
575
576#if SK_SCALAR_IS_GR_SCALAR
577 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
578 (i < 2) ? fRect.fTop : fRect.fBottom,
579 (SkPoint*)dstPoint);
580#else
581 SkPoint dst;
582 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
583 (i < 2) ? fRect.fTop : fRect.fBottom,
584 &dst);
585 dstPoint->fX = SkScalarToGrScalar(dst.fX);
586 dstPoint->fY = SkScalarToGrScalar(dst.fY);
587#endif
588 }
589private:
590 const SkRect& fRect;
591 const SkMatrix& fMatrix;
592};
593
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000594#endif
595
reed@google.comac10a2d2010-12-22 21:39:39 +0000596///////////////////////////////////////////////////////////////////////////////
597
bsalomon@google.com398109c2011-04-14 18:40:27 +0000598void SkGpuDevice::clear(SkColor color) {
599 fContext->clear(color);
600}
601
reed@google.comac10a2d2010-12-22 21:39:39 +0000602void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
603 CHECK_SHOULD_DRAW(draw);
604
bsalomon@google.com5782d712011-01-21 21:03:59 +0000605 GrPaint grPaint;
606 SkAutoCachedTexture act;
607 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000608 return;
609 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000610
611 fContext->drawPaint(grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000612}
613
614// must be in SkCanvas::PointMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +0000615static const GrPrimitiveType gPointMode2PrimtiveType[] = {
616 kPoints_PrimitiveType,
617 kLines_PrimitiveType,
618 kLineStrip_PrimitiveType
reed@google.comac10a2d2010-12-22 21:39:39 +0000619};
620
621void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000622 size_t count, const SkPoint pts[], const SkPaint& paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000623 CHECK_SHOULD_DRAW(draw);
624
625 SkScalar width = paint.getStrokeWidth();
626 if (width < 0) {
627 return;
628 }
629
630 // we only handle hairlines here, else we let the SkDraw call our drawPath()
631 if (width > 0) {
632 draw.drawPoints(mode, count, pts, paint, true);
633 return;
634 }
635
bsalomon@google.com5782d712011-01-21 21:03:59 +0000636 GrPaint grPaint;
637 SkAutoCachedTexture act;
638 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000639 return;
640 }
641
reed@google.comac10a2d2010-12-22 21:39:39 +0000642#if SK_SCALAR_IS_GR_SCALAR
bsalomon@google.com5782d712011-01-21 21:03:59 +0000643 fContext->drawVertices(grPaint,
644 gPointMode2PrimtiveType[mode],
645 count,
646 (GrPoint*)pts,
647 NULL,
648 NULL,
649 NULL,
650 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000651#else
bsalomon@google.com5782d712011-01-21 21:03:59 +0000652 fContext->drawCustomVertices(grPaint,
653 gPointMode2PrimtiveType[mode],
654 SkPositionSource(pts, count));
reed@google.comac10a2d2010-12-22 21:39:39 +0000655#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000656}
657
reed@google.comc9aa5872011-04-05 21:05:37 +0000658///////////////////////////////////////////////////////////////////////////////
659
reed@google.comac10a2d2010-12-22 21:39:39 +0000660void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
661 const SkPaint& paint) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000662 CHECK_SHOULD_DRAW(draw);
663
664 bool doStroke = paint.getStyle() == SkPaint::kStroke_Style;
665 SkScalar width = paint.getStrokeWidth();
666
667 /*
668 We have special code for hairline strokes, miter-strokes, and fills.
669 Anything else we just call our path code.
670 */
671 bool usePath = doStroke && width > 0 &&
672 paint.getStrokeJoin() != SkPaint::kMiter_Join;
673 // another reason we might need to call drawPath...
674 if (paint.getMaskFilter()) {
675 usePath = true;
676 }
677
678 if (usePath) {
679 SkPath path;
680 path.addRect(rect);
681 this->drawPath(draw, path, paint, NULL, true);
682 return;
683 }
684
685 GrPaint grPaint;
686 SkAutoCachedTexture act;
687 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
688 return;
689 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000690 fContext->drawRect(grPaint, Sk2Gr(rect), doStroke ? width : -1);
reed@google.comac10a2d2010-12-22 21:39:39 +0000691}
692
reed@google.com69302852011-02-16 18:08:07 +0000693#include "SkMaskFilter.h"
694#include "SkBounder.h"
695
reed@google.com69302852011-02-16 18:08:07 +0000696static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
697 SkMaskFilter* filter, const SkMatrix& matrix,
698 const SkRegion& clip, SkBounder* bounder,
699 GrPaint* grp) {
700 SkMask srcM, dstM;
701
702 if (!SkDraw::DrawToMask(path, &clip.getBounds(), filter, &matrix, &srcM,
703 SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
704 return false;
705 }
706
707 SkAutoMaskImage autoSrc(&srcM, false);
708
709 if (!filter->filterMask(&dstM, srcM, matrix, NULL)) {
710 return false;
711 }
712 // this will free-up dstM when we're done (allocated in filterMask())
713 SkAutoMaskImage autoDst(&dstM, false);
714
715 if (clip.quickReject(dstM.fBounds)) {
716 return false;
717 }
718 if (bounder && !bounder->doIRect(dstM.fBounds)) {
719 return false;
720 }
721
722 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
723 // the current clip (and identity matrix) and grpaint settings
724
reed@google.com0c219b62011-02-16 21:31:18 +0000725 GrAutoMatrix avm(context, GrMatrix::I());
reed@google.com69302852011-02-16 18:08:07 +0000726
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000727 const GrTextureDesc desc = {
728 kNone_GrTextureFlags,
729 kNone_GrAALevel,
reed@google.com69302852011-02-16 18:08:07 +0000730 dstM.fBounds.width(),
731 dstM.fBounds.height(),
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000732 kAlpha_8_GrPixelConfig
reed@google.com69302852011-02-16 18:08:07 +0000733 };
734
735 GrTexture* texture = context->createUncachedTexture(desc, dstM.fImage,
736 dstM.fRowBytes);
737 if (NULL == texture) {
738 return false;
739 }
740
reed@google.com0c219b62011-02-16 21:31:18 +0000741 grp->setTexture(texture);
742 texture->unref();
743 grp->fSampler.setClampNoFilter();
reed@google.com69302852011-02-16 18:08:07 +0000744
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000745 GrRect d;
746 d.setLTRB(GrIntToScalar(dstM.fBounds.fLeft),
reed@google.com0c219b62011-02-16 21:31:18 +0000747 GrIntToScalar(dstM.fBounds.fTop),
748 GrIntToScalar(dstM.fBounds.fRight),
749 GrIntToScalar(dstM.fBounds.fBottom));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000750 GrRect s;
751 s.setLTRB(0, 0, GR_Scalar1, GR_Scalar1);
752 context->drawRectToRect(*grp, d, s);
reed@google.com69302852011-02-16 18:08:07 +0000753 return true;
754}
reed@google.com69302852011-02-16 18:08:07 +0000755
reed@google.com0c219b62011-02-16 21:31:18 +0000756void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
reed@google.comac10a2d2010-12-22 21:39:39 +0000757 const SkPaint& paint, const SkMatrix* prePathMatrix,
758 bool pathIsMutable) {
759 CHECK_SHOULD_DRAW(draw);
760
bsalomon@google.com5782d712011-01-21 21:03:59 +0000761 GrPaint grPaint;
762 SkAutoCachedTexture act;
763 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000764 return;
765 }
766
reed@google.com0c219b62011-02-16 21:31:18 +0000767 // BEGIN lift from SkDraw::drawPath()
768
769 SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
770 bool doFill = true;
771 SkPath tmpPath;
reed@google.comac10a2d2010-12-22 21:39:39 +0000772
773 if (prePathMatrix) {
reed@google.come3445642011-02-16 23:20:39 +0000774 SkPath* result = pathPtr;
reed@google.com0c219b62011-02-16 21:31:18 +0000775
reed@google.come3445642011-02-16 23:20:39 +0000776 if (!pathIsMutable) {
777 result = &tmpPath;
778 pathIsMutable = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000779 }
reed@google.come3445642011-02-16 23:20:39 +0000780 // should I push prePathMatrix on our MV stack temporarily, instead
781 // of applying it here? See SkDraw.cpp
782 pathPtr->transform(*prePathMatrix, result);
783 pathPtr = result;
reed@google.comac10a2d2010-12-22 21:39:39 +0000784 }
reed@google.com0c219b62011-02-16 21:31:18 +0000785 // at this point we're done with prePathMatrix
786 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
reed@google.comac10a2d2010-12-22 21:39:39 +0000787
bsalomon@google.com04de7822011-03-25 18:04:43 +0000788 // This "if" is not part of the SkDraw::drawPath() lift.
789 // When we get a 1.0 wide stroke we hairline stroke it instead of creating
790 // a new stroked-path. This is motivated by canvas2D sites that draw
791 // lines as 1.0 wide stroked paths. We can consider doing an alpha-modulated-
792 // hairline for width < 1.0 when AA is enabled.
793 static const int gMatrixMask = ~(SkMatrix::kIdentity_Mask |
794 SkMatrix::kTranslate_Mask);
795 if (!paint.getPathEffect() &&
796 SkPaint::kStroke_Style == paint.getStyle() &&
797 !(draw.fMatrix->getType() & gMatrixMask) &&
798 SK_Scalar1 == paint.getStrokeWidth()) {
799 doFill = false;
800 }
801
802 if (doFill && (paint.getPathEffect() ||
803 paint.getStyle() != SkPaint::kFill_Style)) {
reed@google.com0c219b62011-02-16 21:31:18 +0000804 doFill = paint.getFillPath(*pathPtr, &tmpPath);
805 pathPtr = &tmpPath;
806 }
807
808 // END lift from SkDraw::drawPath()
809
reed@google.com69302852011-02-16 18:08:07 +0000810 if (paint.getMaskFilter()) {
reed@google.com0c219b62011-02-16 21:31:18 +0000811 // avoid possibly allocating a new path in transform if we can
812 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
813
814 // transform the path into device space
reed@google.come3445642011-02-16 23:20:39 +0000815 pathPtr->transform(*draw.fMatrix, devPathPtr);
reed@google.com0c219b62011-02-16 21:31:18 +0000816
817 drawWithMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
reed@google.com69302852011-02-16 18:08:07 +0000818 *draw.fMatrix, *draw.fClip, draw.fBounder, &grPaint);
819 return;
820 }
reed@google.com69302852011-02-16 18:08:07 +0000821
bsalomon@google.comffca4002011-02-22 20:34:01 +0000822 GrPathFill fill = kHairLine_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000823
reed@google.com0c219b62011-02-16 21:31:18 +0000824 if (doFill) {
825 switch (pathPtr->getFillType()) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000826 case SkPath::kWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000827 fill = kWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000828 break;
829 case SkPath::kEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000830 fill = kEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000831 break;
832 case SkPath::kInverseWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000833 fill = kInverseWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000834 break;
835 case SkPath::kInverseEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000836 fill = kInverseEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000837 break;
838 default:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000839 SkDebugf("Unsupported path fill type\n");
reed@google.comac10a2d2010-12-22 21:39:39 +0000840 return;
841 }
842 }
843
reed@google.com0c219b62011-02-16 21:31:18 +0000844 SkGrPathIter iter(*pathPtr);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000845 fContext->drawPath(grPaint, &iter, fill);
reed@google.comac10a2d2010-12-22 21:39:39 +0000846}
847
reed@google.comac10a2d2010-12-22 21:39:39 +0000848void SkGpuDevice::drawBitmap(const SkDraw& draw,
849 const SkBitmap& bitmap,
850 const SkIRect* srcRectPtr,
851 const SkMatrix& m,
852 const SkPaint& paint) {
853 CHECK_SHOULD_DRAW(draw);
854
855 SkIRect srcRect;
856 if (NULL == srcRectPtr) {
857 srcRect.set(0, 0, bitmap.width(), bitmap.height());
858 } else {
859 srcRect = *srcRectPtr;
860 }
861
bsalomon@google.com5782d712011-01-21 21:03:59 +0000862 GrPaint grPaint;
863 if (!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
864 return;
865 }
866 grPaint.fSampler.setFilter(paint.isFilterBitmap());
867
reed@google.com02a7e6c2011-01-28 21:21:49 +0000868 const int maxTextureDim = fContext->getMaxTextureDimension();
869 if (bitmap.getTexture() || (bitmap.width() <= maxTextureDim &&
870 bitmap.height() <= maxTextureDim)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000871 // take the fast case
bsalomon@google.com5782d712011-01-21 21:03:59 +0000872 this->internalDrawBitmap(draw, bitmap, srcRect, m, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000873 return;
874 }
875
876 // undo the translate done by SkCanvas
877 int DX = SkMax32(0, srcRect.fLeft);
878 int DY = SkMax32(0, srcRect.fTop);
879 // compute clip bounds in local coordinates
880 SkIRect clipRect;
881 {
882 SkRect r;
883 r.set(draw.fClip->getBounds());
884 SkMatrix matrix, inverse;
885 matrix.setConcat(*draw.fMatrix, m);
886 if (!matrix.invert(&inverse)) {
887 return;
888 }
889 inverse.mapRect(&r);
890 r.roundOut(&clipRect);
891 // apply the canvas' translate to our local clip
892 clipRect.offset(DX, DY);
893 }
894
reed@google.com02a7e6c2011-01-28 21:21:49 +0000895 int nx = bitmap.width() / maxTextureDim;
896 int ny = bitmap.height() / maxTextureDim;
reed@google.comac10a2d2010-12-22 21:39:39 +0000897 for (int x = 0; x <= nx; x++) {
898 for (int y = 0; y <= ny; y++) {
899 SkIRect tileR;
reed@google.com02a7e6c2011-01-28 21:21:49 +0000900 tileR.set(x * maxTextureDim, y * maxTextureDim,
901 (x + 1) * maxTextureDim, (y + 1) * maxTextureDim);
reed@google.comac10a2d2010-12-22 21:39:39 +0000902 if (!SkIRect::Intersects(tileR, clipRect)) {
903 continue;
904 }
905
906 SkIRect srcR = tileR;
907 if (!srcR.intersect(srcRect)) {
908 continue;
909 }
910
911 SkBitmap tmpB;
912 if (bitmap.extractSubset(&tmpB, tileR)) {
913 // now offset it to make it "local" to our tmp bitmap
914 srcR.offset(-tileR.fLeft, -tileR.fTop);
915
916 SkMatrix tmpM(m);
917 {
918 int dx = tileR.fLeft - DX + SkMax32(0, srcR.fLeft);
919 int dy = tileR.fTop - DY + SkMax32(0, srcR.fTop);
920 tmpM.preTranslate(SkIntToScalar(dx), SkIntToScalar(dy));
921 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000922 this->internalDrawBitmap(draw, tmpB, srcR, tmpM, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000923 }
924 }
925 }
926}
927
928/*
929 * This is called by drawBitmap(), which has to handle images that may be too
930 * large to be represented by a single texture.
931 *
bsalomon@google.com5782d712011-01-21 21:03:59 +0000932 * internalDrawBitmap assumes that the specified bitmap will fit in a texture
933 * and that non-texture portion of the GrPaint has already been setup.
reed@google.comac10a2d2010-12-22 21:39:39 +0000934 */
935void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
936 const SkBitmap& bitmap,
937 const SkIRect& srcRect,
938 const SkMatrix& m,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000939 GrPaint* grPaint) {
reed@google.com02a7e6c2011-01-28 21:21:49 +0000940 SkASSERT(bitmap.width() <= fContext->getMaxTextureDimension() &&
941 bitmap.height() <= fContext->getMaxTextureDimension());
reed@google.comac10a2d2010-12-22 21:39:39 +0000942
943 SkAutoLockPixels alp(bitmap);
944 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
945 return;
946 }
947
bsalomon@google.com5782d712011-01-21 21:03:59 +0000948 grPaint->fSampler.setWrapX(GrSamplerState::kClamp_WrapMode);
949 grPaint->fSampler.setWrapY(GrSamplerState::kClamp_WrapMode);
950 grPaint->fSampler.setSampleMode(GrSamplerState::kNormal_SampleMode);
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000951 grPaint->fSampler.setMatrix(GrMatrix::I());
reed@google.comac10a2d2010-12-22 21:39:39 +0000952
953 GrTexture* texture;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000954 SkAutoCachedTexture act(this, bitmap, grPaint->fSampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000955 if (NULL == texture) {
956 return;
957 }
958
bsalomon@google.com5782d712011-01-21 21:03:59 +0000959 grPaint->setTexture(texture);
reed@google.com46799cd2011-02-22 20:56:26 +0000960
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000961 GrRect dstRect(0, 0, GrIntToScalar(srcRect.width()), GrIntToScalar(srcRect.height()));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000962 GrRect paintRect;
963 paintRect.setLTRB(GrFixedToScalar((srcRect.fLeft << 16) / bitmap.width()),
964 GrFixedToScalar((srcRect.fTop << 16) / bitmap.height()),
965 GrFixedToScalar((srcRect.fRight << 16) / bitmap.width()),
966 GrFixedToScalar((srcRect.fBottom << 16) / bitmap.height()));
reed@google.comac10a2d2010-12-22 21:39:39 +0000967
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000968 GrMatrix grMat;
969 SkGr::SkMatrix2GrMatrix(m, &grMat);
reed@google.comac10a2d2010-12-22 21:39:39 +0000970
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000971 fContext->drawRectToRect(*grPaint, dstRect, paintRect, &grMat);
reed@google.comac10a2d2010-12-22 21:39:39 +0000972}
973
974void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
975 int left, int top, const SkPaint& paint) {
976 CHECK_SHOULD_DRAW(draw);
977
978 SkAutoLockPixels alp(bitmap);
979 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
980 return;
981 }
982
bsalomon@google.com5782d712011-01-21 21:03:59 +0000983 GrPaint grPaint;
984 if(!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
985 return;
986 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000987
bsalomon@google.com5782d712011-01-21 21:03:59 +0000988 GrAutoMatrix avm(fContext, GrMatrix::I());
989
990 GrTexture* texture;
991 grPaint.fSampler.setClampNoFilter();
992 SkAutoCachedTexture act(this, bitmap, grPaint.fSampler, &texture);
993
bsalomon@google.com5782d712011-01-21 21:03:59 +0000994 grPaint.setTexture(texture);
995
bsalomon@google.com5782d712011-01-21 21:03:59 +0000996 fContext->drawRectToRect(grPaint,
997 GrRect(GrIntToScalar(left), GrIntToScalar(top),
998 GrIntToScalar(left + bitmap.width()),
999 GrIntToScalar(top + bitmap.height())),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001000 GrRect(0, 0, GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001001}
1002
1003void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
1004 int x, int y, const SkPaint& paint) {
1005 CHECK_SHOULD_DRAW(draw);
1006
bsalomon@google.com5782d712011-01-21 21:03:59 +00001007 GrPaint grPaint;
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001008 if (!((SkGpuDevice*)dev)->bindDeviceAsTexture(&grPaint) ||
bsalomon@google.com5782d712011-01-21 21:03:59 +00001009 !this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
1010 return;
reed@google.comac10a2d2010-12-22 21:39:39 +00001011 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001012
1013 SkASSERT(NULL != grPaint.getTexture());
1014
1015 const SkBitmap& bm = dev->accessBitmap(false);
1016 int w = bm.width();
1017 int h = bm.height();
1018
1019 GrAutoMatrix avm(fContext, GrMatrix::I());
1020
1021 grPaint.fSampler.setClampNoFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +00001022
1023 fContext->drawRectToRect(grPaint,
reed@google.com1a2e8d22011-01-21 22:08:29 +00001024 GrRect(GrIntToScalar(x),
1025 GrIntToScalar(y),
1026 GrIntToScalar(x + w),
bsalomon@google.com5782d712011-01-21 21:03:59 +00001027 GrIntToScalar(y + h)),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001028 GrRect(0, 0, GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001029}
1030
1031///////////////////////////////////////////////////////////////////////////////
1032
1033// must be in SkCanvas::VertexMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +00001034static const GrPrimitiveType gVertexMode2PrimitiveType[] = {
1035 kTriangles_PrimitiveType,
1036 kTriangleStrip_PrimitiveType,
1037 kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +00001038};
1039
1040void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
1041 int vertexCount, const SkPoint vertices[],
1042 const SkPoint texs[], const SkColor colors[],
1043 SkXfermode* xmode,
1044 const uint16_t indices[], int indexCount,
1045 const SkPaint& paint) {
1046 CHECK_SHOULD_DRAW(draw);
1047
bsalomon@google.com5782d712011-01-21 21:03:59 +00001048 GrPaint grPaint;
1049 SkAutoCachedTexture act;
1050 // we ignore the shader if texs is null.
1051 if (NULL == texs) {
1052 if (!this->skPaint2GrPaintNoShader(paint, false, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001053 return;
1054 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001055 } else {
reed@google.com1a2e8d22011-01-21 22:08:29 +00001056 if (!this->skPaint2GrPaintShader(paint, &act,
1057 *draw.fMatrix,
bsalomon@google.com5782d712011-01-21 21:03:59 +00001058 &grPaint)) {
1059 return;
1060 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001061 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001062
1063 if (NULL != xmode && NULL != texs && NULL != colors) {
1064 SkXfermode::Mode mode;
1065 if (!SkXfermode::IsMode(xmode, &mode) ||
1066 SkXfermode::kMultiply_Mode != mode) {
1067 SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
1068#if 0
1069 return
1070#endif
1071 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001072 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001073
1074#if SK_SCALAR_IS_GR_SCALAR
1075 // even if GrColor and SkColor byte offsets match we need
1076 // to perform pre-multiply.
1077 if (NULL == colors) {
1078 fContext->drawVertices(grPaint,
1079 gVertexMode2PrimitiveType[vmode],
1080 vertexCount,
1081 (GrPoint*) vertices,
1082 (GrPoint*) texs,
1083 NULL,
1084 indices,
1085 indexCount);
1086 } else
1087#endif
1088 {
1089 SkTexCoordSource texSrc(texs);
1090 SkColorSource colSrc(colors);
1091 SkIndexSource idxSrc(indices, indexCount);
1092
1093 fContext->drawCustomVertices(grPaint,
1094 gVertexMode2PrimitiveType[vmode],
1095 SkPositionSource(vertices, vertexCount),
1096 (NULL == texs) ? NULL : &texSrc,
1097 (NULL == colors) ? NULL : &colSrc,
1098 (NULL == indices) ? NULL : &idxSrc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001099 }
1100}
1101
1102///////////////////////////////////////////////////////////////////////////////
1103
1104static void GlyphCacheAuxProc(void* data) {
1105 delete (GrFontScaler*)data;
1106}
1107
1108static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) {
1109 void* auxData;
1110 GrFontScaler* scaler = NULL;
1111 if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
1112 scaler = (GrFontScaler*)auxData;
1113 }
1114 if (NULL == scaler) {
1115 scaler = new SkGrFontScaler(cache);
1116 cache->setAuxProc(GlyphCacheAuxProc, scaler);
1117 }
1118 return scaler;
1119}
1120
1121static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
1122 SkFixed fx, SkFixed fy,
1123 const SkGlyph& glyph) {
1124 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1125
1126 GrSkDrawProcs* procs = (GrSkDrawProcs*)state.fDraw->fProcs;
1127
1128 if (NULL == procs->fFontScaler) {
1129 procs->fFontScaler = get_gr_font_scaler(state.fCache);
1130 }
reed@google.com39ce0ac2011-04-08 15:42:19 +00001131
1132 /*
1133 * Skia calls us with fx,fy already biased by 1/2. It does this to speed
1134 * up rounding these, so that all of its procs (like us) can just call
1135 * SkFixedFloor and get the "rounded" value.
1136 *
1137 * We take advantage of that for fx, where we pass a rounded value, but
1138 * we want the fractional fy, so we have to unbias it first.
1139 */
reed@google.comac10a2d2010-12-22 21:39:39 +00001140 procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0),
reed@google.com39ce0ac2011-04-08 15:42:19 +00001141 SkIntToFixed(SkFixedFloor(fx)),
1142 fy - SK_FixedHalf,
reed@google.comac10a2d2010-12-22 21:39:39 +00001143 procs->fFontScaler);
1144}
1145
bsalomon@google.com5782d712011-01-21 21:03:59 +00001146SkDrawProcs* SkGpuDevice::initDrawForText(GrTextContext* context) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001147
1148 // deferred allocation
1149 if (NULL == fDrawProcs) {
1150 fDrawProcs = new GrSkDrawProcs;
1151 fDrawProcs->fD1GProc = SkGPU_Draw1Glyph;
1152 fDrawProcs->fContext = fContext;
1153 }
1154
1155 // init our (and GL's) state
1156 fDrawProcs->fTextContext = context;
1157 fDrawProcs->fFontScaler = NULL;
1158 return fDrawProcs;
1159}
1160
1161void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
1162 size_t byteLength, SkScalar x, SkScalar y,
1163 const SkPaint& paint) {
1164 CHECK_SHOULD_DRAW(draw);
1165
1166 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1167 // this guy will just call our drawPath()
1168 draw.drawText((const char*)text, byteLength, x, y, paint);
1169 } else {
1170 SkAutoExtMatrix aem(draw.fExtMatrix);
1171 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001172
1173 GrPaint grPaint;
1174 SkAutoCachedTexture act;
1175
1176 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1177 return;
1178 }
1179 GrTextContext context(fContext, grPaint, aem.extMatrix());
1180 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001181 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
1182 }
1183}
1184
1185void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
1186 size_t byteLength, const SkScalar pos[],
1187 SkScalar constY, int scalarsPerPos,
1188 const SkPaint& paint) {
1189 CHECK_SHOULD_DRAW(draw);
1190
1191 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1192 // this guy will just call our drawPath()
1193 draw.drawPosText((const char*)text, byteLength, pos, constY,
1194 scalarsPerPos, paint);
1195 } else {
1196 SkAutoExtMatrix aem(draw.fExtMatrix);
1197 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001198
1199 GrPaint grPaint;
1200 SkAutoCachedTexture act;
1201 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1202 return;
1203 }
1204
1205 GrTextContext context(fContext, grPaint, aem.extMatrix());
1206 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001207 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
1208 scalarsPerPos, paint);
1209 }
1210}
1211
1212void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
1213 size_t len, const SkPath& path,
1214 const SkMatrix* m, const SkPaint& paint) {
1215 CHECK_SHOULD_DRAW(draw);
1216
1217 SkASSERT(draw.fDevice == this);
1218 draw.drawTextOnPath((const char*)text, len, path, m, paint);
1219}
1220
1221///////////////////////////////////////////////////////////////////////////////
1222
reed@google.comf67e4cf2011-03-15 20:56:58 +00001223bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
1224 if (!paint.isLCDRenderText()) {
1225 // we're cool with the paint as is
1226 return false;
1227 }
1228
1229 if (paint.getShader() ||
1230 paint.getXfermode() || // unless its srcover
1231 paint.getMaskFilter() ||
1232 paint.getRasterizer() ||
1233 paint.getColorFilter() ||
1234 paint.getPathEffect() ||
1235 paint.isFakeBoldText() ||
1236 paint.getStyle() != SkPaint::kFill_Style) {
1237 // turn off lcd
1238 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
1239 flags->fHinting = paint.getHinting();
1240 return true;
1241 }
1242 // we're cool with the paint as is
1243 return false;
1244}
1245
1246///////////////////////////////////////////////////////////////////////////////
1247
reed@google.comac10a2d2010-12-22 21:39:39 +00001248SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001249 const GrSamplerState& sampler,
1250 GrTexture** texture,
1251 bool forDeviceRenderTarget) {
1252 GrTexture* newTexture = NULL;
1253 GrTextureEntry* entry = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +00001254 GrContext* ctx = this->context();
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001255
reed@google.comac10a2d2010-12-22 21:39:39 +00001256 if (forDeviceRenderTarget) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001257 const GrTextureDesc desc = {
1258 kRenderTarget_GrTextureFlagBit,
1259 kNone_GrAALevel,
1260 bitmap.width(),
1261 bitmap.height(),
1262 SkGr::Bitmap2PixelConfig(bitmap)
1263 };
1264 entry = ctx->lockKeylessTexture(desc, sampler);
reed@google.comac10a2d2010-12-22 21:39:39 +00001265 } else {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001266 uint32_t p0, p1;
reed@google.comac10a2d2010-12-22 21:39:39 +00001267 p0 = bitmap.getGenerationID();
1268 p1 = bitmap.pixelRefOffset();
reed@google.comac10a2d2010-12-22 21:39:39 +00001269
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001270 GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
1271 entry = ctx->findAndLockTexture(&key, sampler);
reed@google.comac10a2d2010-12-22 21:39:39 +00001272
reed@google.comac10a2d2010-12-22 21:39:39 +00001273 if (NULL == entry) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001274 entry = sk_gr_create_bitmap_texture(ctx, &key, sampler, bitmap);
1275 if (NULL == entry) {
1276 GrPrintf("---- failed to create texture for cache [%d %d]\n",
1277 bitmap.width(), bitmap.height());
1278 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001279 }
1280 }
1281
1282 if (NULL != entry) {
1283 newTexture = entry->texture();
reed@google.comac10a2d2010-12-22 21:39:39 +00001284 if (texture) {
1285 *texture = newTexture;
1286 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001287 }
1288 return (TexCache*)entry;
1289}
1290
1291void SkGpuDevice::unlockCachedTexture(TexCache* cache) {
1292 this->context()->unlockTexture((GrTextureEntry*)cache);
1293}
1294
reed@google.com7b201d22011-01-11 18:59:23 +00001295///////////////////////////////////////////////////////////////////////////////
1296
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001297SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context,
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001298 GrRenderTarget* rootRenderTarget) {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001299 GrAssert(NULL != context);
1300 GrAssert(NULL != rootRenderTarget);
1301
1302 // check this now rather than passing this value to SkGpuDevice cons.
1303 // we want the rt that is bound *now* in the 3D API, not the one
1304 // at the time of newDevice.
1305 if (SkGpuDevice::Current3DApiRenderTarget() == rootRenderTarget) {
1306 fRootRenderTarget = context->createRenderTargetFrom3DApiState();
1307 } else {
1308 fRootRenderTarget = rootRenderTarget;
1309 rootRenderTarget->ref();
1310 }
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001311
1312 fContext = context;
reed@google.com7b201d22011-01-11 18:59:23 +00001313 context->ref();
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001314
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001315 fRootTexture = NULL;
1316}
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001317
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001318SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context, GrTexture* rootRenderTargetTexture) {
1319 GrAssert(NULL != context);
1320 GrAssert(NULL != rootRenderTargetTexture);
1321 GrAssert(NULL != rootRenderTargetTexture->asRenderTarget());
1322
1323 fRootTexture = rootRenderTargetTexture;
1324 rootRenderTargetTexture->ref();
1325
1326 fRootRenderTarget = rootRenderTargetTexture->asRenderTarget();
1327 fRootRenderTarget->ref();
1328
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001329 fContext = context;
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001330 context->ref();
reed@google.com7b201d22011-01-11 18:59:23 +00001331}
1332
1333SkGpuDeviceFactory::~SkGpuDeviceFactory() {
1334 fContext->unref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001335 fRootRenderTarget->unref();
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001336 GrSafeUnref(fRootTexture);
reed@google.com7b201d22011-01-11 18:59:23 +00001337}
1338
1339SkDevice* SkGpuDeviceFactory::newDevice(SkCanvas*, SkBitmap::Config config,
1340 int width, int height,
1341 bool isOpaque, bool isLayer) {
1342 SkBitmap bm;
1343 bm.setConfig(config, width, height);
1344 bm.setIsOpaque(isOpaque);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001345 return new SkGpuDevice(fContext, bm, isLayer ? NULL : fRootRenderTarget);
reed@google.com7b201d22011-01-11 18:59:23 +00001346}