blob: 76777f014feee9d1ddd5c1c311db0fae819a212b [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"
27
28#define CACHE_LAYER_TEXTURES 1
29
30#if 0
31 extern bool (*gShouldDrawProc)();
32 #define CHECK_SHOULD_DRAW(draw) \
33 do { \
34 if (gShouldDrawProc && !gShouldDrawProc()) return; \
35 this->prepareRenderTarget(draw); \
36 } while (0)
37#else
38 #define CHECK_SHOULD_DRAW(draw) this->prepareRenderTarget(draw)
39#endif
40
41class SkAutoExtMatrix {
42public:
43 SkAutoExtMatrix(const SkMatrix* extMatrix) {
44 if (extMatrix) {
45 SkGr::SkMatrix2GrMatrix(*extMatrix, &fMatrix);
46 fExtMatrix = &fMatrix;
47 } else {
48 fExtMatrix = NULL;
49 }
50 }
51 const GrMatrix* extMatrix() const { return fExtMatrix; }
52
53private:
54 GrMatrix fMatrix;
55 GrMatrix* fExtMatrix; // NULL or &fMatrix
56};
57
58///////////////////////////////////////////////////////////////////////////////
59
60SkGpuDevice::SkAutoCachedTexture::
61 SkAutoCachedTexture(SkGpuDevice* device,
62 const SkBitmap& bitmap,
63 const GrSamplerState& sampler,
64 GrTexture** texture) {
65 GrAssert(texture);
66 fTex = NULL;
67 *texture = this->set(device, bitmap, sampler);
68}
69
70SkGpuDevice::SkAutoCachedTexture::SkAutoCachedTexture() {
71 fTex = NULL;
72}
73
74GrTexture* SkGpuDevice::SkAutoCachedTexture::set(SkGpuDevice* device,
75 const SkBitmap& bitmap,
76 const GrSamplerState& sampler) {
77 if (fTex) {
78 fDevice->unlockCachedTexture(fTex);
79 }
80 fDevice = device;
81 GrTexture* texture = (GrTexture*)bitmap.getTexture();
82 if (texture) {
83 // return the native texture
84 fTex = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +000085 } else {
86 // look it up in our cache
87 fTex = device->lockCachedTexture(bitmap, sampler, &texture, false);
88 }
89 return texture;
90}
91
92SkGpuDevice::SkAutoCachedTexture::~SkAutoCachedTexture() {
93 if (fTex) {
94 fDevice->unlockCachedTexture(fTex);
95 }
96}
97
98///////////////////////////////////////////////////////////////////////////////
99
100bool gDoTraceDraw;
101
102struct GrSkDrawProcs : public SkDrawProcs {
103public:
104 GrContext* fContext;
105 GrTextContext* fTextContext;
106 GrFontScaler* fFontScaler; // cached in the skia glyphcache
107};
108
109///////////////////////////////////////////////////////////////////////////////
110
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000111GrRenderTarget* SkGpuDevice::Current3DApiRenderTarget() {
112 return (GrRenderTarget*) -1;
113}
114
115SkGpuDevice::SkGpuDevice(GrContext* context,
116 const SkBitmap& bitmap,
117 GrRenderTarget* renderTargetOrNull)
118 : SkDevice(NULL, bitmap, (NULL == renderTargetOrNull)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000119
120 fNeedPrepareRenderTarget = false;
121 fDrawProcs = NULL;
122
reed@google.com7b201d22011-01-11 18:59:23 +0000123 fContext = context;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000124 fContext->ref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000125
126 fCache = NULL;
127 fTexture = NULL;
128 fRenderTarget = NULL;
129 fNeedClear = false;
130
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000131 if (NULL == renderTargetOrNull) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000132 SkBitmap::Config c = bitmap.config();
133 if (c != SkBitmap::kRGB_565_Config) {
134 c = SkBitmap::kARGB_8888_Config;
135 }
136 SkBitmap bm;
137 bm.setConfig(c, this->width(), this->height());
138
139#if CACHE_LAYER_TEXTURES
140
141 fCache = this->lockCachedTexture(bm, GrSamplerState::ClampNoFilter(),
142 &fTexture, true);
143 if (fCache) {
144 SkASSERT(NULL != fTexture);
bsalomon@google.com1da07462011-03-10 14:51:57 +0000145 SkASSERT(NULL != fTexture->asRenderTarget());
reed@google.comac10a2d2010-12-22 21:39:39 +0000146 }
147#else
148 const GrGpu::TextureDesc desc = {
149 GrGpu::kRenderTarget_TextureFlag,
150 GrGpu::kNone_AALevel,
151 this->width(),
152 this->height(),
153 SkGr::Bitmap2PixelConfig(bm)
154 };
155
156 fTexture = fContext->createUncachedTexture(desc, NULL, 0);
157#endif
158 if (NULL != fTexture) {
159 fRenderTarget = fTexture->asRenderTarget();
160
161 GrAssert(NULL != fRenderTarget);
162
163 // we defer the actual clear until our gainFocus()
164 fNeedClear = true;
165
166 // wrap the bitmap with a pixelref to expose our texture
167 SkGrTexturePixelRef* pr = new SkGrTexturePixelRef(fTexture);
168 this->setPixelRef(pr, 0)->unref();
169 } else {
170 GrPrintf("--- failed to create gpu-offscreen [%d %d]\n",
171 this->width(), this->height());
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000172 GrAssert(false);
reed@google.comac10a2d2010-12-22 21:39:39 +0000173 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000174 } else {
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000175 if (Current3DApiRenderTarget() == renderTargetOrNull) {
176 fRenderTarget = fContext->createRenderTargetFrom3DApiState();
177 } else {
178 fRenderTarget = renderTargetOrNull;
179 fRenderTarget->ref();
180 }
181 SkGrRenderTargetPixelRef* pr = new SkGrRenderTargetPixelRef(fRenderTarget);
182 this->setPixelRef(pr, 0)->unref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000183 }
184}
185
186SkGpuDevice::~SkGpuDevice() {
187 if (fDrawProcs) {
188 delete fDrawProcs;
189 }
190
191 if (fCache) {
192 GrAssert(NULL != fTexture);
193 GrAssert(fRenderTarget == fTexture->asRenderTarget());
194 // IMPORTANT: reattach the rendertarget/tex back to the cache.
195 fContext->reattachAndUnlockCachedTexture((GrTextureEntry*)fCache);
196 } 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}
213///////////////////////////////////////////////////////////////////////////////
214
215void SkGpuDevice::makeRenderTargetCurrent() {
216 fContext->setRenderTarget(fRenderTarget);
217 fContext->flush(true);
218 fNeedPrepareRenderTarget = true;
219}
220
221///////////////////////////////////////////////////////////////////////////////
222
223bool SkGpuDevice::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
224 SkIRect bounds;
225 bounds.set(0, 0, this->width(), this->height());
226 if (!bounds.intersect(srcRect)) {
227 return false;
228 }
229
230 const int w = bounds.width();
231 const int h = bounds.height();
232 SkBitmap tmp;
233 // note we explicitly specify our rowBytes to be snug (no gap between rows)
234 tmp.setConfig(SkBitmap::kARGB_8888_Config, w, h, w * 4);
235 if (!tmp.allocPixels()) {
236 return false;
237 }
238
239 SkAutoLockPixels alp(tmp);
reed@google.comac10a2d2010-12-22 21:39:39 +0000240
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000241 if (!fContext->readRenderTargetPixels(fRenderTarget,
242 bounds.fLeft, bounds.fTop,
243 bounds.width(), bounds.height(),
244 kRGBA_8888_GrPixelConfig,
245 tmp.getPixels())) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000246 return false;
247 }
248
249 tmp.swap(*bitmap);
250 return true;
251}
252
253void SkGpuDevice::writePixels(const SkBitmap& bitmap, int x, int y) {
254 SkAutoLockPixels alp(bitmap);
255 if (!bitmap.readyToDraw()) {
256 return;
257 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000258 GrPixelConfig config = SkGr::BitmapConfig2PixelConfig(bitmap.config(),
259 bitmap.isOpaque());
reed@google.comac10a2d2010-12-22 21:39:39 +0000260 fContext->setRenderTarget(fRenderTarget);
261 // we aren't setting the clip or matrix, so mark as dirty
262 // we don't need to set them for this call and don't have them anyway
263 fNeedPrepareRenderTarget = true;
264
265 fContext->writePixels(x, y, bitmap.width(), bitmap.height(),
266 config, bitmap.getPixels(), bitmap.rowBytes());
267}
268
269///////////////////////////////////////////////////////////////////////////////
270
271static void convert_matrixclip(GrContext* context, const SkMatrix& matrix,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000272 const SkClipStack& clipStack,
reed@google.com6f8f2922011-03-04 22:27:10 +0000273 const SkRegion& clipRegion,
274 const SkIPoint& origin) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000275 GrMatrix grmat;
276 SkGr::SkMatrix2GrMatrix(matrix, &grmat);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000277 context->setMatrix(grmat);
reed@google.comac10a2d2010-12-22 21:39:39 +0000278
279 SkGrClipIterator iter;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000280 iter.reset(clipStack);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000281 const SkIRect& skBounds = clipRegion.getBounds();
282 GrRect bounds;
283 bounds.setLTRB(GrIntToScalar(skBounds.fLeft),
284 GrIntToScalar(skBounds.fTop),
285 GrIntToScalar(skBounds.fRight),
286 GrIntToScalar(skBounds.fBottom));
reed@google.com6f8f2922011-03-04 22:27:10 +0000287 GrClip grc(&iter, GrIntToScalar(-origin.x()), GrIntToScalar(-origin.y()),
288 &bounds);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000289 context->setClip(grc);
reed@google.comac10a2d2010-12-22 21:39:39 +0000290}
291
292// call this ever each draw call, to ensure that the context reflects our state,
293// and not the state from some other canvas/device
294void SkGpuDevice::prepareRenderTarget(const SkDraw& draw) {
295 if (fNeedPrepareRenderTarget ||
bsalomon@google.com5782d712011-01-21 21:03:59 +0000296 fContext->getRenderTarget() != fRenderTarget) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000297
298 fContext->setRenderTarget(fRenderTarget);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000299 SkASSERT(draw.fClipStack);
300 convert_matrixclip(fContext, *draw.fMatrix,
reed@google.com6f8f2922011-03-04 22:27:10 +0000301 *draw.fClipStack, *draw.fClip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000302 fNeedPrepareRenderTarget = false;
303 }
304}
305
reed@google.com46799cd2011-02-22 20:56:26 +0000306void SkGpuDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& clip,
307 const SkClipStack& clipStack) {
308 this->INHERITED::setMatrixClip(matrix, clip, clipStack);
reed@google.comac10a2d2010-12-22 21:39:39 +0000309
reed@google.com6f8f2922011-03-04 22:27:10 +0000310 convert_matrixclip(fContext, matrix, clipStack, clip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000311}
312
313void SkGpuDevice::gainFocus(SkCanvas* canvas, const SkMatrix& matrix,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000314 const SkRegion& clip, const SkClipStack& clipStack) {
315
reed@google.comac10a2d2010-12-22 21:39:39 +0000316 fContext->setRenderTarget(fRenderTarget);
317
bsalomon@google.comd302f142011-03-03 13:54:13 +0000318 this->INHERITED::gainFocus(canvas, matrix, clip, clipStack);
reed@google.comac10a2d2010-12-22 21:39:39 +0000319
reed@google.com6f8f2922011-03-04 22:27:10 +0000320 convert_matrixclip(fContext, matrix, clipStack, clip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000321
322 if (fNeedClear) {
323 fContext->eraseColor(0x0);
324 fNeedClear = false;
325 }
326}
327
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000328bool SkGpuDevice::bindDeviceAsTexture(GrPaint* paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000329 if (NULL != fTexture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000330 paint->setTexture(fTexture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000331 return true;
332 }
333 return false;
334}
335
336///////////////////////////////////////////////////////////////////////////////
337
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000338SK_COMPILE_ASSERT(SkShader::kNone_BitmapType == 0, shader_type_mismatch);
339SK_COMPILE_ASSERT(SkShader::kDefault_BitmapType == 1, shader_type_mismatch);
340SK_COMPILE_ASSERT(SkShader::kRadial_BitmapType == 2, shader_type_mismatch);
341SK_COMPILE_ASSERT(SkShader::kSweep_BitmapType == 3, shader_type_mismatch);
342SK_COMPILE_ASSERT(SkShader::kTwoPointRadial_BitmapType == 4,
343 shader_type_mismatch);
344SK_COMPILE_ASSERT(SkShader::kLast_BitmapType == 4, shader_type_mismatch);
reed@google.comac10a2d2010-12-22 21:39:39 +0000345
bsalomon@google.com5782d712011-01-21 21:03:59 +0000346static const GrSamplerState::SampleMode sk_bmp_type_to_sample_mode[] = {
347 (GrSamplerState::SampleMode) -1, // kNone_BitmapType
348 GrSamplerState::kNormal_SampleMode, // kDefault_BitmapType
349 GrSamplerState::kRadial_SampleMode, // kRadial_BitmapType
350 GrSamplerState::kSweep_SampleMode, // kSweep_BitmapType
351 GrSamplerState::kRadial2_SampleMode, // kTwoPointRadial_BitmapType
352};
353
354bool SkGpuDevice::skPaint2GrPaintNoShader(const SkPaint& skPaint,
355 bool justAlpha,
356 GrPaint* grPaint) {
357
358 grPaint->fDither = skPaint.isDither();
359 grPaint->fAntiAlias = skPaint.isAntiAlias();
360
361 SkXfermode::Coeff sm = SkXfermode::kOne_Coeff;
362 SkXfermode::Coeff dm = SkXfermode::kISA_Coeff;
363
364 SkXfermode* mode = skPaint.getXfermode();
365 if (mode) {
366 if (!mode->asCoeff(&sm, &dm)) {
reed@google.com1a2e8d22011-01-21 22:08:29 +0000367 SkDEBUGCODE(SkDebugf("Unsupported xfer mode.\n");)
bsalomon@google.com5782d712011-01-21 21:03:59 +0000368#if 0
369 return false;
370#endif
371 }
372 }
373 grPaint->fSrcBlendCoeff = sk_blend_to_grblend(sm);
374 grPaint->fDstBlendCoeff = sk_blend_to_grblend(dm);
375
376 if (justAlpha) {
377 uint8_t alpha = skPaint.getAlpha();
378 grPaint->fColor = GrColorPackRGBA(alpha, alpha, alpha, alpha);
379 } else {
380 grPaint->fColor = SkGr::SkColor2GrColor(skPaint.getColor());
381 grPaint->setTexture(NULL);
382 }
383 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000384}
385
bsalomon@google.com5782d712011-01-21 21:03:59 +0000386bool SkGpuDevice::skPaint2GrPaintShader(const SkPaint& skPaint,
387 SkAutoCachedTexture* act,
388 const SkMatrix& ctm,
389 GrPaint* grPaint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000390
bsalomon@google.com5782d712011-01-21 21:03:59 +0000391 SkASSERT(NULL != act);
reed@google.comac10a2d2010-12-22 21:39:39 +0000392
bsalomon@google.com5782d712011-01-21 21:03:59 +0000393 SkShader* shader = skPaint.getShader();
reed@google.comac10a2d2010-12-22 21:39:39 +0000394 if (NULL == shader) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000395 return this->skPaint2GrPaintNoShader(skPaint, false, grPaint);
396 grPaint->setTexture(NULL);
397 return true;
398 } else if (!this->skPaint2GrPaintNoShader(skPaint, true, grPaint)) {
399 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000400 }
401
bsalomon@google.com5782d712011-01-21 21:03:59 +0000402 SkPaint noAlphaPaint(skPaint);
403 noAlphaPaint.setAlpha(255);
404 shader->setContext(this->accessBitmap(false), noAlphaPaint, ctm);
reed@google.comac10a2d2010-12-22 21:39:39 +0000405
reed@google.comac10a2d2010-12-22 21:39:39 +0000406 SkBitmap bitmap;
407 SkMatrix matrix;
408 SkShader::TileMode tileModes[2];
409 SkScalar twoPointParams[3];
410 SkShader::BitmapType bmptype = shader->asABitmap(&bitmap, &matrix,
411 tileModes, twoPointParams);
412
bsalomon@google.com5782d712011-01-21 21:03:59 +0000413 GrSamplerState::SampleMode sampleMode = sk_bmp_type_to_sample_mode[bmptype];
414 if (-1 == sampleMode) {
415 SkDebugf("shader->asABitmap() == kNone_BitmapType\n");
416 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000417 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000418 grPaint->fSampler.setSampleMode(sampleMode);
bsalomon@google.com0748f212011-02-01 22:56:16 +0000419 grPaint->fSampler.setFilter(skPaint.isFilterBitmap());
bsalomon@google.com5782d712011-01-21 21:03:59 +0000420 grPaint->fSampler.setWrapX(sk_tile_mode_to_grwrap(tileModes[0]));
421 grPaint->fSampler.setWrapY(sk_tile_mode_to_grwrap(tileModes[1]));
reed@google.comac10a2d2010-12-22 21:39:39 +0000422 if (GrSamplerState::kRadial2_SampleMode == sampleMode) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000423 grPaint->fSampler.setRadial2Params(twoPointParams[0],
424 twoPointParams[1],
425 twoPointParams[2] < 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000426 }
427
bsalomon@google.com5782d712011-01-21 21:03:59 +0000428 GrTexture* texture = act->set(this, bitmap, grPaint->fSampler);
reed@google.comac10a2d2010-12-22 21:39:39 +0000429 if (NULL == texture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000430 SkDebugf("Couldn't convert bitmap to texture.\n");
431 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000432 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000433 grPaint->setTexture(texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000434
435 // since our texture coords will be in local space, we wack the texture
436 // matrix to map them back into 0...1 before we load it
437 SkMatrix localM;
438 if (shader->getLocalMatrix(&localM)) {
439 SkMatrix inverse;
440 if (localM.invert(&inverse)) {
441 matrix.preConcat(inverse);
442 }
443 }
444 if (SkShader::kDefault_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000445 GrScalar sx = GrFixedToScalar(GR_Fixed1 / bitmap.width());
446 GrScalar sy = GrFixedToScalar(GR_Fixed1 / bitmap.height());
reed@google.comac10a2d2010-12-22 21:39:39 +0000447 matrix.postScale(sx, sy);
reed@google.comac10a2d2010-12-22 21:39:39 +0000448 } else if (SkShader::kRadial_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000449 GrScalar s = GrFixedToScalar(GR_Fixed1 / bitmap.width());
reed@google.comac10a2d2010-12-22 21:39:39 +0000450 matrix.postScale(s, s);
451 }
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000452 GrMatrix grMat;
453 SkGr::SkMatrix2GrMatrix(matrix, &grMat);
454 grPaint->fSampler.setMatrix(grMat);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000455
456 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000457}
458
459///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com5782d712011-01-21 21:03:59 +0000460
461class SkPositionSource {
462public:
463 SkPositionSource(const SkPoint* points, int count)
464 : fPoints(points), fCount(count) {}
465
466 int count() const { return fCount; }
467
468 void writeValue(int i, GrPoint* dstPosition) const {
469 SkASSERT(i < fCount);
470 dstPosition->fX = SkScalarToGrScalar(fPoints[i].fX);
471 dstPosition->fY = SkScalarToGrScalar(fPoints[i].fY);
472 }
473private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000474 const SkPoint* fPoints;
bsalomon@google.com19628322011-02-03 21:30:17 +0000475 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000476};
477
478class SkTexCoordSource {
479public:
480 SkTexCoordSource(const SkPoint* coords)
481 : fCoords(coords) {}
482
483 void writeValue(int i, GrPoint* dstCoord) const {
484 dstCoord->fX = SkScalarToGrScalar(fCoords[i].fX);
485 dstCoord->fY = SkScalarToGrScalar(fCoords[i].fY);
486 }
487private:
488 const SkPoint* fCoords;
489};
490
491class SkColorSource {
492public:
493 SkColorSource(const SkColor* colors) : fColors(colors) {}
494
495 void writeValue(int i, GrColor* dstColor) const {
496 *dstColor = SkGr::SkColor2GrColor(fColors[i]);
497 }
498private:
499 const SkColor* fColors;
500};
501
502class SkIndexSource {
503public:
504 SkIndexSource(const uint16_t* indices, int count)
505 : fIndices(indices), fCount(count) {
506 }
507
508 int count() const { return fCount; }
509
510 void writeValue(int i, uint16_t* dstIndex) const {
511 *dstIndex = fIndices[i];
512 }
513
514private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000515 const uint16_t* fIndices;
bsalomon@google.com19628322011-02-03 21:30:17 +0000516 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000517};
518
519///////////////////////////////////////////////////////////////////////////////
520
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000521#if 0 // not currently being used so don't compile,
522
bsalomon@google.com5782d712011-01-21 21:03:59 +0000523// can be used for positions or texture coordinates
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000524
bsalomon@google.com5782d712011-01-21 21:03:59 +0000525class SkRectFanSource {
526public:
527 SkRectFanSource(const SkRect& rect) : fRect(rect) {}
528
529 int count() const { return 4; }
530
531 void writeValue(int i, GrPoint* dstPoint) const {
532 SkASSERT(i < 4);
533 dstPoint->fX = SkScalarToGrScalar((i % 3) ? fRect.fRight :
534 fRect.fLeft);
535 dstPoint->fY = SkScalarToGrScalar((i < 2) ? fRect.fTop :
536 fRect.fBottom);
537 }
538private:
539 const SkRect& fRect;
540};
541
542class SkIRectFanSource {
543public:
544 SkIRectFanSource(const SkIRect& rect) : fRect(rect) {}
545
546 int count() const { return 4; }
547
548 void writeValue(int i, GrPoint* dstPoint) const {
549 SkASSERT(i < 4);
550 dstPoint->fX = (i % 3) ? GrIntToScalar(fRect.fRight) :
551 GrIntToScalar(fRect.fLeft);
552 dstPoint->fY = (i < 2) ? GrIntToScalar(fRect.fTop) :
553 GrIntToScalar(fRect.fBottom);
554 }
555private:
556 const SkIRect& fRect;
557};
558
559class SkMatRectFanSource {
560public:
561 SkMatRectFanSource(const SkRect& rect, const SkMatrix& matrix)
562 : fRect(rect), fMatrix(matrix) {}
563
564 int count() const { return 4; }
565
566 void writeValue(int i, GrPoint* dstPoint) const {
567 SkASSERT(i < 4);
568
569#if SK_SCALAR_IS_GR_SCALAR
570 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
571 (i < 2) ? fRect.fTop : fRect.fBottom,
572 (SkPoint*)dstPoint);
573#else
574 SkPoint dst;
575 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
576 (i < 2) ? fRect.fTop : fRect.fBottom,
577 &dst);
578 dstPoint->fX = SkScalarToGrScalar(dst.fX);
579 dstPoint->fY = SkScalarToGrScalar(dst.fY);
580#endif
581 }
582private:
583 const SkRect& fRect;
584 const SkMatrix& fMatrix;
585};
586
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000587#endif
588
reed@google.comac10a2d2010-12-22 21:39:39 +0000589///////////////////////////////////////////////////////////////////////////////
590
591void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
592 CHECK_SHOULD_DRAW(draw);
593
bsalomon@google.com5782d712011-01-21 21:03:59 +0000594 GrPaint grPaint;
595 SkAutoCachedTexture act;
596 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000597 return;
598 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000599
600 fContext->drawPaint(grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000601}
602
603// must be in SkCanvas::PointMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +0000604static const GrPrimitiveType gPointMode2PrimtiveType[] = {
605 kPoints_PrimitiveType,
606 kLines_PrimitiveType,
607 kLineStrip_PrimitiveType
reed@google.comac10a2d2010-12-22 21:39:39 +0000608};
609
610void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000611 size_t count, const SkPoint pts[], const SkPaint& paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000612 CHECK_SHOULD_DRAW(draw);
613
614 SkScalar width = paint.getStrokeWidth();
615 if (width < 0) {
616 return;
617 }
618
619 // we only handle hairlines here, else we let the SkDraw call our drawPath()
620 if (width > 0) {
621 draw.drawPoints(mode, count, pts, paint, true);
622 return;
623 }
624
bsalomon@google.com5782d712011-01-21 21:03:59 +0000625 GrPaint grPaint;
626 SkAutoCachedTexture act;
627 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000628 return;
629 }
630
reed@google.comac10a2d2010-12-22 21:39:39 +0000631#if SK_SCALAR_IS_GR_SCALAR
bsalomon@google.com5782d712011-01-21 21:03:59 +0000632 fContext->drawVertices(grPaint,
633 gPointMode2PrimtiveType[mode],
634 count,
635 (GrPoint*)pts,
636 NULL,
637 NULL,
638 NULL,
639 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000640#else
bsalomon@google.com5782d712011-01-21 21:03:59 +0000641 fContext->drawCustomVertices(grPaint,
642 gPointMode2PrimtiveType[mode],
643 SkPositionSource(pts, count));
reed@google.comac10a2d2010-12-22 21:39:39 +0000644#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000645}
646
647void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
648 const SkPaint& paint) {
649 CHECK_SHOULD_DRAW(draw);
650
reed@google.com62ab7ad2011-04-05 14:08:25 +0000651 const SkMatrix& matrix = *draw.fMatrix;
652 SkPoint strokeSize;
653 SkDraw::RectType type = SkDraw::ComputeRectType(paint, matrix, &strokeSize);
reed@google.comac10a2d2010-12-22 21:39:39 +0000654
reed@google.com62ab7ad2011-04-05 14:08:25 +0000655 if (SkDraw::kPath_RectType == type) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000656 SkPath path;
657 path.addRect(rect);
658 this->drawPath(draw, path, paint, NULL, true);
reed@google.com62ab7ad2011-04-05 14:08:25 +0000659 } else {
660 GrPaint grPaint;
661 SkAutoCachedTexture act;
662 if (!this->skPaint2GrPaintShader(paint, &act, matrix, &grPaint)) {
663 return;
664 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000665
reed@google.com62ab7ad2011-04-05 14:08:25 +0000666 SkScalar width = paint.getStrokeWidth();
667 if (SkDraw::kFill_RectType == type) {
668 width = -1;
669 }
670 fContext->drawRect(grPaint, Sk2Gr(rect), width);
reed@google.comac10a2d2010-12-22 21:39:39 +0000671 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000672}
673
reed@google.com69302852011-02-16 18:08:07 +0000674#include "SkMaskFilter.h"
675#include "SkBounder.h"
676
reed@google.com69302852011-02-16 18:08:07 +0000677static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
678 SkMaskFilter* filter, const SkMatrix& matrix,
679 const SkRegion& clip, SkBounder* bounder,
680 GrPaint* grp) {
681 SkMask srcM, dstM;
682
683 if (!SkDraw::DrawToMask(path, &clip.getBounds(), filter, &matrix, &srcM,
684 SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
685 return false;
686 }
687
688 SkAutoMaskImage autoSrc(&srcM, false);
689
690 if (!filter->filterMask(&dstM, srcM, matrix, NULL)) {
691 return false;
692 }
693 // this will free-up dstM when we're done (allocated in filterMask())
694 SkAutoMaskImage autoDst(&dstM, false);
695
696 if (clip.quickReject(dstM.fBounds)) {
697 return false;
698 }
699 if (bounder && !bounder->doIRect(dstM.fBounds)) {
700 return false;
701 }
702
703 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
704 // the current clip (and identity matrix) and grpaint settings
705
reed@google.com0c219b62011-02-16 21:31:18 +0000706 GrAutoMatrix avm(context, GrMatrix::I());
reed@google.com69302852011-02-16 18:08:07 +0000707
708 const GrGpu::TextureDesc desc = {
709 0,
710 GrGpu::kNone_AALevel,
711 dstM.fBounds.width(),
712 dstM.fBounds.height(),
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000713 kAlpha_8_GrPixelConfig
reed@google.com69302852011-02-16 18:08:07 +0000714 };
715
716 GrTexture* texture = context->createUncachedTexture(desc, dstM.fImage,
717 dstM.fRowBytes);
718 if (NULL == texture) {
719 return false;
720 }
721
reed@google.com0c219b62011-02-16 21:31:18 +0000722 grp->setTexture(texture);
723 texture->unref();
724 grp->fSampler.setClampNoFilter();
reed@google.com69302852011-02-16 18:08:07 +0000725
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000726 GrRect d;
727 d.setLTRB(GrIntToScalar(dstM.fBounds.fLeft),
reed@google.com0c219b62011-02-16 21:31:18 +0000728 GrIntToScalar(dstM.fBounds.fTop),
729 GrIntToScalar(dstM.fBounds.fRight),
730 GrIntToScalar(dstM.fBounds.fBottom));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000731 GrRect s;
732 s.setLTRB(0, 0, GR_Scalar1, GR_Scalar1);
733 context->drawRectToRect(*grp, d, s);
reed@google.com69302852011-02-16 18:08:07 +0000734 return true;
735}
reed@google.com69302852011-02-16 18:08:07 +0000736
reed@google.com0c219b62011-02-16 21:31:18 +0000737void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
reed@google.comac10a2d2010-12-22 21:39:39 +0000738 const SkPaint& paint, const SkMatrix* prePathMatrix,
739 bool pathIsMutable) {
740 CHECK_SHOULD_DRAW(draw);
741
bsalomon@google.com5782d712011-01-21 21:03:59 +0000742 GrPaint grPaint;
743 SkAutoCachedTexture act;
744 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000745 return;
746 }
747
reed@google.com0c219b62011-02-16 21:31:18 +0000748 // BEGIN lift from SkDraw::drawPath()
749
750 SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
751 bool doFill = true;
752 SkPath tmpPath;
reed@google.comac10a2d2010-12-22 21:39:39 +0000753
754 if (prePathMatrix) {
reed@google.come3445642011-02-16 23:20:39 +0000755 SkPath* result = pathPtr;
reed@google.com0c219b62011-02-16 21:31:18 +0000756
reed@google.come3445642011-02-16 23:20:39 +0000757 if (!pathIsMutable) {
758 result = &tmpPath;
759 pathIsMutable = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000760 }
reed@google.come3445642011-02-16 23:20:39 +0000761 // should I push prePathMatrix on our MV stack temporarily, instead
762 // of applying it here? See SkDraw.cpp
763 pathPtr->transform(*prePathMatrix, result);
764 pathPtr = result;
reed@google.comac10a2d2010-12-22 21:39:39 +0000765 }
reed@google.com0c219b62011-02-16 21:31:18 +0000766 // at this point we're done with prePathMatrix
767 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
reed@google.comac10a2d2010-12-22 21:39:39 +0000768
bsalomon@google.com04de7822011-03-25 18:04:43 +0000769 // This "if" is not part of the SkDraw::drawPath() lift.
770 // When we get a 1.0 wide stroke we hairline stroke it instead of creating
771 // a new stroked-path. This is motivated by canvas2D sites that draw
772 // lines as 1.0 wide stroked paths. We can consider doing an alpha-modulated-
773 // hairline for width < 1.0 when AA is enabled.
774 static const int gMatrixMask = ~(SkMatrix::kIdentity_Mask |
775 SkMatrix::kTranslate_Mask);
776 if (!paint.getPathEffect() &&
777 SkPaint::kStroke_Style == paint.getStyle() &&
778 !(draw.fMatrix->getType() & gMatrixMask) &&
779 SK_Scalar1 == paint.getStrokeWidth()) {
780 doFill = false;
781 }
782
783 if (doFill && (paint.getPathEffect() ||
784 paint.getStyle() != SkPaint::kFill_Style)) {
reed@google.com0c219b62011-02-16 21:31:18 +0000785 doFill = paint.getFillPath(*pathPtr, &tmpPath);
786 pathPtr = &tmpPath;
787 }
788
789 // END lift from SkDraw::drawPath()
790
reed@google.com69302852011-02-16 18:08:07 +0000791 if (paint.getMaskFilter()) {
reed@google.com0c219b62011-02-16 21:31:18 +0000792 // avoid possibly allocating a new path in transform if we can
793 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
794
795 // transform the path into device space
reed@google.come3445642011-02-16 23:20:39 +0000796 pathPtr->transform(*draw.fMatrix, devPathPtr);
reed@google.com0c219b62011-02-16 21:31:18 +0000797
798 drawWithMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
reed@google.com69302852011-02-16 18:08:07 +0000799 *draw.fMatrix, *draw.fClip, draw.fBounder, &grPaint);
800 return;
801 }
reed@google.com69302852011-02-16 18:08:07 +0000802
bsalomon@google.comffca4002011-02-22 20:34:01 +0000803 GrPathFill fill = kHairLine_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000804
reed@google.com0c219b62011-02-16 21:31:18 +0000805 if (doFill) {
806 switch (pathPtr->getFillType()) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000807 case SkPath::kWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000808 fill = kWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000809 break;
810 case SkPath::kEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000811 fill = kEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000812 break;
813 case SkPath::kInverseWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000814 fill = kInverseWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000815 break;
816 case SkPath::kInverseEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000817 fill = kInverseEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000818 break;
819 default:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000820 SkDebugf("Unsupported path fill type\n");
reed@google.comac10a2d2010-12-22 21:39:39 +0000821 return;
822 }
823 }
824
reed@google.com0c219b62011-02-16 21:31:18 +0000825 SkGrPathIter iter(*pathPtr);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000826 fContext->drawPath(grPaint, &iter, fill);
reed@google.comac10a2d2010-12-22 21:39:39 +0000827}
828
reed@google.comac10a2d2010-12-22 21:39:39 +0000829void SkGpuDevice::drawBitmap(const SkDraw& draw,
830 const SkBitmap& bitmap,
831 const SkIRect* srcRectPtr,
832 const SkMatrix& m,
833 const SkPaint& paint) {
834 CHECK_SHOULD_DRAW(draw);
835
836 SkIRect srcRect;
837 if (NULL == srcRectPtr) {
838 srcRect.set(0, 0, bitmap.width(), bitmap.height());
839 } else {
840 srcRect = *srcRectPtr;
841 }
842
bsalomon@google.com5782d712011-01-21 21:03:59 +0000843 GrPaint grPaint;
844 if (!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
845 return;
846 }
847 grPaint.fSampler.setFilter(paint.isFilterBitmap());
848
reed@google.com02a7e6c2011-01-28 21:21:49 +0000849 const int maxTextureDim = fContext->getMaxTextureDimension();
850 if (bitmap.getTexture() || (bitmap.width() <= maxTextureDim &&
851 bitmap.height() <= maxTextureDim)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000852 // take the fast case
bsalomon@google.com5782d712011-01-21 21:03:59 +0000853 this->internalDrawBitmap(draw, bitmap, srcRect, m, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000854 return;
855 }
856
857 // undo the translate done by SkCanvas
858 int DX = SkMax32(0, srcRect.fLeft);
859 int DY = SkMax32(0, srcRect.fTop);
860 // compute clip bounds in local coordinates
861 SkIRect clipRect;
862 {
863 SkRect r;
864 r.set(draw.fClip->getBounds());
865 SkMatrix matrix, inverse;
866 matrix.setConcat(*draw.fMatrix, m);
867 if (!matrix.invert(&inverse)) {
868 return;
869 }
870 inverse.mapRect(&r);
871 r.roundOut(&clipRect);
872 // apply the canvas' translate to our local clip
873 clipRect.offset(DX, DY);
874 }
875
reed@google.com02a7e6c2011-01-28 21:21:49 +0000876 int nx = bitmap.width() / maxTextureDim;
877 int ny = bitmap.height() / maxTextureDim;
reed@google.comac10a2d2010-12-22 21:39:39 +0000878 for (int x = 0; x <= nx; x++) {
879 for (int y = 0; y <= ny; y++) {
880 SkIRect tileR;
reed@google.com02a7e6c2011-01-28 21:21:49 +0000881 tileR.set(x * maxTextureDim, y * maxTextureDim,
882 (x + 1) * maxTextureDim, (y + 1) * maxTextureDim);
reed@google.comac10a2d2010-12-22 21:39:39 +0000883 if (!SkIRect::Intersects(tileR, clipRect)) {
884 continue;
885 }
886
887 SkIRect srcR = tileR;
888 if (!srcR.intersect(srcRect)) {
889 continue;
890 }
891
892 SkBitmap tmpB;
893 if (bitmap.extractSubset(&tmpB, tileR)) {
894 // now offset it to make it "local" to our tmp bitmap
895 srcR.offset(-tileR.fLeft, -tileR.fTop);
896
897 SkMatrix tmpM(m);
898 {
899 int dx = tileR.fLeft - DX + SkMax32(0, srcR.fLeft);
900 int dy = tileR.fTop - DY + SkMax32(0, srcR.fTop);
901 tmpM.preTranslate(SkIntToScalar(dx), SkIntToScalar(dy));
902 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000903 this->internalDrawBitmap(draw, tmpB, srcR, tmpM, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000904 }
905 }
906 }
907}
908
909/*
910 * This is called by drawBitmap(), which has to handle images that may be too
911 * large to be represented by a single texture.
912 *
bsalomon@google.com5782d712011-01-21 21:03:59 +0000913 * internalDrawBitmap assumes that the specified bitmap will fit in a texture
914 * and that non-texture portion of the GrPaint has already been setup.
reed@google.comac10a2d2010-12-22 21:39:39 +0000915 */
916void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
917 const SkBitmap& bitmap,
918 const SkIRect& srcRect,
919 const SkMatrix& m,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000920 GrPaint* grPaint) {
reed@google.com02a7e6c2011-01-28 21:21:49 +0000921 SkASSERT(bitmap.width() <= fContext->getMaxTextureDimension() &&
922 bitmap.height() <= fContext->getMaxTextureDimension());
reed@google.comac10a2d2010-12-22 21:39:39 +0000923
924 SkAutoLockPixels alp(bitmap);
925 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
926 return;
927 }
928
bsalomon@google.com5782d712011-01-21 21:03:59 +0000929 grPaint->fSampler.setWrapX(GrSamplerState::kClamp_WrapMode);
930 grPaint->fSampler.setWrapY(GrSamplerState::kClamp_WrapMode);
931 grPaint->fSampler.setSampleMode(GrSamplerState::kNormal_SampleMode);
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000932 grPaint->fSampler.setMatrix(GrMatrix::I());
reed@google.comac10a2d2010-12-22 21:39:39 +0000933
934 GrTexture* texture;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000935 SkAutoCachedTexture act(this, bitmap, grPaint->fSampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000936 if (NULL == texture) {
937 return;
938 }
939
bsalomon@google.com5782d712011-01-21 21:03:59 +0000940 grPaint->setTexture(texture);
reed@google.com46799cd2011-02-22 20:56:26 +0000941
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000942 GrRect dstRect(0, 0, GrIntToScalar(srcRect.width()), GrIntToScalar(srcRect.height()));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000943 GrRect paintRect;
944 paintRect.setLTRB(GrFixedToScalar((srcRect.fLeft << 16) / bitmap.width()),
945 GrFixedToScalar((srcRect.fTop << 16) / bitmap.height()),
946 GrFixedToScalar((srcRect.fRight << 16) / bitmap.width()),
947 GrFixedToScalar((srcRect.fBottom << 16) / bitmap.height()));
reed@google.comac10a2d2010-12-22 21:39:39 +0000948
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000949 GrMatrix grMat;
950 SkGr::SkMatrix2GrMatrix(m, &grMat);
reed@google.comac10a2d2010-12-22 21:39:39 +0000951
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000952 fContext->drawRectToRect(*grPaint, dstRect, paintRect, &grMat);
reed@google.comac10a2d2010-12-22 21:39:39 +0000953}
954
955void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
956 int left, int top, const SkPaint& paint) {
957 CHECK_SHOULD_DRAW(draw);
958
959 SkAutoLockPixels alp(bitmap);
960 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
961 return;
962 }
963
bsalomon@google.com5782d712011-01-21 21:03:59 +0000964 GrPaint grPaint;
965 if(!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
966 return;
967 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000968
bsalomon@google.com5782d712011-01-21 21:03:59 +0000969 GrAutoMatrix avm(fContext, GrMatrix::I());
970
971 GrTexture* texture;
972 grPaint.fSampler.setClampNoFilter();
973 SkAutoCachedTexture act(this, bitmap, grPaint.fSampler, &texture);
974
bsalomon@google.com5782d712011-01-21 21:03:59 +0000975 grPaint.setTexture(texture);
976
bsalomon@google.com5782d712011-01-21 21:03:59 +0000977 fContext->drawRectToRect(grPaint,
978 GrRect(GrIntToScalar(left), GrIntToScalar(top),
979 GrIntToScalar(left + bitmap.width()),
980 GrIntToScalar(top + bitmap.height())),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000981 GrRect(0, 0, GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +0000982}
983
984void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
985 int x, int y, const SkPaint& paint) {
986 CHECK_SHOULD_DRAW(draw);
987
bsalomon@google.com5782d712011-01-21 21:03:59 +0000988 GrPaint grPaint;
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000989 if (!((SkGpuDevice*)dev)->bindDeviceAsTexture(&grPaint) ||
bsalomon@google.com5782d712011-01-21 21:03:59 +0000990 !this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
991 return;
reed@google.comac10a2d2010-12-22 21:39:39 +0000992 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000993
994 SkASSERT(NULL != grPaint.getTexture());
995
996 const SkBitmap& bm = dev->accessBitmap(false);
997 int w = bm.width();
998 int h = bm.height();
999
1000 GrAutoMatrix avm(fContext, GrMatrix::I());
1001
1002 grPaint.fSampler.setClampNoFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +00001003
1004 fContext->drawRectToRect(grPaint,
reed@google.com1a2e8d22011-01-21 22:08:29 +00001005 GrRect(GrIntToScalar(x),
1006 GrIntToScalar(y),
1007 GrIntToScalar(x + w),
bsalomon@google.com5782d712011-01-21 21:03:59 +00001008 GrIntToScalar(y + h)),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001009 GrRect(0, 0, GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001010}
1011
1012///////////////////////////////////////////////////////////////////////////////
1013
1014// must be in SkCanvas::VertexMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +00001015static const GrPrimitiveType gVertexMode2PrimitiveType[] = {
1016 kTriangles_PrimitiveType,
1017 kTriangleStrip_PrimitiveType,
1018 kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +00001019};
1020
1021void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
1022 int vertexCount, const SkPoint vertices[],
1023 const SkPoint texs[], const SkColor colors[],
1024 SkXfermode* xmode,
1025 const uint16_t indices[], int indexCount,
1026 const SkPaint& paint) {
1027 CHECK_SHOULD_DRAW(draw);
1028
bsalomon@google.com5782d712011-01-21 21:03:59 +00001029 GrPaint grPaint;
1030 SkAutoCachedTexture act;
1031 // we ignore the shader if texs is null.
1032 if (NULL == texs) {
1033 if (!this->skPaint2GrPaintNoShader(paint, false, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001034 return;
1035 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001036 } else {
reed@google.com1a2e8d22011-01-21 22:08:29 +00001037 if (!this->skPaint2GrPaintShader(paint, &act,
1038 *draw.fMatrix,
bsalomon@google.com5782d712011-01-21 21:03:59 +00001039 &grPaint)) {
1040 return;
1041 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001042 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001043
1044 if (NULL != xmode && NULL != texs && NULL != colors) {
1045 SkXfermode::Mode mode;
1046 if (!SkXfermode::IsMode(xmode, &mode) ||
1047 SkXfermode::kMultiply_Mode != mode) {
1048 SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
1049#if 0
1050 return
1051#endif
1052 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001053 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001054
1055#if SK_SCALAR_IS_GR_SCALAR
1056 // even if GrColor and SkColor byte offsets match we need
1057 // to perform pre-multiply.
1058 if (NULL == colors) {
1059 fContext->drawVertices(grPaint,
1060 gVertexMode2PrimitiveType[vmode],
1061 vertexCount,
1062 (GrPoint*) vertices,
1063 (GrPoint*) texs,
1064 NULL,
1065 indices,
1066 indexCount);
1067 } else
1068#endif
1069 {
1070 SkTexCoordSource texSrc(texs);
1071 SkColorSource colSrc(colors);
1072 SkIndexSource idxSrc(indices, indexCount);
1073
1074 fContext->drawCustomVertices(grPaint,
1075 gVertexMode2PrimitiveType[vmode],
1076 SkPositionSource(vertices, vertexCount),
1077 (NULL == texs) ? NULL : &texSrc,
1078 (NULL == colors) ? NULL : &colSrc,
1079 (NULL == indices) ? NULL : &idxSrc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001080 }
1081}
1082
1083///////////////////////////////////////////////////////////////////////////////
1084
1085static void GlyphCacheAuxProc(void* data) {
1086 delete (GrFontScaler*)data;
1087}
1088
1089static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) {
1090 void* auxData;
1091 GrFontScaler* scaler = NULL;
1092 if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
1093 scaler = (GrFontScaler*)auxData;
1094 }
1095 if (NULL == scaler) {
1096 scaler = new SkGrFontScaler(cache);
1097 cache->setAuxProc(GlyphCacheAuxProc, scaler);
1098 }
1099 return scaler;
1100}
1101
1102static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
1103 SkFixed fx, SkFixed fy,
1104 const SkGlyph& glyph) {
1105 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1106
1107 GrSkDrawProcs* procs = (GrSkDrawProcs*)state.fDraw->fProcs;
1108
1109 if (NULL == procs->fFontScaler) {
1110 procs->fFontScaler = get_gr_font_scaler(state.fCache);
1111 }
1112 procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0),
1113 SkIntToFixed(SkFixedFloor(fx)), fy,
1114 procs->fFontScaler);
1115}
1116
bsalomon@google.com5782d712011-01-21 21:03:59 +00001117SkDrawProcs* SkGpuDevice::initDrawForText(GrTextContext* context) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001118
1119 // deferred allocation
1120 if (NULL == fDrawProcs) {
1121 fDrawProcs = new GrSkDrawProcs;
1122 fDrawProcs->fD1GProc = SkGPU_Draw1Glyph;
1123 fDrawProcs->fContext = fContext;
1124 }
1125
1126 // init our (and GL's) state
1127 fDrawProcs->fTextContext = context;
1128 fDrawProcs->fFontScaler = NULL;
1129 return fDrawProcs;
1130}
1131
1132void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
1133 size_t byteLength, SkScalar x, SkScalar y,
1134 const SkPaint& paint) {
1135 CHECK_SHOULD_DRAW(draw);
1136
1137 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1138 // this guy will just call our drawPath()
1139 draw.drawText((const char*)text, byteLength, x, y, paint);
1140 } else {
1141 SkAutoExtMatrix aem(draw.fExtMatrix);
1142 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001143
1144 GrPaint grPaint;
1145 SkAutoCachedTexture act;
1146
1147 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1148 return;
1149 }
1150 GrTextContext context(fContext, grPaint, aem.extMatrix());
1151 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001152 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
1153 }
1154}
1155
1156void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
1157 size_t byteLength, const SkScalar pos[],
1158 SkScalar constY, int scalarsPerPos,
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.drawPosText((const char*)text, byteLength, pos, constY,
1165 scalarsPerPos, paint);
1166 } else {
1167 SkAutoExtMatrix aem(draw.fExtMatrix);
1168 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001169
1170 GrPaint grPaint;
1171 SkAutoCachedTexture act;
1172 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1173 return;
1174 }
1175
1176 GrTextContext context(fContext, grPaint, aem.extMatrix());
1177 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001178 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
1179 scalarsPerPos, paint);
1180 }
1181}
1182
1183void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
1184 size_t len, const SkPath& path,
1185 const SkMatrix* m, const SkPaint& paint) {
1186 CHECK_SHOULD_DRAW(draw);
1187
1188 SkASSERT(draw.fDevice == this);
1189 draw.drawTextOnPath((const char*)text, len, path, m, paint);
1190}
1191
1192///////////////////////////////////////////////////////////////////////////////
1193
reed@google.comf67e4cf2011-03-15 20:56:58 +00001194bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
1195 if (!paint.isLCDRenderText()) {
1196 // we're cool with the paint as is
1197 return false;
1198 }
1199
1200 if (paint.getShader() ||
1201 paint.getXfermode() || // unless its srcover
1202 paint.getMaskFilter() ||
1203 paint.getRasterizer() ||
1204 paint.getColorFilter() ||
1205 paint.getPathEffect() ||
1206 paint.isFakeBoldText() ||
1207 paint.getStyle() != SkPaint::kFill_Style) {
1208 // turn off lcd
1209 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
1210 flags->fHinting = paint.getHinting();
1211 return true;
1212 }
1213 // we're cool with the paint as is
1214 return false;
1215}
1216
1217///////////////////////////////////////////////////////////////////////////////
1218
reed@google.comac10a2d2010-12-22 21:39:39 +00001219SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
1220 const GrSamplerState& sampler,
1221 GrTexture** texture,
1222 bool forDeviceRenderTarget) {
1223 GrContext* ctx = this->context();
1224 uint32_t p0, p1;
1225 if (forDeviceRenderTarget) {
1226 p0 = p1 = -1;
1227 } else {
1228 p0 = bitmap.getGenerationID();
1229 p1 = bitmap.pixelRefOffset();
1230 }
1231
1232 GrTexture* newTexture = NULL;
1233 GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
1234 GrTextureEntry* entry = ctx->findAndLockTexture(&key, sampler);
1235
1236 if (NULL == entry) {
1237
1238 if (forDeviceRenderTarget) {
1239 const GrGpu::TextureDesc desc = {
1240 GrGpu::kRenderTarget_TextureFlag,
1241 GrGpu::kNone_AALevel,
1242 bitmap.width(),
1243 bitmap.height(),
1244 SkGr::Bitmap2PixelConfig(bitmap)
1245 };
1246 entry = ctx->createAndLockTexture(&key, sampler, desc, NULL, 0);
1247
1248 } else {
1249 entry = sk_gr_create_bitmap_texture(ctx, &key, sampler, bitmap);
1250 }
1251 if (NULL == entry) {
1252 GrPrintf("---- failed to create texture for cache [%d %d]\n",
1253 bitmap.width(), bitmap.height());
1254 }
1255 }
1256
1257 if (NULL != entry) {
1258 newTexture = entry->texture();
reed@google.comac10a2d2010-12-22 21:39:39 +00001259 if (texture) {
1260 *texture = newTexture;
1261 }
1262 // IMPORTANT: We can't allow another SkGpuDevice to get this
1263 // cache entry until this one is destroyed!
1264 if (forDeviceRenderTarget) {
1265 ctx->detachCachedTexture(entry);
1266 }
1267 }
1268 return (TexCache*)entry;
1269}
1270
1271void SkGpuDevice::unlockCachedTexture(TexCache* cache) {
1272 this->context()->unlockTexture((GrTextureEntry*)cache);
1273}
1274
reed@google.com7b201d22011-01-11 18:59:23 +00001275///////////////////////////////////////////////////////////////////////////////
1276
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001277SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context,
1278 GrRenderTarget* rootRenderTarget)
1279 : fContext(context) {
1280
1281 GrAssert(NULL != context);
1282 GrAssert(NULL != rootRenderTarget);
1283
1284 // check this now rather than passing this value to SkGpuDevice cons.
1285 // we want the rt that is bound *now* in the 3D API, not the one
1286 // at the time of newDevice.
1287 if (SkGpuDevice::Current3DApiRenderTarget() == rootRenderTarget) {
1288 fRootRenderTarget = context->createRenderTargetFrom3DApiState();
1289 } else {
1290 fRootRenderTarget = rootRenderTarget;
1291 rootRenderTarget->ref();
1292 }
reed@google.com7b201d22011-01-11 18:59:23 +00001293 context->ref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001294
reed@google.com7b201d22011-01-11 18:59:23 +00001295}
1296
1297SkGpuDeviceFactory::~SkGpuDeviceFactory() {
1298 fContext->unref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001299 fRootRenderTarget->unref();
reed@google.com7b201d22011-01-11 18:59:23 +00001300}
1301
1302SkDevice* SkGpuDeviceFactory::newDevice(SkCanvas*, SkBitmap::Config config,
1303 int width, int height,
1304 bool isOpaque, bool isLayer) {
1305 SkBitmap bm;
1306 bm.setConfig(config, width, height);
1307 bm.setIsOpaque(isOpaque);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001308 return new SkGpuDevice(fContext, bm, isLayer ? NULL : fRootRenderTarget);
reed@google.com7b201d22011-01-11 18:59:23 +00001309}
reed@google.comac10a2d2010-12-22 21:39:39 +00001310