blob: 1c797c3b95a50717f7524a9d92cfc76bb63a2d3d [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());
195 // IMPORTANT: reattach the rendertarget/tex back to the cache.
196 fContext->reattachAndUnlockCachedTexture((GrTextureEntry*)fCache);
197 } else if (NULL != fTexture) {
198 GrAssert(!CACHE_LAYER_TEXTURES);
199 GrAssert(fRenderTarget == fTexture->asRenderTarget());
200 fTexture->unref();
201 } else if (NULL != fRenderTarget) {
202 fRenderTarget->unref();
203 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000204 fContext->unref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000205}
206
reed@google.comac10a2d2010-12-22 21:39:39 +0000207intptr_t SkGpuDevice::getLayerTextureHandle() const {
208 if (fTexture) {
209 return fTexture->getTextureHandle();
210 } else {
211 return 0;
212 }
213}
214///////////////////////////////////////////////////////////////////////////////
215
216void SkGpuDevice::makeRenderTargetCurrent() {
217 fContext->setRenderTarget(fRenderTarget);
218 fContext->flush(true);
219 fNeedPrepareRenderTarget = true;
220}
221
222///////////////////////////////////////////////////////////////////////////////
223
224bool SkGpuDevice::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
225 SkIRect bounds;
226 bounds.set(0, 0, this->width(), this->height());
227 if (!bounds.intersect(srcRect)) {
228 return false;
229 }
230
231 const int w = bounds.width();
232 const int h = bounds.height();
233 SkBitmap tmp;
234 // note we explicitly specify our rowBytes to be snug (no gap between rows)
235 tmp.setConfig(SkBitmap::kARGB_8888_Config, w, h, w * 4);
236 if (!tmp.allocPixels()) {
237 return false;
238 }
239
Scroggo813c33c2011-04-07 20:56:21 +0000240 tmp.lockPixels();
reed@google.comac10a2d2010-12-22 21:39:39 +0000241
Scroggoeb176032011-04-07 21:11:49 +0000242 bool read = fContext->readRenderTargetPixels(fRenderTarget,
243 bounds.fLeft, bounds.fTop,
244 bounds.width(), bounds.height(),
245 kRGBA_8888_GrPixelConfig,
246 tmp.getPixels());
Scroggo813c33c2011-04-07 20:56:21 +0000247 tmp.unlockPixels();
248 if (!read) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000249 return false;
250 }
251
252 tmp.swap(*bitmap);
253 return true;
254}
255
256void SkGpuDevice::writePixels(const SkBitmap& bitmap, int x, int y) {
257 SkAutoLockPixels alp(bitmap);
258 if (!bitmap.readyToDraw()) {
259 return;
260 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000261 GrPixelConfig config = SkGr::BitmapConfig2PixelConfig(bitmap.config(),
262 bitmap.isOpaque());
reed@google.comac10a2d2010-12-22 21:39:39 +0000263 fContext->setRenderTarget(fRenderTarget);
264 // we aren't setting the clip or matrix, so mark as dirty
265 // we don't need to set them for this call and don't have them anyway
266 fNeedPrepareRenderTarget = true;
267
268 fContext->writePixels(x, y, bitmap.width(), bitmap.height(),
269 config, bitmap.getPixels(), bitmap.rowBytes());
270}
271
272///////////////////////////////////////////////////////////////////////////////
273
274static void convert_matrixclip(GrContext* context, const SkMatrix& matrix,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000275 const SkClipStack& clipStack,
reed@google.com6f8f2922011-03-04 22:27:10 +0000276 const SkRegion& clipRegion,
277 const SkIPoint& origin) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000278 GrMatrix grmat;
279 SkGr::SkMatrix2GrMatrix(matrix, &grmat);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000280 context->setMatrix(grmat);
reed@google.comac10a2d2010-12-22 21:39:39 +0000281
282 SkGrClipIterator iter;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000283 iter.reset(clipStack);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000284 const SkIRect& skBounds = clipRegion.getBounds();
285 GrRect bounds;
286 bounds.setLTRB(GrIntToScalar(skBounds.fLeft),
287 GrIntToScalar(skBounds.fTop),
288 GrIntToScalar(skBounds.fRight),
289 GrIntToScalar(skBounds.fBottom));
reed@google.com6f8f2922011-03-04 22:27:10 +0000290 GrClip grc(&iter, GrIntToScalar(-origin.x()), GrIntToScalar(-origin.y()),
291 &bounds);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000292 context->setClip(grc);
reed@google.comac10a2d2010-12-22 21:39:39 +0000293}
294
295// call this ever each draw call, to ensure that the context reflects our state,
296// and not the state from some other canvas/device
297void SkGpuDevice::prepareRenderTarget(const SkDraw& draw) {
298 if (fNeedPrepareRenderTarget ||
bsalomon@google.com5782d712011-01-21 21:03:59 +0000299 fContext->getRenderTarget() != fRenderTarget) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000300
301 fContext->setRenderTarget(fRenderTarget);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000302 SkASSERT(draw.fClipStack);
303 convert_matrixclip(fContext, *draw.fMatrix,
reed@google.com6f8f2922011-03-04 22:27:10 +0000304 *draw.fClipStack, *draw.fClip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000305 fNeedPrepareRenderTarget = false;
306 }
307}
308
reed@google.com46799cd2011-02-22 20:56:26 +0000309void SkGpuDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& clip,
310 const SkClipStack& clipStack) {
311 this->INHERITED::setMatrixClip(matrix, clip, clipStack);
bsalomon@google.coma7bf6e22011-04-11 19:20:46 +0000312 // We don't need to set them now because the context may not reflect this device.
313 fNeedPrepareRenderTarget = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000314}
315
316void SkGpuDevice::gainFocus(SkCanvas* canvas, const SkMatrix& matrix,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000317 const SkRegion& clip, const SkClipStack& clipStack) {
318
reed@google.comac10a2d2010-12-22 21:39:39 +0000319 fContext->setRenderTarget(fRenderTarget);
320
bsalomon@google.comd302f142011-03-03 13:54:13 +0000321 this->INHERITED::gainFocus(canvas, matrix, clip, clipStack);
reed@google.comac10a2d2010-12-22 21:39:39 +0000322
reed@google.com6f8f2922011-03-04 22:27:10 +0000323 convert_matrixclip(fContext, matrix, clipStack, clip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000324
325 if (fNeedClear) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000326 fContext->clear(0x0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000327 fNeedClear = false;
328 }
329}
330
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000331bool SkGpuDevice::bindDeviceAsTexture(GrPaint* paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000332 if (NULL != fTexture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000333 paint->setTexture(fTexture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000334 return true;
335 }
336 return false;
337}
338
339///////////////////////////////////////////////////////////////////////////////
340
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000341SK_COMPILE_ASSERT(SkShader::kNone_BitmapType == 0, shader_type_mismatch);
342SK_COMPILE_ASSERT(SkShader::kDefault_BitmapType == 1, shader_type_mismatch);
343SK_COMPILE_ASSERT(SkShader::kRadial_BitmapType == 2, shader_type_mismatch);
344SK_COMPILE_ASSERT(SkShader::kSweep_BitmapType == 3, shader_type_mismatch);
345SK_COMPILE_ASSERT(SkShader::kTwoPointRadial_BitmapType == 4,
346 shader_type_mismatch);
347SK_COMPILE_ASSERT(SkShader::kLast_BitmapType == 4, shader_type_mismatch);
reed@google.comac10a2d2010-12-22 21:39:39 +0000348
bsalomon@google.com5782d712011-01-21 21:03:59 +0000349static const GrSamplerState::SampleMode sk_bmp_type_to_sample_mode[] = {
350 (GrSamplerState::SampleMode) -1, // kNone_BitmapType
351 GrSamplerState::kNormal_SampleMode, // kDefault_BitmapType
352 GrSamplerState::kRadial_SampleMode, // kRadial_BitmapType
353 GrSamplerState::kSweep_SampleMode, // kSweep_BitmapType
354 GrSamplerState::kRadial2_SampleMode, // kTwoPointRadial_BitmapType
355};
356
357bool SkGpuDevice::skPaint2GrPaintNoShader(const SkPaint& skPaint,
358 bool justAlpha,
359 GrPaint* grPaint) {
360
361 grPaint->fDither = skPaint.isDither();
362 grPaint->fAntiAlias = skPaint.isAntiAlias();
363
364 SkXfermode::Coeff sm = SkXfermode::kOne_Coeff;
365 SkXfermode::Coeff dm = SkXfermode::kISA_Coeff;
366
367 SkXfermode* mode = skPaint.getXfermode();
368 if (mode) {
369 if (!mode->asCoeff(&sm, &dm)) {
reed@google.com1a2e8d22011-01-21 22:08:29 +0000370 SkDEBUGCODE(SkDebugf("Unsupported xfer mode.\n");)
bsalomon@google.com5782d712011-01-21 21:03:59 +0000371#if 0
372 return false;
373#endif
374 }
375 }
376 grPaint->fSrcBlendCoeff = sk_blend_to_grblend(sm);
377 grPaint->fDstBlendCoeff = sk_blend_to_grblend(dm);
378
379 if (justAlpha) {
380 uint8_t alpha = skPaint.getAlpha();
381 grPaint->fColor = GrColorPackRGBA(alpha, alpha, alpha, alpha);
382 } else {
383 grPaint->fColor = SkGr::SkColor2GrColor(skPaint.getColor());
384 grPaint->setTexture(NULL);
385 }
386 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000387}
388
bsalomon@google.com5782d712011-01-21 21:03:59 +0000389bool SkGpuDevice::skPaint2GrPaintShader(const SkPaint& skPaint,
390 SkAutoCachedTexture* act,
391 const SkMatrix& ctm,
392 GrPaint* grPaint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000393
bsalomon@google.com5782d712011-01-21 21:03:59 +0000394 SkASSERT(NULL != act);
reed@google.comac10a2d2010-12-22 21:39:39 +0000395
bsalomon@google.com5782d712011-01-21 21:03:59 +0000396 SkShader* shader = skPaint.getShader();
reed@google.comac10a2d2010-12-22 21:39:39 +0000397 if (NULL == shader) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000398 return this->skPaint2GrPaintNoShader(skPaint, false, grPaint);
399 grPaint->setTexture(NULL);
400 return true;
401 } else if (!this->skPaint2GrPaintNoShader(skPaint, true, grPaint)) {
402 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000403 }
404
bsalomon@google.com5782d712011-01-21 21:03:59 +0000405 SkPaint noAlphaPaint(skPaint);
406 noAlphaPaint.setAlpha(255);
407 shader->setContext(this->accessBitmap(false), noAlphaPaint, ctm);
reed@google.comac10a2d2010-12-22 21:39:39 +0000408
reed@google.comac10a2d2010-12-22 21:39:39 +0000409 SkBitmap bitmap;
410 SkMatrix matrix;
411 SkShader::TileMode tileModes[2];
412 SkScalar twoPointParams[3];
413 SkShader::BitmapType bmptype = shader->asABitmap(&bitmap, &matrix,
414 tileModes, twoPointParams);
415
bsalomon@google.com5782d712011-01-21 21:03:59 +0000416 GrSamplerState::SampleMode sampleMode = sk_bmp_type_to_sample_mode[bmptype];
417 if (-1 == sampleMode) {
418 SkDebugf("shader->asABitmap() == kNone_BitmapType\n");
419 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000420 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000421 grPaint->fSampler.setSampleMode(sampleMode);
bsalomon@google.com0748f212011-02-01 22:56:16 +0000422 grPaint->fSampler.setFilter(skPaint.isFilterBitmap());
bsalomon@google.com5782d712011-01-21 21:03:59 +0000423 grPaint->fSampler.setWrapX(sk_tile_mode_to_grwrap(tileModes[0]));
424 grPaint->fSampler.setWrapY(sk_tile_mode_to_grwrap(tileModes[1]));
reed@google.comac10a2d2010-12-22 21:39:39 +0000425 if (GrSamplerState::kRadial2_SampleMode == sampleMode) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000426 grPaint->fSampler.setRadial2Params(twoPointParams[0],
427 twoPointParams[1],
428 twoPointParams[2] < 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000429 }
430
bsalomon@google.com5782d712011-01-21 21:03:59 +0000431 GrTexture* texture = act->set(this, bitmap, grPaint->fSampler);
reed@google.comac10a2d2010-12-22 21:39:39 +0000432 if (NULL == texture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000433 SkDebugf("Couldn't convert bitmap to texture.\n");
434 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000435 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000436 grPaint->setTexture(texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000437
438 // since our texture coords will be in local space, we wack the texture
439 // matrix to map them back into 0...1 before we load it
440 SkMatrix localM;
441 if (shader->getLocalMatrix(&localM)) {
442 SkMatrix inverse;
443 if (localM.invert(&inverse)) {
444 matrix.preConcat(inverse);
445 }
446 }
447 if (SkShader::kDefault_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000448 GrScalar sx = GrFixedToScalar(GR_Fixed1 / bitmap.width());
449 GrScalar sy = GrFixedToScalar(GR_Fixed1 / bitmap.height());
reed@google.comac10a2d2010-12-22 21:39:39 +0000450 matrix.postScale(sx, sy);
reed@google.comac10a2d2010-12-22 21:39:39 +0000451 } else if (SkShader::kRadial_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000452 GrScalar s = GrFixedToScalar(GR_Fixed1 / bitmap.width());
reed@google.comac10a2d2010-12-22 21:39:39 +0000453 matrix.postScale(s, s);
454 }
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000455 GrMatrix grMat;
456 SkGr::SkMatrix2GrMatrix(matrix, &grMat);
457 grPaint->fSampler.setMatrix(grMat);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000458
459 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000460}
461
462///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com5782d712011-01-21 21:03:59 +0000463
464class SkPositionSource {
465public:
466 SkPositionSource(const SkPoint* points, int count)
467 : fPoints(points), fCount(count) {}
468
469 int count() const { return fCount; }
470
471 void writeValue(int i, GrPoint* dstPosition) const {
472 SkASSERT(i < fCount);
473 dstPosition->fX = SkScalarToGrScalar(fPoints[i].fX);
474 dstPosition->fY = SkScalarToGrScalar(fPoints[i].fY);
475 }
476private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000477 const SkPoint* fPoints;
bsalomon@google.com19628322011-02-03 21:30:17 +0000478 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000479};
480
481class SkTexCoordSource {
482public:
483 SkTexCoordSource(const SkPoint* coords)
484 : fCoords(coords) {}
485
486 void writeValue(int i, GrPoint* dstCoord) const {
487 dstCoord->fX = SkScalarToGrScalar(fCoords[i].fX);
488 dstCoord->fY = SkScalarToGrScalar(fCoords[i].fY);
489 }
490private:
491 const SkPoint* fCoords;
492};
493
494class SkColorSource {
495public:
496 SkColorSource(const SkColor* colors) : fColors(colors) {}
497
498 void writeValue(int i, GrColor* dstColor) const {
499 *dstColor = SkGr::SkColor2GrColor(fColors[i]);
500 }
501private:
502 const SkColor* fColors;
503};
504
505class SkIndexSource {
506public:
507 SkIndexSource(const uint16_t* indices, int count)
508 : fIndices(indices), fCount(count) {
509 }
510
511 int count() const { return fCount; }
512
513 void writeValue(int i, uint16_t* dstIndex) const {
514 *dstIndex = fIndices[i];
515 }
516
517private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000518 const uint16_t* fIndices;
bsalomon@google.com19628322011-02-03 21:30:17 +0000519 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000520};
521
522///////////////////////////////////////////////////////////////////////////////
523
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000524#if 0 // not currently being used so don't compile,
525
bsalomon@google.com5782d712011-01-21 21:03:59 +0000526// can be used for positions or texture coordinates
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000527
bsalomon@google.com5782d712011-01-21 21:03:59 +0000528class SkRectFanSource {
529public:
530 SkRectFanSource(const SkRect& rect) : fRect(rect) {}
531
532 int count() const { return 4; }
533
534 void writeValue(int i, GrPoint* dstPoint) const {
535 SkASSERT(i < 4);
536 dstPoint->fX = SkScalarToGrScalar((i % 3) ? fRect.fRight :
537 fRect.fLeft);
538 dstPoint->fY = SkScalarToGrScalar((i < 2) ? fRect.fTop :
539 fRect.fBottom);
540 }
541private:
542 const SkRect& fRect;
543};
544
545class SkIRectFanSource {
546public:
547 SkIRectFanSource(const SkIRect& rect) : fRect(rect) {}
548
549 int count() const { return 4; }
550
551 void writeValue(int i, GrPoint* dstPoint) const {
552 SkASSERT(i < 4);
553 dstPoint->fX = (i % 3) ? GrIntToScalar(fRect.fRight) :
554 GrIntToScalar(fRect.fLeft);
555 dstPoint->fY = (i < 2) ? GrIntToScalar(fRect.fTop) :
556 GrIntToScalar(fRect.fBottom);
557 }
558private:
559 const SkIRect& fRect;
560};
561
562class SkMatRectFanSource {
563public:
564 SkMatRectFanSource(const SkRect& rect, const SkMatrix& matrix)
565 : fRect(rect), fMatrix(matrix) {}
566
567 int count() const { return 4; }
568
569 void writeValue(int i, GrPoint* dstPoint) const {
570 SkASSERT(i < 4);
571
572#if SK_SCALAR_IS_GR_SCALAR
573 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
574 (i < 2) ? fRect.fTop : fRect.fBottom,
575 (SkPoint*)dstPoint);
576#else
577 SkPoint dst;
578 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
579 (i < 2) ? fRect.fTop : fRect.fBottom,
580 &dst);
581 dstPoint->fX = SkScalarToGrScalar(dst.fX);
582 dstPoint->fY = SkScalarToGrScalar(dst.fY);
583#endif
584 }
585private:
586 const SkRect& fRect;
587 const SkMatrix& fMatrix;
588};
589
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000590#endif
591
reed@google.comac10a2d2010-12-22 21:39:39 +0000592///////////////////////////////////////////////////////////////////////////////
593
bsalomon@google.com398109c2011-04-14 18:40:27 +0000594void SkGpuDevice::clear(SkColor color) {
595 fContext->clear(color);
596}
597
reed@google.comac10a2d2010-12-22 21:39:39 +0000598void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
599 CHECK_SHOULD_DRAW(draw);
600
bsalomon@google.com5782d712011-01-21 21:03:59 +0000601 GrPaint grPaint;
602 SkAutoCachedTexture act;
603 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000604 return;
605 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000606
607 fContext->drawPaint(grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000608}
609
610// must be in SkCanvas::PointMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +0000611static const GrPrimitiveType gPointMode2PrimtiveType[] = {
612 kPoints_PrimitiveType,
613 kLines_PrimitiveType,
614 kLineStrip_PrimitiveType
reed@google.comac10a2d2010-12-22 21:39:39 +0000615};
616
617void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000618 size_t count, const SkPoint pts[], const SkPaint& paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000619 CHECK_SHOULD_DRAW(draw);
620
621 SkScalar width = paint.getStrokeWidth();
622 if (width < 0) {
623 return;
624 }
625
626 // we only handle hairlines here, else we let the SkDraw call our drawPath()
627 if (width > 0) {
628 draw.drawPoints(mode, count, pts, paint, true);
629 return;
630 }
631
bsalomon@google.com5782d712011-01-21 21:03:59 +0000632 GrPaint grPaint;
633 SkAutoCachedTexture act;
634 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000635 return;
636 }
637
reed@google.comac10a2d2010-12-22 21:39:39 +0000638#if SK_SCALAR_IS_GR_SCALAR
bsalomon@google.com5782d712011-01-21 21:03:59 +0000639 fContext->drawVertices(grPaint,
640 gPointMode2PrimtiveType[mode],
641 count,
642 (GrPoint*)pts,
643 NULL,
644 NULL,
645 NULL,
646 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000647#else
bsalomon@google.com5782d712011-01-21 21:03:59 +0000648 fContext->drawCustomVertices(grPaint,
649 gPointMode2PrimtiveType[mode],
650 SkPositionSource(pts, count));
reed@google.comac10a2d2010-12-22 21:39:39 +0000651#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000652}
653
reed@google.comc9aa5872011-04-05 21:05:37 +0000654///////////////////////////////////////////////////////////////////////////////
655
reed@google.comac10a2d2010-12-22 21:39:39 +0000656void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
657 const SkPaint& paint) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000658 CHECK_SHOULD_DRAW(draw);
659
660 bool doStroke = paint.getStyle() == SkPaint::kStroke_Style;
661 SkScalar width = paint.getStrokeWidth();
662
663 /*
664 We have special code for hairline strokes, miter-strokes, and fills.
665 Anything else we just call our path code.
666 */
667 bool usePath = doStroke && width > 0 &&
668 paint.getStrokeJoin() != SkPaint::kMiter_Join;
669 // another reason we might need to call drawPath...
670 if (paint.getMaskFilter()) {
671 usePath = true;
672 }
673
674 if (usePath) {
675 SkPath path;
676 path.addRect(rect);
677 this->drawPath(draw, path, paint, NULL, true);
678 return;
679 }
680
681 GrPaint grPaint;
682 SkAutoCachedTexture act;
683 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
684 return;
685 }
686 fContext->drawRect(grPaint, Sk2Gr(rect), doStroke ? width : -1);
reed@google.comac10a2d2010-12-22 21:39:39 +0000687}
688
reed@google.com69302852011-02-16 18:08:07 +0000689#include "SkMaskFilter.h"
690#include "SkBounder.h"
691
reed@google.com69302852011-02-16 18:08:07 +0000692static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
693 SkMaskFilter* filter, const SkMatrix& matrix,
694 const SkRegion& clip, SkBounder* bounder,
695 GrPaint* grp) {
696 SkMask srcM, dstM;
697
698 if (!SkDraw::DrawToMask(path, &clip.getBounds(), filter, &matrix, &srcM,
699 SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
700 return false;
701 }
702
703 SkAutoMaskImage autoSrc(&srcM, false);
704
705 if (!filter->filterMask(&dstM, srcM, matrix, NULL)) {
706 return false;
707 }
708 // this will free-up dstM when we're done (allocated in filterMask())
709 SkAutoMaskImage autoDst(&dstM, false);
710
711 if (clip.quickReject(dstM.fBounds)) {
712 return false;
713 }
714 if (bounder && !bounder->doIRect(dstM.fBounds)) {
715 return false;
716 }
717
718 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
719 // the current clip (and identity matrix) and grpaint settings
720
reed@google.com0c219b62011-02-16 21:31:18 +0000721 GrAutoMatrix avm(context, GrMatrix::I());
reed@google.com69302852011-02-16 18:08:07 +0000722
723 const GrGpu::TextureDesc desc = {
724 0,
725 GrGpu::kNone_AALevel,
726 dstM.fBounds.width(),
727 dstM.fBounds.height(),
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000728 kAlpha_8_GrPixelConfig
reed@google.com69302852011-02-16 18:08:07 +0000729 };
730
731 GrTexture* texture = context->createUncachedTexture(desc, dstM.fImage,
732 dstM.fRowBytes);
733 if (NULL == texture) {
734 return false;
735 }
736
reed@google.com0c219b62011-02-16 21:31:18 +0000737 grp->setTexture(texture);
738 texture->unref();
739 grp->fSampler.setClampNoFilter();
reed@google.com69302852011-02-16 18:08:07 +0000740
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000741 GrRect d;
742 d.setLTRB(GrIntToScalar(dstM.fBounds.fLeft),
reed@google.com0c219b62011-02-16 21:31:18 +0000743 GrIntToScalar(dstM.fBounds.fTop),
744 GrIntToScalar(dstM.fBounds.fRight),
745 GrIntToScalar(dstM.fBounds.fBottom));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000746 GrRect s;
747 s.setLTRB(0, 0, GR_Scalar1, GR_Scalar1);
748 context->drawRectToRect(*grp, d, s);
reed@google.com69302852011-02-16 18:08:07 +0000749 return true;
750}
reed@google.com69302852011-02-16 18:08:07 +0000751
reed@google.com0c219b62011-02-16 21:31:18 +0000752void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
reed@google.comac10a2d2010-12-22 21:39:39 +0000753 const SkPaint& paint, const SkMatrix* prePathMatrix,
754 bool pathIsMutable) {
755 CHECK_SHOULD_DRAW(draw);
756
bsalomon@google.com5782d712011-01-21 21:03:59 +0000757 GrPaint grPaint;
758 SkAutoCachedTexture act;
759 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000760 return;
761 }
762
reed@google.com0c219b62011-02-16 21:31:18 +0000763 // BEGIN lift from SkDraw::drawPath()
764
765 SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
766 bool doFill = true;
767 SkPath tmpPath;
reed@google.comac10a2d2010-12-22 21:39:39 +0000768
769 if (prePathMatrix) {
reed@google.come3445642011-02-16 23:20:39 +0000770 SkPath* result = pathPtr;
reed@google.com0c219b62011-02-16 21:31:18 +0000771
reed@google.come3445642011-02-16 23:20:39 +0000772 if (!pathIsMutable) {
773 result = &tmpPath;
774 pathIsMutable = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000775 }
reed@google.come3445642011-02-16 23:20:39 +0000776 // should I push prePathMatrix on our MV stack temporarily, instead
777 // of applying it here? See SkDraw.cpp
778 pathPtr->transform(*prePathMatrix, result);
779 pathPtr = result;
reed@google.comac10a2d2010-12-22 21:39:39 +0000780 }
reed@google.com0c219b62011-02-16 21:31:18 +0000781 // at this point we're done with prePathMatrix
782 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
reed@google.comac10a2d2010-12-22 21:39:39 +0000783
bsalomon@google.com04de7822011-03-25 18:04:43 +0000784 // This "if" is not part of the SkDraw::drawPath() lift.
785 // When we get a 1.0 wide stroke we hairline stroke it instead of creating
786 // a new stroked-path. This is motivated by canvas2D sites that draw
787 // lines as 1.0 wide stroked paths. We can consider doing an alpha-modulated-
788 // hairline for width < 1.0 when AA is enabled.
789 static const int gMatrixMask = ~(SkMatrix::kIdentity_Mask |
790 SkMatrix::kTranslate_Mask);
791 if (!paint.getPathEffect() &&
792 SkPaint::kStroke_Style == paint.getStyle() &&
793 !(draw.fMatrix->getType() & gMatrixMask) &&
794 SK_Scalar1 == paint.getStrokeWidth()) {
795 doFill = false;
796 }
797
798 if (doFill && (paint.getPathEffect() ||
799 paint.getStyle() != SkPaint::kFill_Style)) {
reed@google.com0c219b62011-02-16 21:31:18 +0000800 doFill = paint.getFillPath(*pathPtr, &tmpPath);
801 pathPtr = &tmpPath;
802 }
803
804 // END lift from SkDraw::drawPath()
805
reed@google.com69302852011-02-16 18:08:07 +0000806 if (paint.getMaskFilter()) {
reed@google.com0c219b62011-02-16 21:31:18 +0000807 // avoid possibly allocating a new path in transform if we can
808 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
809
810 // transform the path into device space
reed@google.come3445642011-02-16 23:20:39 +0000811 pathPtr->transform(*draw.fMatrix, devPathPtr);
reed@google.com0c219b62011-02-16 21:31:18 +0000812
813 drawWithMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
reed@google.com69302852011-02-16 18:08:07 +0000814 *draw.fMatrix, *draw.fClip, draw.fBounder, &grPaint);
815 return;
816 }
reed@google.com69302852011-02-16 18:08:07 +0000817
bsalomon@google.comffca4002011-02-22 20:34:01 +0000818 GrPathFill fill = kHairLine_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000819
reed@google.com0c219b62011-02-16 21:31:18 +0000820 if (doFill) {
821 switch (pathPtr->getFillType()) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000822 case SkPath::kWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000823 fill = kWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000824 break;
825 case SkPath::kEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000826 fill = kEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000827 break;
828 case SkPath::kInverseWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000829 fill = kInverseWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000830 break;
831 case SkPath::kInverseEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000832 fill = kInverseEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000833 break;
834 default:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000835 SkDebugf("Unsupported path fill type\n");
reed@google.comac10a2d2010-12-22 21:39:39 +0000836 return;
837 }
838 }
839
reed@google.com0c219b62011-02-16 21:31:18 +0000840 SkGrPathIter iter(*pathPtr);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000841 fContext->drawPath(grPaint, &iter, fill);
reed@google.comac10a2d2010-12-22 21:39:39 +0000842}
843
reed@google.comac10a2d2010-12-22 21:39:39 +0000844void SkGpuDevice::drawBitmap(const SkDraw& draw,
845 const SkBitmap& bitmap,
846 const SkIRect* srcRectPtr,
847 const SkMatrix& m,
848 const SkPaint& paint) {
849 CHECK_SHOULD_DRAW(draw);
850
851 SkIRect srcRect;
852 if (NULL == srcRectPtr) {
853 srcRect.set(0, 0, bitmap.width(), bitmap.height());
854 } else {
855 srcRect = *srcRectPtr;
856 }
857
bsalomon@google.com5782d712011-01-21 21:03:59 +0000858 GrPaint grPaint;
859 if (!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
860 return;
861 }
862 grPaint.fSampler.setFilter(paint.isFilterBitmap());
863
reed@google.com02a7e6c2011-01-28 21:21:49 +0000864 const int maxTextureDim = fContext->getMaxTextureDimension();
865 if (bitmap.getTexture() || (bitmap.width() <= maxTextureDim &&
866 bitmap.height() <= maxTextureDim)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000867 // take the fast case
bsalomon@google.com5782d712011-01-21 21:03:59 +0000868 this->internalDrawBitmap(draw, bitmap, srcRect, m, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000869 return;
870 }
871
872 // undo the translate done by SkCanvas
873 int DX = SkMax32(0, srcRect.fLeft);
874 int DY = SkMax32(0, srcRect.fTop);
875 // compute clip bounds in local coordinates
876 SkIRect clipRect;
877 {
878 SkRect r;
879 r.set(draw.fClip->getBounds());
880 SkMatrix matrix, inverse;
881 matrix.setConcat(*draw.fMatrix, m);
882 if (!matrix.invert(&inverse)) {
883 return;
884 }
885 inverse.mapRect(&r);
886 r.roundOut(&clipRect);
887 // apply the canvas' translate to our local clip
888 clipRect.offset(DX, DY);
889 }
890
reed@google.com02a7e6c2011-01-28 21:21:49 +0000891 int nx = bitmap.width() / maxTextureDim;
892 int ny = bitmap.height() / maxTextureDim;
reed@google.comac10a2d2010-12-22 21:39:39 +0000893 for (int x = 0; x <= nx; x++) {
894 for (int y = 0; y <= ny; y++) {
895 SkIRect tileR;
reed@google.com02a7e6c2011-01-28 21:21:49 +0000896 tileR.set(x * maxTextureDim, y * maxTextureDim,
897 (x + 1) * maxTextureDim, (y + 1) * maxTextureDim);
reed@google.comac10a2d2010-12-22 21:39:39 +0000898 if (!SkIRect::Intersects(tileR, clipRect)) {
899 continue;
900 }
901
902 SkIRect srcR = tileR;
903 if (!srcR.intersect(srcRect)) {
904 continue;
905 }
906
907 SkBitmap tmpB;
908 if (bitmap.extractSubset(&tmpB, tileR)) {
909 // now offset it to make it "local" to our tmp bitmap
910 srcR.offset(-tileR.fLeft, -tileR.fTop);
911
912 SkMatrix tmpM(m);
913 {
914 int dx = tileR.fLeft - DX + SkMax32(0, srcR.fLeft);
915 int dy = tileR.fTop - DY + SkMax32(0, srcR.fTop);
916 tmpM.preTranslate(SkIntToScalar(dx), SkIntToScalar(dy));
917 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000918 this->internalDrawBitmap(draw, tmpB, srcR, tmpM, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000919 }
920 }
921 }
922}
923
924/*
925 * This is called by drawBitmap(), which has to handle images that may be too
926 * large to be represented by a single texture.
927 *
bsalomon@google.com5782d712011-01-21 21:03:59 +0000928 * internalDrawBitmap assumes that the specified bitmap will fit in a texture
929 * and that non-texture portion of the GrPaint has already been setup.
reed@google.comac10a2d2010-12-22 21:39:39 +0000930 */
931void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
932 const SkBitmap& bitmap,
933 const SkIRect& srcRect,
934 const SkMatrix& m,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000935 GrPaint* grPaint) {
reed@google.com02a7e6c2011-01-28 21:21:49 +0000936 SkASSERT(bitmap.width() <= fContext->getMaxTextureDimension() &&
937 bitmap.height() <= fContext->getMaxTextureDimension());
reed@google.comac10a2d2010-12-22 21:39:39 +0000938
939 SkAutoLockPixels alp(bitmap);
940 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
941 return;
942 }
943
bsalomon@google.com5782d712011-01-21 21:03:59 +0000944 grPaint->fSampler.setWrapX(GrSamplerState::kClamp_WrapMode);
945 grPaint->fSampler.setWrapY(GrSamplerState::kClamp_WrapMode);
946 grPaint->fSampler.setSampleMode(GrSamplerState::kNormal_SampleMode);
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000947 grPaint->fSampler.setMatrix(GrMatrix::I());
reed@google.comac10a2d2010-12-22 21:39:39 +0000948
949 GrTexture* texture;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000950 SkAutoCachedTexture act(this, bitmap, grPaint->fSampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000951 if (NULL == texture) {
952 return;
953 }
954
bsalomon@google.com5782d712011-01-21 21:03:59 +0000955 grPaint->setTexture(texture);
reed@google.com46799cd2011-02-22 20:56:26 +0000956
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000957 GrRect dstRect(0, 0, GrIntToScalar(srcRect.width()), GrIntToScalar(srcRect.height()));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000958 GrRect paintRect;
959 paintRect.setLTRB(GrFixedToScalar((srcRect.fLeft << 16) / bitmap.width()),
960 GrFixedToScalar((srcRect.fTop << 16) / bitmap.height()),
961 GrFixedToScalar((srcRect.fRight << 16) / bitmap.width()),
962 GrFixedToScalar((srcRect.fBottom << 16) / bitmap.height()));
reed@google.comac10a2d2010-12-22 21:39:39 +0000963
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000964 GrMatrix grMat;
965 SkGr::SkMatrix2GrMatrix(m, &grMat);
reed@google.comac10a2d2010-12-22 21:39:39 +0000966
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000967 fContext->drawRectToRect(*grPaint, dstRect, paintRect, &grMat);
reed@google.comac10a2d2010-12-22 21:39:39 +0000968}
969
970void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
971 int left, int top, const SkPaint& paint) {
972 CHECK_SHOULD_DRAW(draw);
973
974 SkAutoLockPixels alp(bitmap);
975 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
976 return;
977 }
978
bsalomon@google.com5782d712011-01-21 21:03:59 +0000979 GrPaint grPaint;
980 if(!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
981 return;
982 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000983
bsalomon@google.com5782d712011-01-21 21:03:59 +0000984 GrAutoMatrix avm(fContext, GrMatrix::I());
985
986 GrTexture* texture;
987 grPaint.fSampler.setClampNoFilter();
988 SkAutoCachedTexture act(this, bitmap, grPaint.fSampler, &texture);
989
bsalomon@google.com5782d712011-01-21 21:03:59 +0000990 grPaint.setTexture(texture);
991
bsalomon@google.com5782d712011-01-21 21:03:59 +0000992 fContext->drawRectToRect(grPaint,
993 GrRect(GrIntToScalar(left), GrIntToScalar(top),
994 GrIntToScalar(left + bitmap.width()),
995 GrIntToScalar(top + bitmap.height())),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000996 GrRect(0, 0, GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +0000997}
998
999void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
1000 int x, int y, const SkPaint& paint) {
1001 CHECK_SHOULD_DRAW(draw);
1002
bsalomon@google.com5782d712011-01-21 21:03:59 +00001003 GrPaint grPaint;
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001004 if (!((SkGpuDevice*)dev)->bindDeviceAsTexture(&grPaint) ||
bsalomon@google.com5782d712011-01-21 21:03:59 +00001005 !this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
1006 return;
reed@google.comac10a2d2010-12-22 21:39:39 +00001007 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001008
1009 SkASSERT(NULL != grPaint.getTexture());
1010
1011 const SkBitmap& bm = dev->accessBitmap(false);
1012 int w = bm.width();
1013 int h = bm.height();
1014
1015 GrAutoMatrix avm(fContext, GrMatrix::I());
1016
1017 grPaint.fSampler.setClampNoFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +00001018
1019 fContext->drawRectToRect(grPaint,
reed@google.com1a2e8d22011-01-21 22:08:29 +00001020 GrRect(GrIntToScalar(x),
1021 GrIntToScalar(y),
1022 GrIntToScalar(x + w),
bsalomon@google.com5782d712011-01-21 21:03:59 +00001023 GrIntToScalar(y + h)),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001024 GrRect(0, 0, GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001025}
1026
1027///////////////////////////////////////////////////////////////////////////////
1028
1029// must be in SkCanvas::VertexMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +00001030static const GrPrimitiveType gVertexMode2PrimitiveType[] = {
1031 kTriangles_PrimitiveType,
1032 kTriangleStrip_PrimitiveType,
1033 kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +00001034};
1035
1036void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
1037 int vertexCount, const SkPoint vertices[],
1038 const SkPoint texs[], const SkColor colors[],
1039 SkXfermode* xmode,
1040 const uint16_t indices[], int indexCount,
1041 const SkPaint& paint) {
1042 CHECK_SHOULD_DRAW(draw);
1043
bsalomon@google.com5782d712011-01-21 21:03:59 +00001044 GrPaint grPaint;
1045 SkAutoCachedTexture act;
1046 // we ignore the shader if texs is null.
1047 if (NULL == texs) {
1048 if (!this->skPaint2GrPaintNoShader(paint, false, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001049 return;
1050 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001051 } else {
reed@google.com1a2e8d22011-01-21 22:08:29 +00001052 if (!this->skPaint2GrPaintShader(paint, &act,
1053 *draw.fMatrix,
bsalomon@google.com5782d712011-01-21 21:03:59 +00001054 &grPaint)) {
1055 return;
1056 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001057 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001058
1059 if (NULL != xmode && NULL != texs && NULL != colors) {
1060 SkXfermode::Mode mode;
1061 if (!SkXfermode::IsMode(xmode, &mode) ||
1062 SkXfermode::kMultiply_Mode != mode) {
1063 SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
1064#if 0
1065 return
1066#endif
1067 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001068 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001069
1070#if SK_SCALAR_IS_GR_SCALAR
1071 // even if GrColor and SkColor byte offsets match we need
1072 // to perform pre-multiply.
1073 if (NULL == colors) {
1074 fContext->drawVertices(grPaint,
1075 gVertexMode2PrimitiveType[vmode],
1076 vertexCount,
1077 (GrPoint*) vertices,
1078 (GrPoint*) texs,
1079 NULL,
1080 indices,
1081 indexCount);
1082 } else
1083#endif
1084 {
1085 SkTexCoordSource texSrc(texs);
1086 SkColorSource colSrc(colors);
1087 SkIndexSource idxSrc(indices, indexCount);
1088
1089 fContext->drawCustomVertices(grPaint,
1090 gVertexMode2PrimitiveType[vmode],
1091 SkPositionSource(vertices, vertexCount),
1092 (NULL == texs) ? NULL : &texSrc,
1093 (NULL == colors) ? NULL : &colSrc,
1094 (NULL == indices) ? NULL : &idxSrc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001095 }
1096}
1097
1098///////////////////////////////////////////////////////////////////////////////
1099
1100static void GlyphCacheAuxProc(void* data) {
1101 delete (GrFontScaler*)data;
1102}
1103
1104static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) {
1105 void* auxData;
1106 GrFontScaler* scaler = NULL;
1107 if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
1108 scaler = (GrFontScaler*)auxData;
1109 }
1110 if (NULL == scaler) {
1111 scaler = new SkGrFontScaler(cache);
1112 cache->setAuxProc(GlyphCacheAuxProc, scaler);
1113 }
1114 return scaler;
1115}
1116
1117static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
1118 SkFixed fx, SkFixed fy,
1119 const SkGlyph& glyph) {
1120 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1121
1122 GrSkDrawProcs* procs = (GrSkDrawProcs*)state.fDraw->fProcs;
1123
1124 if (NULL == procs->fFontScaler) {
1125 procs->fFontScaler = get_gr_font_scaler(state.fCache);
1126 }
reed@google.com39ce0ac2011-04-08 15:42:19 +00001127
1128 /*
1129 * Skia calls us with fx,fy already biased by 1/2. It does this to speed
1130 * up rounding these, so that all of its procs (like us) can just call
1131 * SkFixedFloor and get the "rounded" value.
1132 *
1133 * We take advantage of that for fx, where we pass a rounded value, but
1134 * we want the fractional fy, so we have to unbias it first.
1135 */
reed@google.comac10a2d2010-12-22 21:39:39 +00001136 procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0),
reed@google.com39ce0ac2011-04-08 15:42:19 +00001137 SkIntToFixed(SkFixedFloor(fx)),
1138 fy - SK_FixedHalf,
reed@google.comac10a2d2010-12-22 21:39:39 +00001139 procs->fFontScaler);
1140}
1141
bsalomon@google.com5782d712011-01-21 21:03:59 +00001142SkDrawProcs* SkGpuDevice::initDrawForText(GrTextContext* context) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001143
1144 // deferred allocation
1145 if (NULL == fDrawProcs) {
1146 fDrawProcs = new GrSkDrawProcs;
1147 fDrawProcs->fD1GProc = SkGPU_Draw1Glyph;
1148 fDrawProcs->fContext = fContext;
1149 }
1150
1151 // init our (and GL's) state
1152 fDrawProcs->fTextContext = context;
1153 fDrawProcs->fFontScaler = NULL;
1154 return fDrawProcs;
1155}
1156
1157void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
1158 size_t byteLength, SkScalar x, SkScalar y,
1159 const SkPaint& paint) {
1160 CHECK_SHOULD_DRAW(draw);
1161
1162 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1163 // this guy will just call our drawPath()
1164 draw.drawText((const char*)text, byteLength, x, y, paint);
1165 } else {
1166 SkAutoExtMatrix aem(draw.fExtMatrix);
1167 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001168
1169 GrPaint grPaint;
1170 SkAutoCachedTexture act;
1171
1172 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1173 return;
1174 }
1175 GrTextContext context(fContext, grPaint, aem.extMatrix());
1176 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001177 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
1178 }
1179}
1180
1181void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
1182 size_t byteLength, const SkScalar pos[],
1183 SkScalar constY, int scalarsPerPos,
1184 const SkPaint& paint) {
1185 CHECK_SHOULD_DRAW(draw);
1186
1187 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1188 // this guy will just call our drawPath()
1189 draw.drawPosText((const char*)text, byteLength, pos, constY,
1190 scalarsPerPos, paint);
1191 } else {
1192 SkAutoExtMatrix aem(draw.fExtMatrix);
1193 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001194
1195 GrPaint grPaint;
1196 SkAutoCachedTexture act;
1197 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1198 return;
1199 }
1200
1201 GrTextContext context(fContext, grPaint, aem.extMatrix());
1202 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001203 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
1204 scalarsPerPos, paint);
1205 }
1206}
1207
1208void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
1209 size_t len, const SkPath& path,
1210 const SkMatrix* m, const SkPaint& paint) {
1211 CHECK_SHOULD_DRAW(draw);
1212
1213 SkASSERT(draw.fDevice == this);
1214 draw.drawTextOnPath((const char*)text, len, path, m, paint);
1215}
1216
1217///////////////////////////////////////////////////////////////////////////////
1218
reed@google.comf67e4cf2011-03-15 20:56:58 +00001219bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
1220 if (!paint.isLCDRenderText()) {
1221 // we're cool with the paint as is
1222 return false;
1223 }
1224
1225 if (paint.getShader() ||
1226 paint.getXfermode() || // unless its srcover
1227 paint.getMaskFilter() ||
1228 paint.getRasterizer() ||
1229 paint.getColorFilter() ||
1230 paint.getPathEffect() ||
1231 paint.isFakeBoldText() ||
1232 paint.getStyle() != SkPaint::kFill_Style) {
1233 // turn off lcd
1234 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
1235 flags->fHinting = paint.getHinting();
1236 return true;
1237 }
1238 // we're cool with the paint as is
1239 return false;
1240}
1241
1242///////////////////////////////////////////////////////////////////////////////
1243
reed@google.comac10a2d2010-12-22 21:39:39 +00001244SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
1245 const GrSamplerState& sampler,
1246 GrTexture** texture,
1247 bool forDeviceRenderTarget) {
1248 GrContext* ctx = this->context();
1249 uint32_t p0, p1;
1250 if (forDeviceRenderTarget) {
1251 p0 = p1 = -1;
1252 } else {
1253 p0 = bitmap.getGenerationID();
1254 p1 = bitmap.pixelRefOffset();
1255 }
1256
1257 GrTexture* newTexture = NULL;
1258 GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
1259 GrTextureEntry* entry = ctx->findAndLockTexture(&key, sampler);
1260
1261 if (NULL == entry) {
1262
1263 if (forDeviceRenderTarget) {
1264 const GrGpu::TextureDesc desc = {
1265 GrGpu::kRenderTarget_TextureFlag,
1266 GrGpu::kNone_AALevel,
1267 bitmap.width(),
1268 bitmap.height(),
1269 SkGr::Bitmap2PixelConfig(bitmap)
1270 };
1271 entry = ctx->createAndLockTexture(&key, sampler, desc, NULL, 0);
1272
1273 } else {
1274 entry = sk_gr_create_bitmap_texture(ctx, &key, sampler, bitmap);
1275 }
1276 if (NULL == entry) {
1277 GrPrintf("---- failed to create texture for cache [%d %d]\n",
1278 bitmap.width(), bitmap.height());
1279 }
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 }
1287 // IMPORTANT: We can't allow another SkGpuDevice to get this
1288 // cache entry until this one is destroyed!
1289 if (forDeviceRenderTarget) {
1290 ctx->detachCachedTexture(entry);
1291 }
1292 }
1293 return (TexCache*)entry;
1294}
1295
1296void SkGpuDevice::unlockCachedTexture(TexCache* cache) {
1297 this->context()->unlockTexture((GrTextureEntry*)cache);
1298}
1299
reed@google.com7b201d22011-01-11 18:59:23 +00001300///////////////////////////////////////////////////////////////////////////////
1301
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001302SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context,
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001303 GrRenderTarget* rootRenderTarget) {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001304 GrAssert(NULL != context);
1305 GrAssert(NULL != rootRenderTarget);
1306
1307 // check this now rather than passing this value to SkGpuDevice cons.
1308 // we want the rt that is bound *now* in the 3D API, not the one
1309 // at the time of newDevice.
1310 if (SkGpuDevice::Current3DApiRenderTarget() == rootRenderTarget) {
1311 fRootRenderTarget = context->createRenderTargetFrom3DApiState();
1312 } else {
1313 fRootRenderTarget = rootRenderTarget;
1314 rootRenderTarget->ref();
1315 }
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001316
1317 fContext = context;
reed@google.com7b201d22011-01-11 18:59:23 +00001318 context->ref();
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001319
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001320 fRootTexture = NULL;
1321}
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001322
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001323SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context, GrTexture* rootRenderTargetTexture) {
1324 GrAssert(NULL != context);
1325 GrAssert(NULL != rootRenderTargetTexture);
1326 GrAssert(NULL != rootRenderTargetTexture->asRenderTarget());
1327
1328 fRootTexture = rootRenderTargetTexture;
1329 rootRenderTargetTexture->ref();
1330
1331 fRootRenderTarget = rootRenderTargetTexture->asRenderTarget();
1332 fRootRenderTarget->ref();
1333
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001334 fContext = context;
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001335 context->ref();
reed@google.com7b201d22011-01-11 18:59:23 +00001336}
1337
1338SkGpuDeviceFactory::~SkGpuDeviceFactory() {
1339 fContext->unref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001340 fRootRenderTarget->unref();
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001341 GrSafeUnref(fRootTexture);
reed@google.com7b201d22011-01-11 18:59:23 +00001342}
1343
1344SkDevice* SkGpuDeviceFactory::newDevice(SkCanvas*, SkBitmap::Config config,
1345 int width, int height,
1346 bool isOpaque, bool isLayer) {
1347 SkBitmap bm;
1348 bm.setConfig(config, width, height);
1349 bm.setIsOpaque(isOpaque);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001350 return new SkGpuDevice(fContext, bm, isLayer ? NULL : fRootRenderTarget);
reed@google.com7b201d22011-01-11 18:59:23 +00001351}