blob: b9e7d476100aee3012d558d3657a1fefa29ad284 [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
Scroggo97c88c22011-05-11 14:05:25 +000025#include "SkColorFilter.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000026#include "SkDrawProcs.h"
27#include "SkGlyphCache.h"
reed@google.comc9aa5872011-04-05 21:05:37 +000028#include "SkUtils.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000029
30#define CACHE_LAYER_TEXTURES 1
31
32#if 0
33 extern bool (*gShouldDrawProc)();
34 #define CHECK_SHOULD_DRAW(draw) \
35 do { \
36 if (gShouldDrawProc && !gShouldDrawProc()) return; \
37 this->prepareRenderTarget(draw); \
38 } while (0)
39#else
40 #define CHECK_SHOULD_DRAW(draw) this->prepareRenderTarget(draw)
41#endif
42
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +000043// we use the same texture slot on GrPaint for bitmaps and shaders
44// (since drawBitmap, drawSprite, and drawDevice ignore skia's shader)
45enum {
46 kBitmapTextureIdx = 0,
47 kShaderTextureIdx = 0
48};
49
reed@google.comac10a2d2010-12-22 21:39:39 +000050///////////////////////////////////////////////////////////////////////////////
51
52SkGpuDevice::SkAutoCachedTexture::
53 SkAutoCachedTexture(SkGpuDevice* device,
54 const SkBitmap& bitmap,
55 const GrSamplerState& sampler,
56 GrTexture** texture) {
57 GrAssert(texture);
58 fTex = NULL;
59 *texture = this->set(device, bitmap, sampler);
60}
61
62SkGpuDevice::SkAutoCachedTexture::SkAutoCachedTexture() {
63 fTex = NULL;
64}
65
66GrTexture* SkGpuDevice::SkAutoCachedTexture::set(SkGpuDevice* device,
67 const SkBitmap& bitmap,
68 const GrSamplerState& sampler) {
69 if (fTex) {
70 fDevice->unlockCachedTexture(fTex);
71 }
72 fDevice = device;
73 GrTexture* texture = (GrTexture*)bitmap.getTexture();
74 if (texture) {
75 // return the native texture
76 fTex = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +000077 } else {
78 // look it up in our cache
bsalomon@google.come97f0852011-06-17 13:10:25 +000079 fTex = device->lockCachedTexture(bitmap, sampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +000080 }
81 return texture;
82}
83
84SkGpuDevice::SkAutoCachedTexture::~SkAutoCachedTexture() {
85 if (fTex) {
86 fDevice->unlockCachedTexture(fTex);
87 }
88}
89
90///////////////////////////////////////////////////////////////////////////////
91
92bool gDoTraceDraw;
93
94struct GrSkDrawProcs : public SkDrawProcs {
95public:
96 GrContext* fContext;
97 GrTextContext* fTextContext;
98 GrFontScaler* fFontScaler; // cached in the skia glyphcache
99};
100
101///////////////////////////////////////////////////////////////////////////////
102
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000103GrRenderTarget* SkGpuDevice::Current3DApiRenderTarget() {
104 return (GrRenderTarget*) -1;
105}
106
reed@google.comaf951c92011-06-16 19:10:39 +0000107static SkBitmap::Config grConfig2skConfig(GrPixelConfig config, bool* isOpaque) {
108 switch (config) {
109 case kAlpha_8_GrPixelConfig:
110 *isOpaque = false;
111 return SkBitmap::kA8_Config;
112 case kRGB_565_GrPixelConfig:
113 *isOpaque = true;
114 return SkBitmap::kRGB_565_Config;
115 case kRGBA_4444_GrPixelConfig:
116 *isOpaque = false;
117 return SkBitmap::kARGB_4444_Config;
118 case kRGBA_8888_GrPixelConfig:
119 case kRGBX_8888_GrPixelConfig:
120 *isOpaque = (kRGBX_8888_GrPixelConfig == config);
121 return SkBitmap::kARGB_8888_Config;
122 default:
123 *isOpaque = false;
124 return SkBitmap::kNo_Config;
125 }
126}
reed@google.comac10a2d2010-12-22 21:39:39 +0000127
reed@google.comaf951c92011-06-16 19:10:39 +0000128static SkBitmap make_bitmap(GrContext* context, GrRenderTarget* renderTarget) {
129 if (SkGpuDevice::Current3DApiRenderTarget() == renderTarget) {
130 renderTarget = context->createRenderTargetFrom3DApiState();
131 }
132 GrTexture* texture = renderTarget->asTexture();
133 GrPixelConfig config = texture ? texture->config() : kRGBA_8888_GrPixelConfig;
134
135 bool isOpaque;
136 SkBitmap bitmap;
137 bitmap.setConfig(grConfig2skConfig(config, &isOpaque),
138 renderTarget->width(), renderTarget->height());
139 bitmap.setIsOpaque(isOpaque);
140 return bitmap;
141}
142
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000143SkGpuDevice::SkGpuDevice(GrContext* context, GrTexture* texture)
144: SkDevice(make_bitmap(context, texture->asRenderTarget())) {
145 this->initFromRenderTarget(context, texture->asRenderTarget());
146}
147
reed@google.comaf951c92011-06-16 19:10:39 +0000148SkGpuDevice::SkGpuDevice(GrContext* context, GrRenderTarget* renderTarget)
149: SkDevice(make_bitmap(context, renderTarget)) {
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000150 this->initFromRenderTarget(context, renderTarget);
151}
152
153void SkGpuDevice::initFromRenderTarget(GrContext* context,
154 GrRenderTarget* renderTarget) {
reed@google.comaf951c92011-06-16 19:10:39 +0000155 fNeedPrepareRenderTarget = false;
156 fDrawProcs = NULL;
157
158 fContext = context;
159 fContext->ref();
160
161 fCache = NULL;
162 fTexture = NULL;
163 fRenderTarget = NULL;
164 fNeedClear = false;
165
166 if (Current3DApiRenderTarget() == renderTarget) {
167 fRenderTarget = fContext->createRenderTargetFrom3DApiState();
168 } else {
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000169 GrAssert(NULL != renderTarget);
reed@google.comaf951c92011-06-16 19:10:39 +0000170 fRenderTarget = renderTarget;
171 fRenderTarget->ref();
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000172 // if this RT is also a texture, hold a ref on it
173 fTexture = fRenderTarget->asTexture();
174 SkSafeRef(fTexture);
reed@google.comaf951c92011-06-16 19:10:39 +0000175 }
176
177 SkGrRenderTargetPixelRef* pr = new SkGrRenderTargetPixelRef(fRenderTarget);
178 this->setPixelRef(pr, 0)->unref();
179}
180
181SkGpuDevice::SkGpuDevice(GrContext* context, SkBitmap::Config config, int width,
bsalomon@google.come97f0852011-06-17 13:10:25 +0000182 int height, Usage usage)
reed@google.comaf951c92011-06-16 19:10:39 +0000183: SkDevice(config, width, height, false /*isOpaque*/) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000184 fNeedPrepareRenderTarget = false;
185 fDrawProcs = NULL;
186
reed@google.com7b201d22011-01-11 18:59:23 +0000187 fContext = context;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000188 fContext->ref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000189
190 fCache = NULL;
191 fTexture = NULL;
192 fRenderTarget = NULL;
193 fNeedClear = false;
194
reed@google.comaf951c92011-06-16 19:10:39 +0000195 if (config != SkBitmap::kRGB_565_Config) {
196 config = SkBitmap::kARGB_8888_Config;
197 }
198 SkBitmap bm;
199 bm.setConfig(config, width, height);
reed@google.comac10a2d2010-12-22 21:39:39 +0000200
201#if CACHE_LAYER_TEXTURES
bsalomon@google.come97f0852011-06-17 13:10:25 +0000202 TexType type = (kSaveLayer_Usage == usage) ?
203 kSaveLayerDeviceRenderTarget_TexType :
204 kDeviceRenderTarget_TexType;
reed@google.comaf951c92011-06-16 19:10:39 +0000205 fCache = this->lockCachedTexture(bm, GrSamplerState::ClampNoFilter(),
bsalomon@google.come97f0852011-06-17 13:10:25 +0000206 &fTexture, type);
reed@google.comaf951c92011-06-16 19:10:39 +0000207 if (fCache) {
208 SkASSERT(NULL != fTexture);
209 SkASSERT(NULL != fTexture->asRenderTarget());
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000210 // hold a ref directly on fTexture (even though fCache has one) to match
211 // other constructor paths. Simplifies cleanup.
212 fTexture->ref();
reed@google.comaf951c92011-06-16 19:10:39 +0000213 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000214#else
reed@google.comaf951c92011-06-16 19:10:39 +0000215 const GrTextureDesc desc = {
216 kRenderTarget_GrTextureFlagBit,
217 kNone_GrAALevel,
218 width,
219 height,
220 SkGr::Bitmap2PixelConfig(bm)
221 };
reed@google.comac10a2d2010-12-22 21:39:39 +0000222
reed@google.comaf951c92011-06-16 19:10:39 +0000223 fTexture = fContext->createUncachedTexture(desc, NULL, 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000224#endif
reed@google.comaf951c92011-06-16 19:10:39 +0000225 if (NULL != fTexture) {
226 fRenderTarget = fTexture->asRenderTarget();
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000227 fRenderTarget->ref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000228
reed@google.comaf951c92011-06-16 19:10:39 +0000229 GrAssert(NULL != fRenderTarget);
reed@google.comac10a2d2010-12-22 21:39:39 +0000230
reed@google.comaf951c92011-06-16 19:10:39 +0000231 // we defer the actual clear until our gainFocus()
232 fNeedClear = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000233
reed@google.comaf951c92011-06-16 19:10:39 +0000234 // wrap the bitmap with a pixelref to expose our texture
235 SkGrTexturePixelRef* pr = new SkGrTexturePixelRef(fTexture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000236 this->setPixelRef(pr, 0)->unref();
reed@google.comaf951c92011-06-16 19:10:39 +0000237 } else {
238 GrPrintf("--- failed to create gpu-offscreen [%d %d]\n",
239 width, height);
240 GrAssert(false);
reed@google.comac10a2d2010-12-22 21:39:39 +0000241 }
242}
243
244SkGpuDevice::~SkGpuDevice() {
245 if (fDrawProcs) {
246 delete fDrawProcs;
247 }
248
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000249 SkSafeUnref(fTexture);
250 SkSafeUnref(fRenderTarget);
reed@google.comac10a2d2010-12-22 21:39:39 +0000251 if (fCache) {
252 GrAssert(NULL != fTexture);
253 GrAssert(fRenderTarget == fTexture->asRenderTarget());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000254 fContext->unlockTexture((GrTextureEntry*)fCache);
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000255 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000256 fContext->unref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000257}
258
reed@google.comac10a2d2010-12-22 21:39:39 +0000259intptr_t SkGpuDevice::getLayerTextureHandle() const {
260 if (fTexture) {
261 return fTexture->getTextureHandle();
262 } else {
263 return 0;
264 }
265}
mike@reedtribe.orgea4ac972011-04-26 11:48:33 +0000266
reed@google.comac10a2d2010-12-22 21:39:39 +0000267///////////////////////////////////////////////////////////////////////////////
268
269void SkGpuDevice::makeRenderTargetCurrent() {
270 fContext->setRenderTarget(fRenderTarget);
271 fContext->flush(true);
272 fNeedPrepareRenderTarget = true;
273}
274
275///////////////////////////////////////////////////////////////////////////////
276
277bool SkGpuDevice::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
278 SkIRect bounds;
279 bounds.set(0, 0, this->width(), this->height());
280 if (!bounds.intersect(srcRect)) {
281 return false;
282 }
283
284 const int w = bounds.width();
285 const int h = bounds.height();
286 SkBitmap tmp;
287 // note we explicitly specify our rowBytes to be snug (no gap between rows)
288 tmp.setConfig(SkBitmap::kARGB_8888_Config, w, h, w * 4);
289 if (!tmp.allocPixels()) {
290 return false;
291 }
292
Scroggo813c33c2011-04-07 20:56:21 +0000293 tmp.lockPixels();
reed@google.comac10a2d2010-12-22 21:39:39 +0000294
Scroggoeb176032011-04-07 21:11:49 +0000295 bool read = fContext->readRenderTargetPixels(fRenderTarget,
296 bounds.fLeft, bounds.fTop,
297 bounds.width(), bounds.height(),
298 kRGBA_8888_GrPixelConfig,
299 tmp.getPixels());
Scroggo813c33c2011-04-07 20:56:21 +0000300 tmp.unlockPixels();
301 if (!read) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000302 return false;
303 }
304
305 tmp.swap(*bitmap);
306 return true;
307}
308
309void SkGpuDevice::writePixels(const SkBitmap& bitmap, int x, int y) {
310 SkAutoLockPixels alp(bitmap);
311 if (!bitmap.readyToDraw()) {
312 return;
313 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000314 GrPixelConfig config = SkGr::BitmapConfig2PixelConfig(bitmap.config(),
315 bitmap.isOpaque());
reed@google.comac10a2d2010-12-22 21:39:39 +0000316 fContext->setRenderTarget(fRenderTarget);
317 // we aren't setting the clip or matrix, so mark as dirty
318 // we don't need to set them for this call and don't have them anyway
319 fNeedPrepareRenderTarget = true;
320
321 fContext->writePixels(x, y, bitmap.width(), bitmap.height(),
322 config, bitmap.getPixels(), bitmap.rowBytes());
323}
324
325///////////////////////////////////////////////////////////////////////////////
326
327static void convert_matrixclip(GrContext* context, const SkMatrix& matrix,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000328 const SkClipStack& clipStack,
reed@google.com6f8f2922011-03-04 22:27:10 +0000329 const SkRegion& clipRegion,
330 const SkIPoint& origin) {
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000331 context->setMatrix(matrix);
reed@google.comac10a2d2010-12-22 21:39:39 +0000332
333 SkGrClipIterator iter;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000334 iter.reset(clipStack);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000335 const SkIRect& skBounds = clipRegion.getBounds();
336 GrRect bounds;
337 bounds.setLTRB(GrIntToScalar(skBounds.fLeft),
338 GrIntToScalar(skBounds.fTop),
339 GrIntToScalar(skBounds.fRight),
340 GrIntToScalar(skBounds.fBottom));
reed@google.com6f8f2922011-03-04 22:27:10 +0000341 GrClip grc(&iter, GrIntToScalar(-origin.x()), GrIntToScalar(-origin.y()),
342 &bounds);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000343 context->setClip(grc);
reed@google.comac10a2d2010-12-22 21:39:39 +0000344}
345
346// call this ever each draw call, to ensure that the context reflects our state,
347// and not the state from some other canvas/device
348void SkGpuDevice::prepareRenderTarget(const SkDraw& draw) {
349 if (fNeedPrepareRenderTarget ||
bsalomon@google.com5782d712011-01-21 21:03:59 +0000350 fContext->getRenderTarget() != fRenderTarget) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000351
352 fContext->setRenderTarget(fRenderTarget);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000353 SkASSERT(draw.fClipStack);
354 convert_matrixclip(fContext, *draw.fMatrix,
reed@google.com6f8f2922011-03-04 22:27:10 +0000355 *draw.fClipStack, *draw.fClip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000356 fNeedPrepareRenderTarget = false;
357 }
358}
359
reed@google.com46799cd2011-02-22 20:56:26 +0000360void SkGpuDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& clip,
361 const SkClipStack& clipStack) {
362 this->INHERITED::setMatrixClip(matrix, clip, clipStack);
bsalomon@google.coma7bf6e22011-04-11 19:20:46 +0000363 // We don't need to set them now because the context may not reflect this device.
364 fNeedPrepareRenderTarget = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000365}
366
367void SkGpuDevice::gainFocus(SkCanvas* canvas, const SkMatrix& matrix,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000368 const SkRegion& clip, const SkClipStack& clipStack) {
369
reed@google.comac10a2d2010-12-22 21:39:39 +0000370 fContext->setRenderTarget(fRenderTarget);
371
bsalomon@google.comd302f142011-03-03 13:54:13 +0000372 this->INHERITED::gainFocus(canvas, matrix, clip, clipStack);
reed@google.comac10a2d2010-12-22 21:39:39 +0000373
reed@google.com6f8f2922011-03-04 22:27:10 +0000374 convert_matrixclip(fContext, matrix, clipStack, clip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000375
376 if (fNeedClear) {
bsalomon@google.com31a58402011-04-27 21:00:02 +0000377 fContext->clear(NULL, 0x0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000378 fNeedClear = false;
379 }
380}
381
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000382bool SkGpuDevice::bindDeviceAsTexture(GrPaint* paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000383 if (NULL != fTexture) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000384 paint->setTexture(kBitmapTextureIdx, fTexture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000385 return true;
386 }
387 return false;
388}
389
390///////////////////////////////////////////////////////////////////////////////
391
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000392SK_COMPILE_ASSERT(SkShader::kNone_BitmapType == 0, shader_type_mismatch);
393SK_COMPILE_ASSERT(SkShader::kDefault_BitmapType == 1, shader_type_mismatch);
394SK_COMPILE_ASSERT(SkShader::kRadial_BitmapType == 2, shader_type_mismatch);
395SK_COMPILE_ASSERT(SkShader::kSweep_BitmapType == 3, shader_type_mismatch);
396SK_COMPILE_ASSERT(SkShader::kTwoPointRadial_BitmapType == 4,
397 shader_type_mismatch);
398SK_COMPILE_ASSERT(SkShader::kLast_BitmapType == 4, shader_type_mismatch);
reed@google.comac10a2d2010-12-22 21:39:39 +0000399
bsalomon@google.com5782d712011-01-21 21:03:59 +0000400static const GrSamplerState::SampleMode sk_bmp_type_to_sample_mode[] = {
401 (GrSamplerState::SampleMode) -1, // kNone_BitmapType
402 GrSamplerState::kNormal_SampleMode, // kDefault_BitmapType
403 GrSamplerState::kRadial_SampleMode, // kRadial_BitmapType
404 GrSamplerState::kSweep_SampleMode, // kSweep_BitmapType
405 GrSamplerState::kRadial2_SampleMode, // kTwoPointRadial_BitmapType
406};
407
408bool SkGpuDevice::skPaint2GrPaintNoShader(const SkPaint& skPaint,
409 bool justAlpha,
Scroggod757df22011-05-16 13:11:16 +0000410 GrPaint* grPaint,
411 bool constantColor) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000412
413 grPaint->fDither = skPaint.isDither();
414 grPaint->fAntiAlias = skPaint.isAntiAlias();
415
416 SkXfermode::Coeff sm = SkXfermode::kOne_Coeff;
417 SkXfermode::Coeff dm = SkXfermode::kISA_Coeff;
418
419 SkXfermode* mode = skPaint.getXfermode();
420 if (mode) {
421 if (!mode->asCoeff(&sm, &dm)) {
reed@google.com1a2e8d22011-01-21 22:08:29 +0000422 SkDEBUGCODE(SkDebugf("Unsupported xfer mode.\n");)
bsalomon@google.com5782d712011-01-21 21:03:59 +0000423#if 0
424 return false;
425#endif
426 }
427 }
428 grPaint->fSrcBlendCoeff = sk_blend_to_grblend(sm);
429 grPaint->fDstBlendCoeff = sk_blend_to_grblend(dm);
430
431 if (justAlpha) {
432 uint8_t alpha = skPaint.getAlpha();
433 grPaint->fColor = GrColorPackRGBA(alpha, alpha, alpha, alpha);
Scroggod757df22011-05-16 13:11:16 +0000434 // justAlpha is currently set to true only if there is a texture,
435 // so constantColor should not also be true.
436 GrAssert(!constantColor);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000437 } else {
438 grPaint->fColor = SkGr::SkColor2GrColor(skPaint.getColor());
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000439 grPaint->setTexture(kShaderTextureIdx, NULL);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000440 }
Scroggo97c88c22011-05-11 14:05:25 +0000441 SkColorFilter* colorFilter = skPaint.getColorFilter();
442 SkColor color;
443 SkXfermode::Mode filterMode;
444 if (colorFilter != NULL && colorFilter->asColorMode(&color, &filterMode)) {
Scroggod757df22011-05-16 13:11:16 +0000445 if (!constantColor) {
446 grPaint->fColorFilterColor = SkGr::SkColor2GrColor(color);
447 grPaint->fColorFilterXfermode = filterMode;
448 return true;
449 }
450 SkColor filtered = colorFilter->filterColor(skPaint.getColor());
451 grPaint->fColor = SkGr::SkColor2GrColor(filtered);
Scroggo97c88c22011-05-11 14:05:25 +0000452 }
Scroggod757df22011-05-16 13:11:16 +0000453 grPaint->resetColorFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +0000454 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000455}
456
bsalomon@google.com5782d712011-01-21 21:03:59 +0000457bool SkGpuDevice::skPaint2GrPaintShader(const SkPaint& skPaint,
458 SkAutoCachedTexture* act,
459 const SkMatrix& ctm,
Scroggod757df22011-05-16 13:11:16 +0000460 GrPaint* grPaint,
461 bool constantColor) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000462
bsalomon@google.com5782d712011-01-21 21:03:59 +0000463 SkASSERT(NULL != act);
reed@google.comac10a2d2010-12-22 21:39:39 +0000464
bsalomon@google.com5782d712011-01-21 21:03:59 +0000465 SkShader* shader = skPaint.getShader();
reed@google.comac10a2d2010-12-22 21:39:39 +0000466 if (NULL == shader) {
Scroggod757df22011-05-16 13:11:16 +0000467 return this->skPaint2GrPaintNoShader(skPaint,
468 false,
469 grPaint,
470 constantColor);
471 } else if (!this->skPaint2GrPaintNoShader(skPaint, true, grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000472 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000473 }
474
bsalomon@google.com5782d712011-01-21 21:03:59 +0000475 SkPaint noAlphaPaint(skPaint);
476 noAlphaPaint.setAlpha(255);
477 shader->setContext(this->accessBitmap(false), noAlphaPaint, ctm);
reed@google.comac10a2d2010-12-22 21:39:39 +0000478
reed@google.comac10a2d2010-12-22 21:39:39 +0000479 SkBitmap bitmap;
480 SkMatrix matrix;
481 SkShader::TileMode tileModes[2];
482 SkScalar twoPointParams[3];
483 SkShader::BitmapType bmptype = shader->asABitmap(&bitmap, &matrix,
484 tileModes, twoPointParams);
485
bsalomon@google.com5782d712011-01-21 21:03:59 +0000486 GrSamplerState::SampleMode sampleMode = sk_bmp_type_to_sample_mode[bmptype];
487 if (-1 == sampleMode) {
488 SkDebugf("shader->asABitmap() == kNone_BitmapType\n");
489 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000490 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000491 GrSamplerState* sampler = grPaint->getTextureSampler(kShaderTextureIdx);
492 sampler->setSampleMode(sampleMode);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000493 if (skPaint.isFilterBitmap()) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000494 sampler->setFilter(GrSamplerState::kBilinear_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000495 } else {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000496 sampler->setFilter(GrSamplerState::kNearest_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000497 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000498 sampler->setWrapX(sk_tile_mode_to_grwrap(tileModes[0]));
499 sampler->setWrapY(sk_tile_mode_to_grwrap(tileModes[1]));
reed@google.comac10a2d2010-12-22 21:39:39 +0000500 if (GrSamplerState::kRadial2_SampleMode == sampleMode) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000501 sampler->setRadial2Params(twoPointParams[0],
502 twoPointParams[1],
503 twoPointParams[2] < 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000504 }
505
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000506 GrTexture* texture = act->set(this, bitmap, *sampler);
reed@google.comac10a2d2010-12-22 21:39:39 +0000507 if (NULL == texture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000508 SkDebugf("Couldn't convert bitmap to texture.\n");
509 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000510 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000511 grPaint->setTexture(kShaderTextureIdx, texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000512
513 // since our texture coords will be in local space, we wack the texture
514 // matrix to map them back into 0...1 before we load it
515 SkMatrix localM;
516 if (shader->getLocalMatrix(&localM)) {
517 SkMatrix inverse;
518 if (localM.invert(&inverse)) {
519 matrix.preConcat(inverse);
520 }
521 }
522 if (SkShader::kDefault_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000523 GrScalar sx = GrFixedToScalar(GR_Fixed1 / bitmap.width());
524 GrScalar sy = GrFixedToScalar(GR_Fixed1 / bitmap.height());
reed@google.comac10a2d2010-12-22 21:39:39 +0000525 matrix.postScale(sx, sy);
reed@google.comac10a2d2010-12-22 21:39:39 +0000526 } else if (SkShader::kRadial_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000527 GrScalar s = GrFixedToScalar(GR_Fixed1 / bitmap.width());
reed@google.comac10a2d2010-12-22 21:39:39 +0000528 matrix.postScale(s, s);
529 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000530 sampler->setMatrix(matrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000531
532 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000533}
534
535///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com5782d712011-01-21 21:03:59 +0000536
537class SkPositionSource {
538public:
539 SkPositionSource(const SkPoint* points, int count)
540 : fPoints(points), fCount(count) {}
541
542 int count() const { return fCount; }
543
544 void writeValue(int i, GrPoint* dstPosition) const {
545 SkASSERT(i < fCount);
546 dstPosition->fX = SkScalarToGrScalar(fPoints[i].fX);
547 dstPosition->fY = SkScalarToGrScalar(fPoints[i].fY);
548 }
549private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000550 const SkPoint* fPoints;
bsalomon@google.com19628322011-02-03 21:30:17 +0000551 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000552};
553
554class SkTexCoordSource {
555public:
556 SkTexCoordSource(const SkPoint* coords)
557 : fCoords(coords) {}
558
559 void writeValue(int i, GrPoint* dstCoord) const {
560 dstCoord->fX = SkScalarToGrScalar(fCoords[i].fX);
561 dstCoord->fY = SkScalarToGrScalar(fCoords[i].fY);
562 }
563private:
564 const SkPoint* fCoords;
565};
566
567class SkColorSource {
568public:
569 SkColorSource(const SkColor* colors) : fColors(colors) {}
570
571 void writeValue(int i, GrColor* dstColor) const {
572 *dstColor = SkGr::SkColor2GrColor(fColors[i]);
573 }
574private:
575 const SkColor* fColors;
576};
577
578class SkIndexSource {
579public:
580 SkIndexSource(const uint16_t* indices, int count)
581 : fIndices(indices), fCount(count) {
582 }
583
584 int count() const { return fCount; }
585
586 void writeValue(int i, uint16_t* dstIndex) const {
587 *dstIndex = fIndices[i];
588 }
589
590private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000591 const uint16_t* fIndices;
bsalomon@google.com19628322011-02-03 21:30:17 +0000592 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000593};
594
595///////////////////////////////////////////////////////////////////////////////
596
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000597#if 0 // not currently being used so don't compile,
598
bsalomon@google.com5782d712011-01-21 21:03:59 +0000599// can be used for positions or texture coordinates
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000600
bsalomon@google.com5782d712011-01-21 21:03:59 +0000601class SkRectFanSource {
602public:
603 SkRectFanSource(const SkRect& rect) : fRect(rect) {}
604
605 int count() const { return 4; }
606
607 void writeValue(int i, GrPoint* dstPoint) const {
608 SkASSERT(i < 4);
609 dstPoint->fX = SkScalarToGrScalar((i % 3) ? fRect.fRight :
610 fRect.fLeft);
611 dstPoint->fY = SkScalarToGrScalar((i < 2) ? fRect.fTop :
612 fRect.fBottom);
613 }
614private:
615 const SkRect& fRect;
616};
617
618class SkIRectFanSource {
619public:
620 SkIRectFanSource(const SkIRect& rect) : fRect(rect) {}
621
622 int count() const { return 4; }
623
624 void writeValue(int i, GrPoint* dstPoint) const {
625 SkASSERT(i < 4);
626 dstPoint->fX = (i % 3) ? GrIntToScalar(fRect.fRight) :
627 GrIntToScalar(fRect.fLeft);
628 dstPoint->fY = (i < 2) ? GrIntToScalar(fRect.fTop) :
629 GrIntToScalar(fRect.fBottom);
630 }
631private:
632 const SkIRect& fRect;
633};
634
635class SkMatRectFanSource {
636public:
637 SkMatRectFanSource(const SkRect& rect, const SkMatrix& matrix)
638 : fRect(rect), fMatrix(matrix) {}
639
640 int count() const { return 4; }
641
642 void writeValue(int i, GrPoint* dstPoint) const {
643 SkASSERT(i < 4);
644
645#if SK_SCALAR_IS_GR_SCALAR
646 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
647 (i < 2) ? fRect.fTop : fRect.fBottom,
648 (SkPoint*)dstPoint);
649#else
650 SkPoint dst;
651 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
652 (i < 2) ? fRect.fTop : fRect.fBottom,
653 &dst);
654 dstPoint->fX = SkScalarToGrScalar(dst.fX);
655 dstPoint->fY = SkScalarToGrScalar(dst.fY);
656#endif
657 }
658private:
659 const SkRect& fRect;
660 const SkMatrix& fMatrix;
661};
662
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000663#endif
664
reed@google.comac10a2d2010-12-22 21:39:39 +0000665///////////////////////////////////////////////////////////////////////////////
666
bsalomon@google.com398109c2011-04-14 18:40:27 +0000667void SkGpuDevice::clear(SkColor color) {
bsalomon@google.com31a58402011-04-27 21:00:02 +0000668 fContext->clear(NULL, color);
bsalomon@google.com398109c2011-04-14 18:40:27 +0000669}
670
reed@google.comac10a2d2010-12-22 21:39:39 +0000671void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
672 CHECK_SHOULD_DRAW(draw);
673
bsalomon@google.com5782d712011-01-21 21:03:59 +0000674 GrPaint grPaint;
675 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000676 if (!this->skPaint2GrPaintShader(paint,
677 &act,
678 *draw.fMatrix,
679 &grPaint,
680 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000681 return;
682 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000683
684 fContext->drawPaint(grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000685}
686
687// must be in SkCanvas::PointMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +0000688static const GrPrimitiveType gPointMode2PrimtiveType[] = {
689 kPoints_PrimitiveType,
690 kLines_PrimitiveType,
691 kLineStrip_PrimitiveType
reed@google.comac10a2d2010-12-22 21:39:39 +0000692};
693
694void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000695 size_t count, const SkPoint pts[], const SkPaint& paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000696 CHECK_SHOULD_DRAW(draw);
697
698 SkScalar width = paint.getStrokeWidth();
699 if (width < 0) {
700 return;
701 }
702
703 // we only handle hairlines here, else we let the SkDraw call our drawPath()
704 if (width > 0) {
705 draw.drawPoints(mode, count, pts, paint, true);
706 return;
707 }
708
bsalomon@google.com5782d712011-01-21 21:03:59 +0000709 GrPaint grPaint;
710 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000711 if (!this->skPaint2GrPaintShader(paint,
712 &act,
713 *draw.fMatrix,
714 &grPaint,
715 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000716 return;
717 }
718
reed@google.comac10a2d2010-12-22 21:39:39 +0000719#if SK_SCALAR_IS_GR_SCALAR
bsalomon@google.com5782d712011-01-21 21:03:59 +0000720 fContext->drawVertices(grPaint,
721 gPointMode2PrimtiveType[mode],
722 count,
723 (GrPoint*)pts,
724 NULL,
725 NULL,
726 NULL,
727 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000728#else
bsalomon@google.com5782d712011-01-21 21:03:59 +0000729 fContext->drawCustomVertices(grPaint,
730 gPointMode2PrimtiveType[mode],
731 SkPositionSource(pts, count));
reed@google.comac10a2d2010-12-22 21:39:39 +0000732#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000733}
734
reed@google.comc9aa5872011-04-05 21:05:37 +0000735///////////////////////////////////////////////////////////////////////////////
736
reed@google.comac10a2d2010-12-22 21:39:39 +0000737void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
738 const SkPaint& paint) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000739 CHECK_SHOULD_DRAW(draw);
740
741 bool doStroke = paint.getStyle() == SkPaint::kStroke_Style;
742 SkScalar width = paint.getStrokeWidth();
743
744 /*
745 We have special code for hairline strokes, miter-strokes, and fills.
746 Anything else we just call our path code.
747 */
748 bool usePath = doStroke && width > 0 &&
749 paint.getStrokeJoin() != SkPaint::kMiter_Join;
750 // another reason we might need to call drawPath...
751 if (paint.getMaskFilter()) {
752 usePath = true;
753 }
reed@google.com67db6642011-05-26 11:46:35 +0000754 // until we aa rotated rects...
755 if (!usePath && paint.isAntiAlias() && !draw.fMatrix->rectStaysRect()) {
756 usePath = true;
757 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000758
759 if (usePath) {
760 SkPath path;
761 path.addRect(rect);
762 this->drawPath(draw, path, paint, NULL, true);
763 return;
764 }
765
766 GrPaint grPaint;
767 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000768 if (!this->skPaint2GrPaintShader(paint,
769 &act,
770 *draw.fMatrix,
771 &grPaint,
772 true)) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000773 return;
774 }
reed@google.com20efde72011-05-09 17:00:02 +0000775 fContext->drawRect(grPaint, rect, doStroke ? width : -1);
reed@google.comac10a2d2010-12-22 21:39:39 +0000776}
777
reed@google.com69302852011-02-16 18:08:07 +0000778#include "SkMaskFilter.h"
779#include "SkBounder.h"
780
reed@google.com69302852011-02-16 18:08:07 +0000781static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
782 SkMaskFilter* filter, const SkMatrix& matrix,
783 const SkRegion& clip, SkBounder* bounder,
784 GrPaint* grp) {
785 SkMask srcM, dstM;
786
787 if (!SkDraw::DrawToMask(path, &clip.getBounds(), filter, &matrix, &srcM,
788 SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
789 return false;
790 }
791
792 SkAutoMaskImage autoSrc(&srcM, false);
793
794 if (!filter->filterMask(&dstM, srcM, matrix, NULL)) {
795 return false;
796 }
797 // this will free-up dstM when we're done (allocated in filterMask())
798 SkAutoMaskImage autoDst(&dstM, false);
799
800 if (clip.quickReject(dstM.fBounds)) {
801 return false;
802 }
803 if (bounder && !bounder->doIRect(dstM.fBounds)) {
804 return false;
805 }
806
807 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
808 // the current clip (and identity matrix) and grpaint settings
809
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000810 // used to compute inverse view, if necessary
811 GrMatrix ivm = context->getMatrix();
812
reed@google.com0c219b62011-02-16 21:31:18 +0000813 GrAutoMatrix avm(context, GrMatrix::I());
reed@google.com69302852011-02-16 18:08:07 +0000814
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000815 const GrTextureDesc desc = {
816 kNone_GrTextureFlags,
817 kNone_GrAALevel,
reed@google.com69302852011-02-16 18:08:07 +0000818 dstM.fBounds.width(),
819 dstM.fBounds.height(),
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000820 kAlpha_8_GrPixelConfig
reed@google.com69302852011-02-16 18:08:07 +0000821 };
822
823 GrTexture* texture = context->createUncachedTexture(desc, dstM.fImage,
824 dstM.fRowBytes);
825 if (NULL == texture) {
826 return false;
827 }
828
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000829 if (grp->hasTextureOrMask() && ivm.invert(&ivm)) {
830 grp->preConcatActiveSamplerMatrices(ivm);
831 }
832
833 static const int MASK_IDX = GrPaint::kMaxMasks - 1;
834 // we assume the last mask index is available for use
835 GrAssert(NULL == grp->getMask(MASK_IDX));
836 grp->setMask(MASK_IDX, texture);
reed@google.com0c219b62011-02-16 21:31:18 +0000837 texture->unref();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000838 grp->getMaskSampler(MASK_IDX)->setClampNoFilter();
reed@google.com69302852011-02-16 18:08:07 +0000839
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000840 GrRect d;
841 d.setLTRB(GrIntToScalar(dstM.fBounds.fLeft),
reed@google.com0c219b62011-02-16 21:31:18 +0000842 GrIntToScalar(dstM.fBounds.fTop),
843 GrIntToScalar(dstM.fBounds.fRight),
844 GrIntToScalar(dstM.fBounds.fBottom));
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000845
846 GrMatrix m;
847 m.setTranslate(-dstM.fBounds.fLeft, -dstM.fBounds.fTop);
848 m.postIDiv(dstM.fBounds.width(), dstM.fBounds.height());
849 grp->getMaskSampler(MASK_IDX)->setMatrix(m);
850
851 context->drawRect(*grp, d);
reed@google.com69302852011-02-16 18:08:07 +0000852 return true;
853}
reed@google.com69302852011-02-16 18:08:07 +0000854
reed@google.com0c219b62011-02-16 21:31:18 +0000855void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
reed@google.comac10a2d2010-12-22 21:39:39 +0000856 const SkPaint& paint, const SkMatrix* prePathMatrix,
857 bool pathIsMutable) {
858 CHECK_SHOULD_DRAW(draw);
859
bsalomon@google.com5782d712011-01-21 21:03:59 +0000860 GrPaint grPaint;
861 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000862 if (!this->skPaint2GrPaintShader(paint,
863 &act,
864 *draw.fMatrix,
865 &grPaint,
866 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000867 return;
868 }
869
reed@google.com0c219b62011-02-16 21:31:18 +0000870 // BEGIN lift from SkDraw::drawPath()
871
872 SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
873 bool doFill = true;
874 SkPath tmpPath;
reed@google.comac10a2d2010-12-22 21:39:39 +0000875
876 if (prePathMatrix) {
reed@google.come3445642011-02-16 23:20:39 +0000877 SkPath* result = pathPtr;
reed@google.com0c219b62011-02-16 21:31:18 +0000878
reed@google.come3445642011-02-16 23:20:39 +0000879 if (!pathIsMutable) {
880 result = &tmpPath;
881 pathIsMutable = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000882 }
reed@google.come3445642011-02-16 23:20:39 +0000883 // should I push prePathMatrix on our MV stack temporarily, instead
884 // of applying it here? See SkDraw.cpp
885 pathPtr->transform(*prePathMatrix, result);
886 pathPtr = result;
reed@google.comac10a2d2010-12-22 21:39:39 +0000887 }
reed@google.com0c219b62011-02-16 21:31:18 +0000888 // at this point we're done with prePathMatrix
889 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
reed@google.comac10a2d2010-12-22 21:39:39 +0000890
bsalomon@google.com04de7822011-03-25 18:04:43 +0000891 // This "if" is not part of the SkDraw::drawPath() lift.
892 // When we get a 1.0 wide stroke we hairline stroke it instead of creating
893 // a new stroked-path. This is motivated by canvas2D sites that draw
894 // lines as 1.0 wide stroked paths. We can consider doing an alpha-modulated-
895 // hairline for width < 1.0 when AA is enabled.
896 static const int gMatrixMask = ~(SkMatrix::kIdentity_Mask |
897 SkMatrix::kTranslate_Mask);
898 if (!paint.getPathEffect() &&
899 SkPaint::kStroke_Style == paint.getStyle() &&
900 !(draw.fMatrix->getType() & gMatrixMask) &&
901 SK_Scalar1 == paint.getStrokeWidth()) {
902 doFill = false;
903 }
904
905 if (doFill && (paint.getPathEffect() ||
906 paint.getStyle() != SkPaint::kFill_Style)) {
reed@google.com0c219b62011-02-16 21:31:18 +0000907 doFill = paint.getFillPath(*pathPtr, &tmpPath);
908 pathPtr = &tmpPath;
909 }
910
911 // END lift from SkDraw::drawPath()
912
reed@google.com69302852011-02-16 18:08:07 +0000913 if (paint.getMaskFilter()) {
reed@google.com0c219b62011-02-16 21:31:18 +0000914 // avoid possibly allocating a new path in transform if we can
915 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
916
917 // transform the path into device space
reed@google.come3445642011-02-16 23:20:39 +0000918 pathPtr->transform(*draw.fMatrix, devPathPtr);
reed@google.com0c219b62011-02-16 21:31:18 +0000919
920 drawWithMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
reed@google.com69302852011-02-16 18:08:07 +0000921 *draw.fMatrix, *draw.fClip, draw.fBounder, &grPaint);
922 return;
923 }
reed@google.com69302852011-02-16 18:08:07 +0000924
bsalomon@google.comffca4002011-02-22 20:34:01 +0000925 GrPathFill fill = kHairLine_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000926
reed@google.com0c219b62011-02-16 21:31:18 +0000927 if (doFill) {
928 switch (pathPtr->getFillType()) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000929 case SkPath::kWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000930 fill = kWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000931 break;
932 case SkPath::kEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000933 fill = kEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000934 break;
935 case SkPath::kInverseWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000936 fill = kInverseWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000937 break;
938 case SkPath::kInverseEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000939 fill = kInverseEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000940 break;
941 default:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000942 SkDebugf("Unsupported path fill type\n");
reed@google.comac10a2d2010-12-22 21:39:39 +0000943 return;
944 }
945 }
946
reed@google.com07f3ee12011-05-16 17:21:57 +0000947 fContext->drawPath(grPaint, *pathPtr, fill);
reed@google.comac10a2d2010-12-22 21:39:39 +0000948}
949
reed@google.comac10a2d2010-12-22 21:39:39 +0000950void SkGpuDevice::drawBitmap(const SkDraw& draw,
951 const SkBitmap& bitmap,
952 const SkIRect* srcRectPtr,
953 const SkMatrix& m,
954 const SkPaint& paint) {
955 CHECK_SHOULD_DRAW(draw);
956
957 SkIRect srcRect;
958 if (NULL == srcRectPtr) {
959 srcRect.set(0, 0, bitmap.width(), bitmap.height());
960 } else {
961 srcRect = *srcRectPtr;
962 }
963
junov@google.comd935cfb2011-06-27 20:48:23 +0000964 if (paint.getMaskFilter()){
965 SkBitmap tmp; // storage if we need a subset of bitmap
966 const SkBitmap* bitmapPtr = &bitmap;
967 if (srcRectPtr) {
968 if (!bitmap.extractSubset(&tmp, srcRect)) {
969 return; // extraction failed
970 }
971 bitmapPtr = &tmp;
972 }
973 SkPaint paintWithTexture(paint);
974 paintWithTexture.setShader(SkShader::CreateBitmapShader( *bitmapPtr,
975 SkShader::kClamp_TileMode, SkShader::kClamp_TileMode))->unref();
976 paintWithTexture.getShader()->setLocalMatrix(m);
977
978 SkRect ScalarRect;
979 ScalarRect.set(srcRect);
980
981 if (m.rectStaysRect()) {
982 // Preferred drawing method, optimized for rectangles
983 m.mapRect(&ScalarRect);
984 this->drawRect(draw, ScalarRect, paintWithTexture);
985 } else {
986 // Slower drawing method, for warped or rotated rectangles
987 SkPath path;
988 path.addRect(ScalarRect);
989 path.transform(m);
990 this->drawPath(draw, path, paintWithTexture, NULL, true);
991 }
992 return;
993 }
994
bsalomon@google.com5782d712011-01-21 21:03:59 +0000995 GrPaint grPaint;
Scroggod757df22011-05-16 13:11:16 +0000996 if (!this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000997 return;
998 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000999 GrSamplerState* sampler = grPaint.getTextureSampler(kBitmapTextureIdx);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001000 if (paint.isFilterBitmap()) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001001 sampler->setFilter(GrSamplerState::kBilinear_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001002 } else {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001003 sampler->setFilter(GrSamplerState::kNearest_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001004 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001005
bsalomon@google.com91958362011-06-13 17:58:13 +00001006 const int maxTextureSize = fContext->getMaxTextureSize();
1007 if (bitmap.getTexture() || (bitmap.width() <= maxTextureSize &&
1008 bitmap.height() <= maxTextureSize)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001009 // take the fast case
bsalomon@google.com5782d712011-01-21 21:03:59 +00001010 this->internalDrawBitmap(draw, bitmap, srcRect, m, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +00001011 return;
1012 }
1013
1014 // undo the translate done by SkCanvas
1015 int DX = SkMax32(0, srcRect.fLeft);
1016 int DY = SkMax32(0, srcRect.fTop);
1017 // compute clip bounds in local coordinates
1018 SkIRect clipRect;
1019 {
1020 SkRect r;
1021 r.set(draw.fClip->getBounds());
1022 SkMatrix matrix, inverse;
1023 matrix.setConcat(*draw.fMatrix, m);
1024 if (!matrix.invert(&inverse)) {
1025 return;
1026 }
1027 inverse.mapRect(&r);
1028 r.roundOut(&clipRect);
1029 // apply the canvas' translate to our local clip
1030 clipRect.offset(DX, DY);
1031 }
1032
bsalomon@google.com91958362011-06-13 17:58:13 +00001033 int nx = bitmap.width() / maxTextureSize;
1034 int ny = bitmap.height() / maxTextureSize;
reed@google.comac10a2d2010-12-22 21:39:39 +00001035 for (int x = 0; x <= nx; x++) {
1036 for (int y = 0; y <= ny; y++) {
1037 SkIRect tileR;
bsalomon@google.com91958362011-06-13 17:58:13 +00001038 tileR.set(x * maxTextureSize, y * maxTextureSize,
1039 (x + 1) * maxTextureSize, (y + 1) * maxTextureSize);
reed@google.comac10a2d2010-12-22 21:39:39 +00001040 if (!SkIRect::Intersects(tileR, clipRect)) {
1041 continue;
1042 }
1043
1044 SkIRect srcR = tileR;
1045 if (!srcR.intersect(srcRect)) {
1046 continue;
1047 }
1048
1049 SkBitmap tmpB;
1050 if (bitmap.extractSubset(&tmpB, tileR)) {
1051 // now offset it to make it "local" to our tmp bitmap
1052 srcR.offset(-tileR.fLeft, -tileR.fTop);
1053
1054 SkMatrix tmpM(m);
1055 {
1056 int dx = tileR.fLeft - DX + SkMax32(0, srcR.fLeft);
1057 int dy = tileR.fTop - DY + SkMax32(0, srcR.fTop);
1058 tmpM.preTranslate(SkIntToScalar(dx), SkIntToScalar(dy));
1059 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001060 this->internalDrawBitmap(draw, tmpB, srcR, tmpM, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +00001061 }
1062 }
1063 }
1064}
1065
1066/*
1067 * This is called by drawBitmap(), which has to handle images that may be too
1068 * large to be represented by a single texture.
1069 *
bsalomon@google.com5782d712011-01-21 21:03:59 +00001070 * internalDrawBitmap assumes that the specified bitmap will fit in a texture
1071 * and that non-texture portion of the GrPaint has already been setup.
reed@google.comac10a2d2010-12-22 21:39:39 +00001072 */
1073void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
1074 const SkBitmap& bitmap,
1075 const SkIRect& srcRect,
1076 const SkMatrix& m,
bsalomon@google.com5782d712011-01-21 21:03:59 +00001077 GrPaint* grPaint) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001078 SkASSERT(bitmap.width() <= fContext->getMaxTextureSize() &&
1079 bitmap.height() <= fContext->getMaxTextureSize());
reed@google.comac10a2d2010-12-22 21:39:39 +00001080
1081 SkAutoLockPixels alp(bitmap);
1082 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
1083 return;
1084 }
1085
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001086 GrSamplerState* sampler = grPaint->getTextureSampler(kBitmapTextureIdx);
1087
1088 sampler->setWrapX(GrSamplerState::kClamp_WrapMode);
1089 sampler->setWrapY(GrSamplerState::kClamp_WrapMode);
1090 sampler->setSampleMode(GrSamplerState::kNormal_SampleMode);
1091 sampler->setMatrix(GrMatrix::I());
reed@google.comac10a2d2010-12-22 21:39:39 +00001092
1093 GrTexture* texture;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001094 SkAutoCachedTexture act(this, bitmap, *sampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +00001095 if (NULL == texture) {
1096 return;
1097 }
1098
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001099 grPaint->setTexture(kShaderTextureIdx, texture);
reed@google.com46799cd2011-02-22 20:56:26 +00001100
reed@google.com20efde72011-05-09 17:00:02 +00001101 GrRect dstRect = SkRect::MakeWH(GrIntToScalar(srcRect.width()),
1102 GrIntToScalar(srcRect.height()));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001103 GrRect paintRect;
junov@google.com6acc9b32011-05-16 18:32:07 +00001104 paintRect.setLTRB(GrFixedToScalar((srcRect.fLeft << 16) / bitmap.width()),
1105 GrFixedToScalar((srcRect.fTop << 16) / bitmap.height()),
1106 GrFixedToScalar((srcRect.fRight << 16) / bitmap.width()),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001107 GrFixedToScalar((srcRect.fBottom << 16) / bitmap.height()));
reed@google.comac10a2d2010-12-22 21:39:39 +00001108
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001109 if (GrSamplerState::kNearest_Filter != sampler->getFilter() &&
junov@google.com6acc9b32011-05-16 18:32:07 +00001110 (srcRect.width() < bitmap.width() ||
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001111 srcRect.height() < bitmap.height())) {
junov@google.com6acc9b32011-05-16 18:32:07 +00001112 // If drawing a subrect of the bitmap and filtering is enabled,
1113 // use a constrained texture domain to avoid color bleeding
1114 GrScalar left, top, right, bottom;
1115 if (srcRect.width() > 1) {
1116 GrScalar border = GR_ScalarHalf / bitmap.width();
1117 left = paintRect.left() + border;
1118 right = paintRect.right() - border;
1119 } else {
1120 left = right = GrScalarHalf(paintRect.left() + paintRect.right());
1121 }
1122 if (srcRect.height() > 1) {
1123 GrScalar border = GR_ScalarHalf / bitmap.height();
1124 top = paintRect.top() + border;
1125 bottom = paintRect.bottom() - border;
1126 } else {
1127 top = bottom = GrScalarHalf(paintRect.top() + paintRect.bottom());
1128 }
1129 GrRect textureDomain;
1130 textureDomain.setLTRB(left, top, right, bottom);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001131 sampler->setTextureDomain(textureDomain);
junov@google.com6acc9b32011-05-16 18:32:07 +00001132 }
1133
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001134 fContext->drawRectToRect(*grPaint, dstRect, paintRect, &m);
reed@google.comac10a2d2010-12-22 21:39:39 +00001135}
1136
1137void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
1138 int left, int top, const SkPaint& paint) {
1139 CHECK_SHOULD_DRAW(draw);
1140
1141 SkAutoLockPixels alp(bitmap);
1142 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
1143 return;
1144 }
1145
bsalomon@google.com5782d712011-01-21 21:03:59 +00001146 GrPaint grPaint;
Scroggod757df22011-05-16 13:11:16 +00001147 if(!this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001148 return;
1149 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001150
bsalomon@google.com5782d712011-01-21 21:03:59 +00001151 GrAutoMatrix avm(fContext, GrMatrix::I());
1152
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001153 GrSamplerState* sampler = grPaint.getTextureSampler(kBitmapTextureIdx);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001154
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001155 GrTexture* texture;
1156 sampler->setClampNoFilter();
1157 SkAutoCachedTexture act(this, bitmap, *sampler, &texture);
1158
1159 grPaint.setTexture(kBitmapTextureIdx, texture);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001160
bsalomon@google.com5782d712011-01-21 21:03:59 +00001161 fContext->drawRectToRect(grPaint,
reed@google.com20efde72011-05-09 17:00:02 +00001162 GrRect::MakeXYWH(GrIntToScalar(left),
1163 GrIntToScalar(top),
1164 GrIntToScalar(bitmap.width()),
1165 GrIntToScalar(bitmap.height())),
1166 GrRect::MakeWH(GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001167}
1168
1169void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
1170 int x, int y, const SkPaint& paint) {
1171 CHECK_SHOULD_DRAW(draw);
1172
bsalomon@google.com5782d712011-01-21 21:03:59 +00001173 GrPaint grPaint;
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001174 if (!((SkGpuDevice*)dev)->bindDeviceAsTexture(&grPaint) ||
Scroggod757df22011-05-16 13:11:16 +00001175 !this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001176 return;
reed@google.comac10a2d2010-12-22 21:39:39 +00001177 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001178
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001179 GrTexture* devTex = grPaint.getTexture(0);
1180 SkASSERT(NULL != devTex);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001181
1182 const SkBitmap& bm = dev->accessBitmap(false);
1183 int w = bm.width();
1184 int h = bm.height();
1185
1186 GrAutoMatrix avm(fContext, GrMatrix::I());
1187
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001188 grPaint.getTextureSampler(kBitmapTextureIdx)->setClampNoFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +00001189
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001190 GrRect dstRect = GrRect::MakeXYWH(GrIntToScalar(x),
1191 GrIntToScalar(y),
1192 GrIntToScalar(w),
1193 GrIntToScalar(h));
1194 // The device being drawn may not fill up its texture (saveLayer uses
1195 // the approximate ).
1196 GrRect srcRect = GrRect::MakeWH(GR_Scalar1 * w / devTex->width(),
1197 GR_Scalar1 * h / devTex->height());
1198
1199 fContext->drawRectToRect(grPaint, dstRect, srcRect);
reed@google.comac10a2d2010-12-22 21:39:39 +00001200}
1201
1202///////////////////////////////////////////////////////////////////////////////
1203
1204// must be in SkCanvas::VertexMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +00001205static const GrPrimitiveType gVertexMode2PrimitiveType[] = {
1206 kTriangles_PrimitiveType,
1207 kTriangleStrip_PrimitiveType,
1208 kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +00001209};
1210
1211void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
1212 int vertexCount, const SkPoint vertices[],
1213 const SkPoint texs[], const SkColor colors[],
1214 SkXfermode* xmode,
1215 const uint16_t indices[], int indexCount,
1216 const SkPaint& paint) {
1217 CHECK_SHOULD_DRAW(draw);
1218
bsalomon@google.com5782d712011-01-21 21:03:59 +00001219 GrPaint grPaint;
1220 SkAutoCachedTexture act;
1221 // we ignore the shader if texs is null.
1222 if (NULL == texs) {
Scroggod757df22011-05-16 13:11:16 +00001223 if (!this->skPaint2GrPaintNoShader(paint,
1224 false,
1225 &grPaint,
1226 NULL == colors)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001227 return;
1228 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001229 } else {
reed@google.com1a2e8d22011-01-21 22:08:29 +00001230 if (!this->skPaint2GrPaintShader(paint, &act,
1231 *draw.fMatrix,
Scroggod757df22011-05-16 13:11:16 +00001232 &grPaint,
1233 NULL == colors)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001234 return;
1235 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001236 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001237
1238 if (NULL != xmode && NULL != texs && NULL != colors) {
1239 SkXfermode::Mode mode;
1240 if (!SkXfermode::IsMode(xmode, &mode) ||
1241 SkXfermode::kMultiply_Mode != mode) {
1242 SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
1243#if 0
1244 return
1245#endif
1246 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001247 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001248
1249#if SK_SCALAR_IS_GR_SCALAR
1250 // even if GrColor and SkColor byte offsets match we need
1251 // to perform pre-multiply.
1252 if (NULL == colors) {
1253 fContext->drawVertices(grPaint,
1254 gVertexMode2PrimitiveType[vmode],
1255 vertexCount,
1256 (GrPoint*) vertices,
1257 (GrPoint*) texs,
1258 NULL,
1259 indices,
1260 indexCount);
1261 } else
1262#endif
1263 {
1264 SkTexCoordSource texSrc(texs);
1265 SkColorSource colSrc(colors);
1266 SkIndexSource idxSrc(indices, indexCount);
1267
1268 fContext->drawCustomVertices(grPaint,
1269 gVertexMode2PrimitiveType[vmode],
1270 SkPositionSource(vertices, vertexCount),
1271 (NULL == texs) ? NULL : &texSrc,
1272 (NULL == colors) ? NULL : &colSrc,
1273 (NULL == indices) ? NULL : &idxSrc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001274 }
1275}
1276
1277///////////////////////////////////////////////////////////////////////////////
1278
1279static void GlyphCacheAuxProc(void* data) {
1280 delete (GrFontScaler*)data;
1281}
1282
1283static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) {
1284 void* auxData;
1285 GrFontScaler* scaler = NULL;
1286 if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
1287 scaler = (GrFontScaler*)auxData;
1288 }
1289 if (NULL == scaler) {
1290 scaler = new SkGrFontScaler(cache);
1291 cache->setAuxProc(GlyphCacheAuxProc, scaler);
1292 }
1293 return scaler;
1294}
1295
1296static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
1297 SkFixed fx, SkFixed fy,
1298 const SkGlyph& glyph) {
1299 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1300
1301 GrSkDrawProcs* procs = (GrSkDrawProcs*)state.fDraw->fProcs;
1302
1303 if (NULL == procs->fFontScaler) {
1304 procs->fFontScaler = get_gr_font_scaler(state.fCache);
1305 }
reed@google.com39ce0ac2011-04-08 15:42:19 +00001306
1307 /*
reed@google.com3b139f52011-06-07 17:56:25 +00001308 * What should we do with fy? (assuming horizontal/latin text)
reed@google.com39ce0ac2011-04-08 15:42:19 +00001309 *
reed@google.com3b139f52011-06-07 17:56:25 +00001310 * The raster code calls SkFixedFloorToFixed on it, as it does with fx.
1311 * It calls that rather than round, because our caller has already added
1312 * SK_FixedHalf, so that calling floor gives us the rounded integer.
1313 *
1314 * Test code between raster and gpu (they should draw the same)
1315 *
1316 * canvas->drawText("Hamburgefons", 12, 0, 16.5f, paint);
1317 *
1318 * Perhaps we should only perform this integralization if there is no
1319 * fExtMatrix...
reed@google.com39ce0ac2011-04-08 15:42:19 +00001320 */
reed@google.com3b139f52011-06-07 17:56:25 +00001321 fy = SkFixedFloorToFixed(fy);
1322
reed@google.comac10a2d2010-12-22 21:39:39 +00001323 procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0),
reed@google.com3b139f52011-06-07 17:56:25 +00001324 SkFixedFloorToFixed(fx), fy,
reed@google.comac10a2d2010-12-22 21:39:39 +00001325 procs->fFontScaler);
1326}
1327
bsalomon@google.com5782d712011-01-21 21:03:59 +00001328SkDrawProcs* SkGpuDevice::initDrawForText(GrTextContext* context) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001329
1330 // deferred allocation
1331 if (NULL == fDrawProcs) {
1332 fDrawProcs = new GrSkDrawProcs;
1333 fDrawProcs->fD1GProc = SkGPU_Draw1Glyph;
1334 fDrawProcs->fContext = fContext;
1335 }
1336
1337 // init our (and GL's) state
1338 fDrawProcs->fTextContext = context;
1339 fDrawProcs->fFontScaler = NULL;
1340 return fDrawProcs;
1341}
1342
1343void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
1344 size_t byteLength, SkScalar x, SkScalar y,
1345 const SkPaint& paint) {
1346 CHECK_SHOULD_DRAW(draw);
1347
1348 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1349 // this guy will just call our drawPath()
1350 draw.drawText((const char*)text, byteLength, x, y, paint);
1351 } else {
reed@google.comac10a2d2010-12-22 21:39:39 +00001352 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001353
1354 GrPaint grPaint;
1355 SkAutoCachedTexture act;
1356
Scroggod757df22011-05-16 13:11:16 +00001357 if (!this->skPaint2GrPaintShader(paint,
1358 &act,
1359 *draw.fMatrix,
1360 &grPaint,
1361 true)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001362 return;
1363 }
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001364 GrTextContext context(fContext, grPaint, draw.fExtMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001365 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001366 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
1367 }
1368}
1369
1370void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
1371 size_t byteLength, const SkScalar pos[],
1372 SkScalar constY, int scalarsPerPos,
1373 const SkPaint& paint) {
1374 CHECK_SHOULD_DRAW(draw);
1375
1376 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1377 // this guy will just call our drawPath()
1378 draw.drawPosText((const char*)text, byteLength, pos, constY,
1379 scalarsPerPos, paint);
1380 } else {
reed@google.comac10a2d2010-12-22 21:39:39 +00001381 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001382
1383 GrPaint grPaint;
1384 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +00001385 if (!this->skPaint2GrPaintShader(paint,
1386 &act,
1387 *draw.fMatrix,
1388 &grPaint,
1389 true)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001390 return;
1391 }
1392
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001393 GrTextContext context(fContext, grPaint, draw.fExtMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001394 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001395 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
1396 scalarsPerPos, paint);
1397 }
1398}
1399
1400void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
1401 size_t len, const SkPath& path,
1402 const SkMatrix* m, const SkPaint& paint) {
1403 CHECK_SHOULD_DRAW(draw);
1404
1405 SkASSERT(draw.fDevice == this);
1406 draw.drawTextOnPath((const char*)text, len, path, m, paint);
1407}
1408
1409///////////////////////////////////////////////////////////////////////////////
1410
reed@google.comf67e4cf2011-03-15 20:56:58 +00001411bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
1412 if (!paint.isLCDRenderText()) {
1413 // we're cool with the paint as is
1414 return false;
1415 }
1416
1417 if (paint.getShader() ||
1418 paint.getXfermode() || // unless its srcover
1419 paint.getMaskFilter() ||
1420 paint.getRasterizer() ||
1421 paint.getColorFilter() ||
1422 paint.getPathEffect() ||
1423 paint.isFakeBoldText() ||
1424 paint.getStyle() != SkPaint::kFill_Style) {
1425 // turn off lcd
1426 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
1427 flags->fHinting = paint.getHinting();
1428 return true;
1429 }
1430 // we're cool with the paint as is
1431 return false;
1432}
1433
1434///////////////////////////////////////////////////////////////////////////////
1435
reed@google.comac10a2d2010-12-22 21:39:39 +00001436SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001437 const GrSamplerState& sampler,
1438 GrTexture** texture,
bsalomon@google.come97f0852011-06-17 13:10:25 +00001439 TexType type) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001440 GrTexture* newTexture = NULL;
1441 GrTextureEntry* entry = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +00001442 GrContext* ctx = this->context();
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001443
bsalomon@google.come97f0852011-06-17 13:10:25 +00001444 if (kBitmap_TexType != type) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001445 const GrTextureDesc desc = {
1446 kRenderTarget_GrTextureFlagBit,
1447 kNone_GrAALevel,
1448 bitmap.width(),
1449 bitmap.height(),
1450 SkGr::Bitmap2PixelConfig(bitmap)
1451 };
bsalomon@google.come97f0852011-06-17 13:10:25 +00001452 if (kSaveLayerDeviceRenderTarget_TexType == type) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001453 // we know layers will only be drawn through drawDevice.
1454 // drawDevice has been made to work with content embedded in a
1455 // larger texture so its okay to use the approximate version.
1456 entry = ctx->findApproximateKeylessTexture(desc);
1457 } else {
bsalomon@google.come97f0852011-06-17 13:10:25 +00001458 SkASSERT(kDeviceRenderTarget_TexType == type);
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001459 entry = ctx->lockKeylessTexture(desc);
1460 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001461 } else {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001462 uint32_t p0, p1;
reed@google.comac10a2d2010-12-22 21:39:39 +00001463 p0 = bitmap.getGenerationID();
1464 p1 = bitmap.pixelRefOffset();
reed@google.comac10a2d2010-12-22 21:39:39 +00001465
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001466 GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
1467 entry = ctx->findAndLockTexture(&key, sampler);
reed@google.comac10a2d2010-12-22 21:39:39 +00001468
reed@google.comac10a2d2010-12-22 21:39:39 +00001469 if (NULL == entry) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001470 entry = sk_gr_create_bitmap_texture(ctx, &key, sampler, bitmap);
1471 if (NULL == entry) {
1472 GrPrintf("---- failed to create texture for cache [%d %d]\n",
1473 bitmap.width(), bitmap.height());
1474 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001475 }
1476 }
1477
1478 if (NULL != entry) {
1479 newTexture = entry->texture();
reed@google.comac10a2d2010-12-22 21:39:39 +00001480 if (texture) {
1481 *texture = newTexture;
1482 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001483 }
1484 return (TexCache*)entry;
1485}
1486
1487void SkGpuDevice::unlockCachedTexture(TexCache* cache) {
1488 this->context()->unlockTexture((GrTextureEntry*)cache);
1489}
1490
bsalomon@google.come97f0852011-06-17 13:10:25 +00001491SkDevice* SkGpuDevice::onCreateCompatibleDevice(SkBitmap::Config config,
1492 int width, int height,
1493 bool isOpaque,
1494 Usage usage) {
1495 return SkNEW_ARGS(SkGpuDevice,(this->context(), config,
1496 width, height, usage));
1497}
1498
1499
reed@google.com7b201d22011-01-11 18:59:23 +00001500///////////////////////////////////////////////////////////////////////////////
1501
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001502SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context,
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001503 GrRenderTarget* rootRenderTarget) {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001504 GrAssert(NULL != context);
1505 GrAssert(NULL != rootRenderTarget);
1506
1507 // check this now rather than passing this value to SkGpuDevice cons.
1508 // we want the rt that is bound *now* in the 3D API, not the one
1509 // at the time of newDevice.
1510 if (SkGpuDevice::Current3DApiRenderTarget() == rootRenderTarget) {
1511 fRootRenderTarget = context->createRenderTargetFrom3DApiState();
1512 } else {
1513 fRootRenderTarget = rootRenderTarget;
1514 rootRenderTarget->ref();
1515 }
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001516
1517 fContext = context;
reed@google.com7b201d22011-01-11 18:59:23 +00001518 context->ref();
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001519
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001520 fRootTexture = NULL;
1521}
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001522
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001523SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context, GrTexture* rootRenderTargetTexture) {
1524 GrAssert(NULL != context);
1525 GrAssert(NULL != rootRenderTargetTexture);
1526 GrAssert(NULL != rootRenderTargetTexture->asRenderTarget());
1527
1528 fRootTexture = rootRenderTargetTexture;
1529 rootRenderTargetTexture->ref();
1530
1531 fRootRenderTarget = rootRenderTargetTexture->asRenderTarget();
1532 fRootRenderTarget->ref();
1533
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001534 fContext = context;
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001535 context->ref();
reed@google.com7b201d22011-01-11 18:59:23 +00001536}
1537
1538SkGpuDeviceFactory::~SkGpuDeviceFactory() {
1539 fContext->unref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001540 fRootRenderTarget->unref();
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001541 GrSafeUnref(fRootTexture);
reed@google.com7b201d22011-01-11 18:59:23 +00001542}
1543
1544SkDevice* SkGpuDeviceFactory::newDevice(SkCanvas*, SkBitmap::Config config,
1545 int width, int height,
1546 bool isOpaque, bool isLayer) {
reed@google.comaf951c92011-06-16 19:10:39 +00001547 if (isLayer) {
1548 return SkNEW_ARGS(SkGpuDevice, (fContext, config, width, height));
1549 } else {
1550 return SkNEW_ARGS(SkGpuDevice, (fContext, fRootRenderTarget));
1551 }
reed@google.com7b201d22011-01-11 18:59:23 +00001552}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001553