blob: cda10d24ff757e31a5e048ea13cb108185ffe1fb [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
143SkGpuDevice::SkGpuDevice(GrContext* context, GrRenderTarget* renderTarget)
144: SkDevice(make_bitmap(context, renderTarget)) {
145
146 fNeedPrepareRenderTarget = false;
147 fDrawProcs = NULL;
148
149 fContext = context;
150 fContext->ref();
151
152 fCache = NULL;
153 fTexture = NULL;
154 fRenderTarget = NULL;
155 fNeedClear = false;
156
157 if (Current3DApiRenderTarget() == renderTarget) {
158 fRenderTarget = fContext->createRenderTargetFrom3DApiState();
159 } else {
160 fRenderTarget = renderTarget;
161 fRenderTarget->ref();
162 }
163
164 SkGrRenderTargetPixelRef* pr = new SkGrRenderTargetPixelRef(fRenderTarget);
165 this->setPixelRef(pr, 0)->unref();
166}
167
168SkGpuDevice::SkGpuDevice(GrContext* context, SkBitmap::Config config, int width,
bsalomon@google.come97f0852011-06-17 13:10:25 +0000169 int height, Usage usage)
reed@google.comaf951c92011-06-16 19:10:39 +0000170: SkDevice(config, width, height, false /*isOpaque*/) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000171 fNeedPrepareRenderTarget = false;
172 fDrawProcs = NULL;
173
reed@google.com7b201d22011-01-11 18:59:23 +0000174 fContext = context;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000175 fContext->ref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000176
177 fCache = NULL;
178 fTexture = NULL;
179 fRenderTarget = NULL;
180 fNeedClear = false;
181
reed@google.comaf951c92011-06-16 19:10:39 +0000182 if (config != SkBitmap::kRGB_565_Config) {
183 config = SkBitmap::kARGB_8888_Config;
184 }
185 SkBitmap bm;
186 bm.setConfig(config, width, height);
reed@google.comac10a2d2010-12-22 21:39:39 +0000187
188#if CACHE_LAYER_TEXTURES
bsalomon@google.come97f0852011-06-17 13:10:25 +0000189 TexType type = (kSaveLayer_Usage == usage) ?
190 kSaveLayerDeviceRenderTarget_TexType :
191 kDeviceRenderTarget_TexType;
reed@google.comaf951c92011-06-16 19:10:39 +0000192 fCache = this->lockCachedTexture(bm, GrSamplerState::ClampNoFilter(),
bsalomon@google.come97f0852011-06-17 13:10:25 +0000193 &fTexture, type);
reed@google.comaf951c92011-06-16 19:10:39 +0000194 if (fCache) {
195 SkASSERT(NULL != fTexture);
196 SkASSERT(NULL != fTexture->asRenderTarget());
197 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000198#else
reed@google.comaf951c92011-06-16 19:10:39 +0000199 const GrTextureDesc desc = {
200 kRenderTarget_GrTextureFlagBit,
201 kNone_GrAALevel,
202 width,
203 height,
204 SkGr::Bitmap2PixelConfig(bm)
205 };
reed@google.comac10a2d2010-12-22 21:39:39 +0000206
reed@google.comaf951c92011-06-16 19:10:39 +0000207 fTexture = fContext->createUncachedTexture(desc, NULL, 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000208#endif
reed@google.comaf951c92011-06-16 19:10:39 +0000209 if (NULL != fTexture) {
210 fRenderTarget = fTexture->asRenderTarget();
reed@google.comac10a2d2010-12-22 21:39:39 +0000211
reed@google.comaf951c92011-06-16 19:10:39 +0000212 GrAssert(NULL != fRenderTarget);
reed@google.comac10a2d2010-12-22 21:39:39 +0000213
reed@google.comaf951c92011-06-16 19:10:39 +0000214 // we defer the actual clear until our gainFocus()
215 fNeedClear = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000216
reed@google.comaf951c92011-06-16 19:10:39 +0000217 // wrap the bitmap with a pixelref to expose our texture
218 SkGrTexturePixelRef* pr = new SkGrTexturePixelRef(fTexture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000219 this->setPixelRef(pr, 0)->unref();
reed@google.comaf951c92011-06-16 19:10:39 +0000220 } else {
221 GrPrintf("--- failed to create gpu-offscreen [%d %d]\n",
222 width, height);
223 GrAssert(false);
reed@google.comac10a2d2010-12-22 21:39:39 +0000224 }
225}
226
227SkGpuDevice::~SkGpuDevice() {
228 if (fDrawProcs) {
229 delete fDrawProcs;
230 }
231
232 if (fCache) {
233 GrAssert(NULL != fTexture);
234 GrAssert(fRenderTarget == fTexture->asRenderTarget());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000235 fContext->unlockTexture((GrTextureEntry*)fCache);
reed@google.comac10a2d2010-12-22 21:39:39 +0000236 } else if (NULL != fTexture) {
237 GrAssert(!CACHE_LAYER_TEXTURES);
238 GrAssert(fRenderTarget == fTexture->asRenderTarget());
239 fTexture->unref();
240 } else if (NULL != fRenderTarget) {
241 fRenderTarget->unref();
242 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000243 fContext->unref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000244}
245
reed@google.comac10a2d2010-12-22 21:39:39 +0000246intptr_t SkGpuDevice::getLayerTextureHandle() const {
247 if (fTexture) {
248 return fTexture->getTextureHandle();
249 } else {
250 return 0;
251 }
252}
mike@reedtribe.orgea4ac972011-04-26 11:48:33 +0000253
254SkDeviceFactory* SkGpuDevice::onNewDeviceFactory() {
255 return SkNEW_ARGS(SkGpuDeviceFactory, (fContext, fRenderTarget));
256}
257
reed@google.comac10a2d2010-12-22 21:39:39 +0000258///////////////////////////////////////////////////////////////////////////////
259
260void SkGpuDevice::makeRenderTargetCurrent() {
261 fContext->setRenderTarget(fRenderTarget);
262 fContext->flush(true);
263 fNeedPrepareRenderTarget = true;
264}
265
266///////////////////////////////////////////////////////////////////////////////
267
268bool SkGpuDevice::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
269 SkIRect bounds;
270 bounds.set(0, 0, this->width(), this->height());
271 if (!bounds.intersect(srcRect)) {
272 return false;
273 }
274
275 const int w = bounds.width();
276 const int h = bounds.height();
277 SkBitmap tmp;
278 // note we explicitly specify our rowBytes to be snug (no gap between rows)
279 tmp.setConfig(SkBitmap::kARGB_8888_Config, w, h, w * 4);
280 if (!tmp.allocPixels()) {
281 return false;
282 }
283
Scroggo813c33c2011-04-07 20:56:21 +0000284 tmp.lockPixels();
reed@google.comac10a2d2010-12-22 21:39:39 +0000285
Scroggoeb176032011-04-07 21:11:49 +0000286 bool read = fContext->readRenderTargetPixels(fRenderTarget,
287 bounds.fLeft, bounds.fTop,
288 bounds.width(), bounds.height(),
289 kRGBA_8888_GrPixelConfig,
290 tmp.getPixels());
Scroggo813c33c2011-04-07 20:56:21 +0000291 tmp.unlockPixels();
292 if (!read) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000293 return false;
294 }
295
296 tmp.swap(*bitmap);
297 return true;
298}
299
300void SkGpuDevice::writePixels(const SkBitmap& bitmap, int x, int y) {
301 SkAutoLockPixels alp(bitmap);
302 if (!bitmap.readyToDraw()) {
303 return;
304 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000305 GrPixelConfig config = SkGr::BitmapConfig2PixelConfig(bitmap.config(),
306 bitmap.isOpaque());
reed@google.comac10a2d2010-12-22 21:39:39 +0000307 fContext->setRenderTarget(fRenderTarget);
308 // we aren't setting the clip or matrix, so mark as dirty
309 // we don't need to set them for this call and don't have them anyway
310 fNeedPrepareRenderTarget = true;
311
312 fContext->writePixels(x, y, bitmap.width(), bitmap.height(),
313 config, bitmap.getPixels(), bitmap.rowBytes());
314}
315
316///////////////////////////////////////////////////////////////////////////////
317
318static void convert_matrixclip(GrContext* context, const SkMatrix& matrix,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000319 const SkClipStack& clipStack,
reed@google.com6f8f2922011-03-04 22:27:10 +0000320 const SkRegion& clipRegion,
321 const SkIPoint& origin) {
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000322 context->setMatrix(matrix);
reed@google.comac10a2d2010-12-22 21:39:39 +0000323
324 SkGrClipIterator iter;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000325 iter.reset(clipStack);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000326 const SkIRect& skBounds = clipRegion.getBounds();
327 GrRect bounds;
328 bounds.setLTRB(GrIntToScalar(skBounds.fLeft),
329 GrIntToScalar(skBounds.fTop),
330 GrIntToScalar(skBounds.fRight),
331 GrIntToScalar(skBounds.fBottom));
reed@google.com6f8f2922011-03-04 22:27:10 +0000332 GrClip grc(&iter, GrIntToScalar(-origin.x()), GrIntToScalar(-origin.y()),
333 &bounds);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000334 context->setClip(grc);
reed@google.comac10a2d2010-12-22 21:39:39 +0000335}
336
337// call this ever each draw call, to ensure that the context reflects our state,
338// and not the state from some other canvas/device
339void SkGpuDevice::prepareRenderTarget(const SkDraw& draw) {
340 if (fNeedPrepareRenderTarget ||
bsalomon@google.com5782d712011-01-21 21:03:59 +0000341 fContext->getRenderTarget() != fRenderTarget) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000342
343 fContext->setRenderTarget(fRenderTarget);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000344 SkASSERT(draw.fClipStack);
345 convert_matrixclip(fContext, *draw.fMatrix,
reed@google.com6f8f2922011-03-04 22:27:10 +0000346 *draw.fClipStack, *draw.fClip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000347 fNeedPrepareRenderTarget = false;
348 }
349}
350
reed@google.com46799cd2011-02-22 20:56:26 +0000351void SkGpuDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& clip,
352 const SkClipStack& clipStack) {
353 this->INHERITED::setMatrixClip(matrix, clip, clipStack);
bsalomon@google.coma7bf6e22011-04-11 19:20:46 +0000354 // We don't need to set them now because the context may not reflect this device.
355 fNeedPrepareRenderTarget = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000356}
357
358void SkGpuDevice::gainFocus(SkCanvas* canvas, const SkMatrix& matrix,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000359 const SkRegion& clip, const SkClipStack& clipStack) {
360
reed@google.comac10a2d2010-12-22 21:39:39 +0000361 fContext->setRenderTarget(fRenderTarget);
362
bsalomon@google.comd302f142011-03-03 13:54:13 +0000363 this->INHERITED::gainFocus(canvas, matrix, clip, clipStack);
reed@google.comac10a2d2010-12-22 21:39:39 +0000364
reed@google.com6f8f2922011-03-04 22:27:10 +0000365 convert_matrixclip(fContext, matrix, clipStack, clip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000366
367 if (fNeedClear) {
bsalomon@google.com31a58402011-04-27 21:00:02 +0000368 fContext->clear(NULL, 0x0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000369 fNeedClear = false;
370 }
371}
372
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000373bool SkGpuDevice::bindDeviceAsTexture(GrPaint* paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000374 if (NULL != fTexture) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000375 paint->setTexture(kBitmapTextureIdx, fTexture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000376 return true;
377 }
378 return false;
379}
380
381///////////////////////////////////////////////////////////////////////////////
382
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000383SK_COMPILE_ASSERT(SkShader::kNone_BitmapType == 0, shader_type_mismatch);
384SK_COMPILE_ASSERT(SkShader::kDefault_BitmapType == 1, shader_type_mismatch);
385SK_COMPILE_ASSERT(SkShader::kRadial_BitmapType == 2, shader_type_mismatch);
386SK_COMPILE_ASSERT(SkShader::kSweep_BitmapType == 3, shader_type_mismatch);
387SK_COMPILE_ASSERT(SkShader::kTwoPointRadial_BitmapType == 4,
388 shader_type_mismatch);
389SK_COMPILE_ASSERT(SkShader::kLast_BitmapType == 4, shader_type_mismatch);
reed@google.comac10a2d2010-12-22 21:39:39 +0000390
bsalomon@google.com5782d712011-01-21 21:03:59 +0000391static const GrSamplerState::SampleMode sk_bmp_type_to_sample_mode[] = {
392 (GrSamplerState::SampleMode) -1, // kNone_BitmapType
393 GrSamplerState::kNormal_SampleMode, // kDefault_BitmapType
394 GrSamplerState::kRadial_SampleMode, // kRadial_BitmapType
395 GrSamplerState::kSweep_SampleMode, // kSweep_BitmapType
396 GrSamplerState::kRadial2_SampleMode, // kTwoPointRadial_BitmapType
397};
398
399bool SkGpuDevice::skPaint2GrPaintNoShader(const SkPaint& skPaint,
400 bool justAlpha,
Scroggod757df22011-05-16 13:11:16 +0000401 GrPaint* grPaint,
402 bool constantColor) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000403
404 grPaint->fDither = skPaint.isDither();
405 grPaint->fAntiAlias = skPaint.isAntiAlias();
406
407 SkXfermode::Coeff sm = SkXfermode::kOne_Coeff;
408 SkXfermode::Coeff dm = SkXfermode::kISA_Coeff;
409
410 SkXfermode* mode = skPaint.getXfermode();
411 if (mode) {
412 if (!mode->asCoeff(&sm, &dm)) {
reed@google.com1a2e8d22011-01-21 22:08:29 +0000413 SkDEBUGCODE(SkDebugf("Unsupported xfer mode.\n");)
bsalomon@google.com5782d712011-01-21 21:03:59 +0000414#if 0
415 return false;
416#endif
417 }
418 }
419 grPaint->fSrcBlendCoeff = sk_blend_to_grblend(sm);
420 grPaint->fDstBlendCoeff = sk_blend_to_grblend(dm);
421
422 if (justAlpha) {
423 uint8_t alpha = skPaint.getAlpha();
424 grPaint->fColor = GrColorPackRGBA(alpha, alpha, alpha, alpha);
Scroggod757df22011-05-16 13:11:16 +0000425 // justAlpha is currently set to true only if there is a texture,
426 // so constantColor should not also be true.
427 GrAssert(!constantColor);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000428 } else {
429 grPaint->fColor = SkGr::SkColor2GrColor(skPaint.getColor());
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000430 grPaint->setTexture(kShaderTextureIdx, NULL);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000431 }
Scroggo97c88c22011-05-11 14:05:25 +0000432 SkColorFilter* colorFilter = skPaint.getColorFilter();
433 SkColor color;
434 SkXfermode::Mode filterMode;
435 if (colorFilter != NULL && colorFilter->asColorMode(&color, &filterMode)) {
Scroggod757df22011-05-16 13:11:16 +0000436 if (!constantColor) {
437 grPaint->fColorFilterColor = SkGr::SkColor2GrColor(color);
438 grPaint->fColorFilterXfermode = filterMode;
439 return true;
440 }
441 SkColor filtered = colorFilter->filterColor(skPaint.getColor());
442 grPaint->fColor = SkGr::SkColor2GrColor(filtered);
Scroggo97c88c22011-05-11 14:05:25 +0000443 }
Scroggod757df22011-05-16 13:11:16 +0000444 grPaint->resetColorFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +0000445 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000446}
447
bsalomon@google.com5782d712011-01-21 21:03:59 +0000448bool SkGpuDevice::skPaint2GrPaintShader(const SkPaint& skPaint,
449 SkAutoCachedTexture* act,
450 const SkMatrix& ctm,
Scroggod757df22011-05-16 13:11:16 +0000451 GrPaint* grPaint,
452 bool constantColor) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000453
bsalomon@google.com5782d712011-01-21 21:03:59 +0000454 SkASSERT(NULL != act);
reed@google.comac10a2d2010-12-22 21:39:39 +0000455
bsalomon@google.com5782d712011-01-21 21:03:59 +0000456 SkShader* shader = skPaint.getShader();
reed@google.comac10a2d2010-12-22 21:39:39 +0000457 if (NULL == shader) {
Scroggod757df22011-05-16 13:11:16 +0000458 return this->skPaint2GrPaintNoShader(skPaint,
459 false,
460 grPaint,
461 constantColor);
462 } else if (!this->skPaint2GrPaintNoShader(skPaint, true, grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000463 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000464 }
465
bsalomon@google.com5782d712011-01-21 21:03:59 +0000466 SkPaint noAlphaPaint(skPaint);
467 noAlphaPaint.setAlpha(255);
468 shader->setContext(this->accessBitmap(false), noAlphaPaint, ctm);
reed@google.comac10a2d2010-12-22 21:39:39 +0000469
reed@google.comac10a2d2010-12-22 21:39:39 +0000470 SkBitmap bitmap;
471 SkMatrix matrix;
472 SkShader::TileMode tileModes[2];
473 SkScalar twoPointParams[3];
474 SkShader::BitmapType bmptype = shader->asABitmap(&bitmap, &matrix,
475 tileModes, twoPointParams);
476
bsalomon@google.com5782d712011-01-21 21:03:59 +0000477 GrSamplerState::SampleMode sampleMode = sk_bmp_type_to_sample_mode[bmptype];
478 if (-1 == sampleMode) {
479 SkDebugf("shader->asABitmap() == kNone_BitmapType\n");
480 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000481 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000482 GrSamplerState* sampler = grPaint->getTextureSampler(kShaderTextureIdx);
483 sampler->setSampleMode(sampleMode);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000484 if (skPaint.isFilterBitmap()) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000485 sampler->setFilter(GrSamplerState::kBilinear_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000486 } else {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000487 sampler->setFilter(GrSamplerState::kNearest_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000488 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000489 sampler->setWrapX(sk_tile_mode_to_grwrap(tileModes[0]));
490 sampler->setWrapY(sk_tile_mode_to_grwrap(tileModes[1]));
reed@google.comac10a2d2010-12-22 21:39:39 +0000491 if (GrSamplerState::kRadial2_SampleMode == sampleMode) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000492 sampler->setRadial2Params(twoPointParams[0],
493 twoPointParams[1],
494 twoPointParams[2] < 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000495 }
496
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000497 GrTexture* texture = act->set(this, bitmap, *sampler);
reed@google.comac10a2d2010-12-22 21:39:39 +0000498 if (NULL == texture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000499 SkDebugf("Couldn't convert bitmap to texture.\n");
500 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000501 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000502 grPaint->setTexture(kShaderTextureIdx, texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000503
504 // since our texture coords will be in local space, we wack the texture
505 // matrix to map them back into 0...1 before we load it
506 SkMatrix localM;
507 if (shader->getLocalMatrix(&localM)) {
508 SkMatrix inverse;
509 if (localM.invert(&inverse)) {
510 matrix.preConcat(inverse);
511 }
512 }
513 if (SkShader::kDefault_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000514 GrScalar sx = GrFixedToScalar(GR_Fixed1 / bitmap.width());
515 GrScalar sy = GrFixedToScalar(GR_Fixed1 / bitmap.height());
reed@google.comac10a2d2010-12-22 21:39:39 +0000516 matrix.postScale(sx, sy);
reed@google.comac10a2d2010-12-22 21:39:39 +0000517 } else if (SkShader::kRadial_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000518 GrScalar s = GrFixedToScalar(GR_Fixed1 / bitmap.width());
reed@google.comac10a2d2010-12-22 21:39:39 +0000519 matrix.postScale(s, s);
520 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000521 sampler->setMatrix(matrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000522
523 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000524}
525
526///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com5782d712011-01-21 21:03:59 +0000527
528class SkPositionSource {
529public:
530 SkPositionSource(const SkPoint* points, int count)
531 : fPoints(points), fCount(count) {}
532
533 int count() const { return fCount; }
534
535 void writeValue(int i, GrPoint* dstPosition) const {
536 SkASSERT(i < fCount);
537 dstPosition->fX = SkScalarToGrScalar(fPoints[i].fX);
538 dstPosition->fY = SkScalarToGrScalar(fPoints[i].fY);
539 }
540private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000541 const SkPoint* fPoints;
bsalomon@google.com19628322011-02-03 21:30:17 +0000542 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000543};
544
545class SkTexCoordSource {
546public:
547 SkTexCoordSource(const SkPoint* coords)
548 : fCoords(coords) {}
549
550 void writeValue(int i, GrPoint* dstCoord) const {
551 dstCoord->fX = SkScalarToGrScalar(fCoords[i].fX);
552 dstCoord->fY = SkScalarToGrScalar(fCoords[i].fY);
553 }
554private:
555 const SkPoint* fCoords;
556};
557
558class SkColorSource {
559public:
560 SkColorSource(const SkColor* colors) : fColors(colors) {}
561
562 void writeValue(int i, GrColor* dstColor) const {
563 *dstColor = SkGr::SkColor2GrColor(fColors[i]);
564 }
565private:
566 const SkColor* fColors;
567};
568
569class SkIndexSource {
570public:
571 SkIndexSource(const uint16_t* indices, int count)
572 : fIndices(indices), fCount(count) {
573 }
574
575 int count() const { return fCount; }
576
577 void writeValue(int i, uint16_t* dstIndex) const {
578 *dstIndex = fIndices[i];
579 }
580
581private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000582 const uint16_t* fIndices;
bsalomon@google.com19628322011-02-03 21:30:17 +0000583 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000584};
585
586///////////////////////////////////////////////////////////////////////////////
587
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000588#if 0 // not currently being used so don't compile,
589
bsalomon@google.com5782d712011-01-21 21:03:59 +0000590// can be used for positions or texture coordinates
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000591
bsalomon@google.com5782d712011-01-21 21:03:59 +0000592class SkRectFanSource {
593public:
594 SkRectFanSource(const SkRect& rect) : fRect(rect) {}
595
596 int count() const { return 4; }
597
598 void writeValue(int i, GrPoint* dstPoint) const {
599 SkASSERT(i < 4);
600 dstPoint->fX = SkScalarToGrScalar((i % 3) ? fRect.fRight :
601 fRect.fLeft);
602 dstPoint->fY = SkScalarToGrScalar((i < 2) ? fRect.fTop :
603 fRect.fBottom);
604 }
605private:
606 const SkRect& fRect;
607};
608
609class SkIRectFanSource {
610public:
611 SkIRectFanSource(const SkIRect& rect) : fRect(rect) {}
612
613 int count() const { return 4; }
614
615 void writeValue(int i, GrPoint* dstPoint) const {
616 SkASSERT(i < 4);
617 dstPoint->fX = (i % 3) ? GrIntToScalar(fRect.fRight) :
618 GrIntToScalar(fRect.fLeft);
619 dstPoint->fY = (i < 2) ? GrIntToScalar(fRect.fTop) :
620 GrIntToScalar(fRect.fBottom);
621 }
622private:
623 const SkIRect& fRect;
624};
625
626class SkMatRectFanSource {
627public:
628 SkMatRectFanSource(const SkRect& rect, const SkMatrix& matrix)
629 : fRect(rect), fMatrix(matrix) {}
630
631 int count() const { return 4; }
632
633 void writeValue(int i, GrPoint* dstPoint) const {
634 SkASSERT(i < 4);
635
636#if SK_SCALAR_IS_GR_SCALAR
637 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
638 (i < 2) ? fRect.fTop : fRect.fBottom,
639 (SkPoint*)dstPoint);
640#else
641 SkPoint dst;
642 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
643 (i < 2) ? fRect.fTop : fRect.fBottom,
644 &dst);
645 dstPoint->fX = SkScalarToGrScalar(dst.fX);
646 dstPoint->fY = SkScalarToGrScalar(dst.fY);
647#endif
648 }
649private:
650 const SkRect& fRect;
651 const SkMatrix& fMatrix;
652};
653
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000654#endif
655
reed@google.comac10a2d2010-12-22 21:39:39 +0000656///////////////////////////////////////////////////////////////////////////////
657
bsalomon@google.com398109c2011-04-14 18:40:27 +0000658void SkGpuDevice::clear(SkColor color) {
bsalomon@google.com31a58402011-04-27 21:00:02 +0000659 fContext->clear(NULL, color);
bsalomon@google.com398109c2011-04-14 18:40:27 +0000660}
661
reed@google.comac10a2d2010-12-22 21:39:39 +0000662void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
663 CHECK_SHOULD_DRAW(draw);
664
bsalomon@google.com5782d712011-01-21 21:03:59 +0000665 GrPaint grPaint;
666 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000667 if (!this->skPaint2GrPaintShader(paint,
668 &act,
669 *draw.fMatrix,
670 &grPaint,
671 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000672 return;
673 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000674
675 fContext->drawPaint(grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000676}
677
678// must be in SkCanvas::PointMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +0000679static const GrPrimitiveType gPointMode2PrimtiveType[] = {
680 kPoints_PrimitiveType,
681 kLines_PrimitiveType,
682 kLineStrip_PrimitiveType
reed@google.comac10a2d2010-12-22 21:39:39 +0000683};
684
685void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000686 size_t count, const SkPoint pts[], const SkPaint& paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000687 CHECK_SHOULD_DRAW(draw);
688
689 SkScalar width = paint.getStrokeWidth();
690 if (width < 0) {
691 return;
692 }
693
694 // we only handle hairlines here, else we let the SkDraw call our drawPath()
695 if (width > 0) {
696 draw.drawPoints(mode, count, pts, paint, true);
697 return;
698 }
699
bsalomon@google.com5782d712011-01-21 21:03:59 +0000700 GrPaint grPaint;
701 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000702 if (!this->skPaint2GrPaintShader(paint,
703 &act,
704 *draw.fMatrix,
705 &grPaint,
706 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000707 return;
708 }
709
reed@google.comac10a2d2010-12-22 21:39:39 +0000710#if SK_SCALAR_IS_GR_SCALAR
bsalomon@google.com5782d712011-01-21 21:03:59 +0000711 fContext->drawVertices(grPaint,
712 gPointMode2PrimtiveType[mode],
713 count,
714 (GrPoint*)pts,
715 NULL,
716 NULL,
717 NULL,
718 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000719#else
bsalomon@google.com5782d712011-01-21 21:03:59 +0000720 fContext->drawCustomVertices(grPaint,
721 gPointMode2PrimtiveType[mode],
722 SkPositionSource(pts, count));
reed@google.comac10a2d2010-12-22 21:39:39 +0000723#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000724}
725
reed@google.comc9aa5872011-04-05 21:05:37 +0000726///////////////////////////////////////////////////////////////////////////////
727
reed@google.comac10a2d2010-12-22 21:39:39 +0000728void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
729 const SkPaint& paint) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000730 CHECK_SHOULD_DRAW(draw);
731
732 bool doStroke = paint.getStyle() == SkPaint::kStroke_Style;
733 SkScalar width = paint.getStrokeWidth();
734
735 /*
736 We have special code for hairline strokes, miter-strokes, and fills.
737 Anything else we just call our path code.
738 */
739 bool usePath = doStroke && width > 0 &&
740 paint.getStrokeJoin() != SkPaint::kMiter_Join;
741 // another reason we might need to call drawPath...
742 if (paint.getMaskFilter()) {
743 usePath = true;
744 }
reed@google.com67db6642011-05-26 11:46:35 +0000745 // until we aa rotated rects...
746 if (!usePath && paint.isAntiAlias() && !draw.fMatrix->rectStaysRect()) {
747 usePath = true;
748 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000749
750 if (usePath) {
751 SkPath path;
752 path.addRect(rect);
753 this->drawPath(draw, path, paint, NULL, true);
754 return;
755 }
756
757 GrPaint grPaint;
758 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000759 if (!this->skPaint2GrPaintShader(paint,
760 &act,
761 *draw.fMatrix,
762 &grPaint,
763 true)) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000764 return;
765 }
reed@google.com20efde72011-05-09 17:00:02 +0000766 fContext->drawRect(grPaint, rect, doStroke ? width : -1);
reed@google.comac10a2d2010-12-22 21:39:39 +0000767}
768
reed@google.com69302852011-02-16 18:08:07 +0000769#include "SkMaskFilter.h"
770#include "SkBounder.h"
771
reed@google.com69302852011-02-16 18:08:07 +0000772static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
773 SkMaskFilter* filter, const SkMatrix& matrix,
774 const SkRegion& clip, SkBounder* bounder,
775 GrPaint* grp) {
776 SkMask srcM, dstM;
777
778 if (!SkDraw::DrawToMask(path, &clip.getBounds(), filter, &matrix, &srcM,
779 SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
780 return false;
781 }
782
783 SkAutoMaskImage autoSrc(&srcM, false);
784
785 if (!filter->filterMask(&dstM, srcM, matrix, NULL)) {
786 return false;
787 }
788 // this will free-up dstM when we're done (allocated in filterMask())
789 SkAutoMaskImage autoDst(&dstM, false);
790
791 if (clip.quickReject(dstM.fBounds)) {
792 return false;
793 }
794 if (bounder && !bounder->doIRect(dstM.fBounds)) {
795 return false;
796 }
797
798 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
799 // the current clip (and identity matrix) and grpaint settings
800
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000801 // used to compute inverse view, if necessary
802 GrMatrix ivm = context->getMatrix();
803
reed@google.com0c219b62011-02-16 21:31:18 +0000804 GrAutoMatrix avm(context, GrMatrix::I());
reed@google.com69302852011-02-16 18:08:07 +0000805
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000806 const GrTextureDesc desc = {
807 kNone_GrTextureFlags,
808 kNone_GrAALevel,
reed@google.com69302852011-02-16 18:08:07 +0000809 dstM.fBounds.width(),
810 dstM.fBounds.height(),
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000811 kAlpha_8_GrPixelConfig
reed@google.com69302852011-02-16 18:08:07 +0000812 };
813
814 GrTexture* texture = context->createUncachedTexture(desc, dstM.fImage,
815 dstM.fRowBytes);
816 if (NULL == texture) {
817 return false;
818 }
819
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000820 if (grp->hasTextureOrMask() && ivm.invert(&ivm)) {
821 grp->preConcatActiveSamplerMatrices(ivm);
822 }
823
824 static const int MASK_IDX = GrPaint::kMaxMasks - 1;
825 // we assume the last mask index is available for use
826 GrAssert(NULL == grp->getMask(MASK_IDX));
827 grp->setMask(MASK_IDX, texture);
reed@google.com0c219b62011-02-16 21:31:18 +0000828 texture->unref();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000829 grp->getMaskSampler(MASK_IDX)->setClampNoFilter();
reed@google.com69302852011-02-16 18:08:07 +0000830
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000831 GrRect d;
832 d.setLTRB(GrIntToScalar(dstM.fBounds.fLeft),
reed@google.com0c219b62011-02-16 21:31:18 +0000833 GrIntToScalar(dstM.fBounds.fTop),
834 GrIntToScalar(dstM.fBounds.fRight),
835 GrIntToScalar(dstM.fBounds.fBottom));
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000836
837 GrMatrix m;
838 m.setTranslate(-dstM.fBounds.fLeft, -dstM.fBounds.fTop);
839 m.postIDiv(dstM.fBounds.width(), dstM.fBounds.height());
840 grp->getMaskSampler(MASK_IDX)->setMatrix(m);
841
842 context->drawRect(*grp, d);
reed@google.com69302852011-02-16 18:08:07 +0000843 return true;
844}
reed@google.com69302852011-02-16 18:08:07 +0000845
reed@google.com0c219b62011-02-16 21:31:18 +0000846void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
reed@google.comac10a2d2010-12-22 21:39:39 +0000847 const SkPaint& paint, const SkMatrix* prePathMatrix,
848 bool pathIsMutable) {
849 CHECK_SHOULD_DRAW(draw);
850
bsalomon@google.com5782d712011-01-21 21:03:59 +0000851 GrPaint grPaint;
852 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000853 if (!this->skPaint2GrPaintShader(paint,
854 &act,
855 *draw.fMatrix,
856 &grPaint,
857 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000858 return;
859 }
860
reed@google.com0c219b62011-02-16 21:31:18 +0000861 // BEGIN lift from SkDraw::drawPath()
862
863 SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
864 bool doFill = true;
865 SkPath tmpPath;
reed@google.comac10a2d2010-12-22 21:39:39 +0000866
867 if (prePathMatrix) {
reed@google.come3445642011-02-16 23:20:39 +0000868 SkPath* result = pathPtr;
reed@google.com0c219b62011-02-16 21:31:18 +0000869
reed@google.come3445642011-02-16 23:20:39 +0000870 if (!pathIsMutable) {
871 result = &tmpPath;
872 pathIsMutable = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000873 }
reed@google.come3445642011-02-16 23:20:39 +0000874 // should I push prePathMatrix on our MV stack temporarily, instead
875 // of applying it here? See SkDraw.cpp
876 pathPtr->transform(*prePathMatrix, result);
877 pathPtr = result;
reed@google.comac10a2d2010-12-22 21:39:39 +0000878 }
reed@google.com0c219b62011-02-16 21:31:18 +0000879 // at this point we're done with prePathMatrix
880 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
reed@google.comac10a2d2010-12-22 21:39:39 +0000881
bsalomon@google.com04de7822011-03-25 18:04:43 +0000882 // This "if" is not part of the SkDraw::drawPath() lift.
883 // When we get a 1.0 wide stroke we hairline stroke it instead of creating
884 // a new stroked-path. This is motivated by canvas2D sites that draw
885 // lines as 1.0 wide stroked paths. We can consider doing an alpha-modulated-
886 // hairline for width < 1.0 when AA is enabled.
887 static const int gMatrixMask = ~(SkMatrix::kIdentity_Mask |
888 SkMatrix::kTranslate_Mask);
889 if (!paint.getPathEffect() &&
890 SkPaint::kStroke_Style == paint.getStyle() &&
891 !(draw.fMatrix->getType() & gMatrixMask) &&
892 SK_Scalar1 == paint.getStrokeWidth()) {
893 doFill = false;
894 }
895
896 if (doFill && (paint.getPathEffect() ||
897 paint.getStyle() != SkPaint::kFill_Style)) {
reed@google.com0c219b62011-02-16 21:31:18 +0000898 doFill = paint.getFillPath(*pathPtr, &tmpPath);
899 pathPtr = &tmpPath;
900 }
901
902 // END lift from SkDraw::drawPath()
903
reed@google.com69302852011-02-16 18:08:07 +0000904 if (paint.getMaskFilter()) {
reed@google.com0c219b62011-02-16 21:31:18 +0000905 // avoid possibly allocating a new path in transform if we can
906 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
907
908 // transform the path into device space
reed@google.come3445642011-02-16 23:20:39 +0000909 pathPtr->transform(*draw.fMatrix, devPathPtr);
reed@google.com0c219b62011-02-16 21:31:18 +0000910
911 drawWithMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
reed@google.com69302852011-02-16 18:08:07 +0000912 *draw.fMatrix, *draw.fClip, draw.fBounder, &grPaint);
913 return;
914 }
reed@google.com69302852011-02-16 18:08:07 +0000915
bsalomon@google.comffca4002011-02-22 20:34:01 +0000916 GrPathFill fill = kHairLine_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000917
reed@google.com0c219b62011-02-16 21:31:18 +0000918 if (doFill) {
919 switch (pathPtr->getFillType()) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000920 case SkPath::kWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000921 fill = kWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000922 break;
923 case SkPath::kEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000924 fill = kEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000925 break;
926 case SkPath::kInverseWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000927 fill = kInverseWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000928 break;
929 case SkPath::kInverseEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000930 fill = kInverseEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000931 break;
932 default:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000933 SkDebugf("Unsupported path fill type\n");
reed@google.comac10a2d2010-12-22 21:39:39 +0000934 return;
935 }
936 }
937
reed@google.com07f3ee12011-05-16 17:21:57 +0000938 fContext->drawPath(grPaint, *pathPtr, fill);
reed@google.comac10a2d2010-12-22 21:39:39 +0000939}
940
reed@google.comac10a2d2010-12-22 21:39:39 +0000941void SkGpuDevice::drawBitmap(const SkDraw& draw,
942 const SkBitmap& bitmap,
943 const SkIRect* srcRectPtr,
944 const SkMatrix& m,
945 const SkPaint& paint) {
946 CHECK_SHOULD_DRAW(draw);
947
948 SkIRect srcRect;
949 if (NULL == srcRectPtr) {
950 srcRect.set(0, 0, bitmap.width(), bitmap.height());
951 } else {
952 srcRect = *srcRectPtr;
953 }
954
bsalomon@google.com5782d712011-01-21 21:03:59 +0000955 GrPaint grPaint;
Scroggod757df22011-05-16 13:11:16 +0000956 if (!this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000957 return;
958 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000959 GrSamplerState* sampler = grPaint.getTextureSampler(kBitmapTextureIdx);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000960 if (paint.isFilterBitmap()) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000961 sampler->setFilter(GrSamplerState::kBilinear_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000962 } else {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000963 sampler->setFilter(GrSamplerState::kNearest_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000964 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000965
bsalomon@google.com91958362011-06-13 17:58:13 +0000966 const int maxTextureSize = fContext->getMaxTextureSize();
967 if (bitmap.getTexture() || (bitmap.width() <= maxTextureSize &&
968 bitmap.height() <= maxTextureSize)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000969 // take the fast case
bsalomon@google.com5782d712011-01-21 21:03:59 +0000970 this->internalDrawBitmap(draw, bitmap, srcRect, m, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000971 return;
972 }
973
974 // undo the translate done by SkCanvas
975 int DX = SkMax32(0, srcRect.fLeft);
976 int DY = SkMax32(0, srcRect.fTop);
977 // compute clip bounds in local coordinates
978 SkIRect clipRect;
979 {
980 SkRect r;
981 r.set(draw.fClip->getBounds());
982 SkMatrix matrix, inverse;
983 matrix.setConcat(*draw.fMatrix, m);
984 if (!matrix.invert(&inverse)) {
985 return;
986 }
987 inverse.mapRect(&r);
988 r.roundOut(&clipRect);
989 // apply the canvas' translate to our local clip
990 clipRect.offset(DX, DY);
991 }
992
bsalomon@google.com91958362011-06-13 17:58:13 +0000993 int nx = bitmap.width() / maxTextureSize;
994 int ny = bitmap.height() / maxTextureSize;
reed@google.comac10a2d2010-12-22 21:39:39 +0000995 for (int x = 0; x <= nx; x++) {
996 for (int y = 0; y <= ny; y++) {
997 SkIRect tileR;
bsalomon@google.com91958362011-06-13 17:58:13 +0000998 tileR.set(x * maxTextureSize, y * maxTextureSize,
999 (x + 1) * maxTextureSize, (y + 1) * maxTextureSize);
reed@google.comac10a2d2010-12-22 21:39:39 +00001000 if (!SkIRect::Intersects(tileR, clipRect)) {
1001 continue;
1002 }
1003
1004 SkIRect srcR = tileR;
1005 if (!srcR.intersect(srcRect)) {
1006 continue;
1007 }
1008
1009 SkBitmap tmpB;
1010 if (bitmap.extractSubset(&tmpB, tileR)) {
1011 // now offset it to make it "local" to our tmp bitmap
1012 srcR.offset(-tileR.fLeft, -tileR.fTop);
1013
1014 SkMatrix tmpM(m);
1015 {
1016 int dx = tileR.fLeft - DX + SkMax32(0, srcR.fLeft);
1017 int dy = tileR.fTop - DY + SkMax32(0, srcR.fTop);
1018 tmpM.preTranslate(SkIntToScalar(dx), SkIntToScalar(dy));
1019 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001020 this->internalDrawBitmap(draw, tmpB, srcR, tmpM, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +00001021 }
1022 }
1023 }
1024}
1025
1026/*
1027 * This is called by drawBitmap(), which has to handle images that may be too
1028 * large to be represented by a single texture.
1029 *
bsalomon@google.com5782d712011-01-21 21:03:59 +00001030 * internalDrawBitmap assumes that the specified bitmap will fit in a texture
1031 * and that non-texture portion of the GrPaint has already been setup.
reed@google.comac10a2d2010-12-22 21:39:39 +00001032 */
1033void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
1034 const SkBitmap& bitmap,
1035 const SkIRect& srcRect,
1036 const SkMatrix& m,
bsalomon@google.com5782d712011-01-21 21:03:59 +00001037 GrPaint* grPaint) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001038 SkASSERT(bitmap.width() <= fContext->getMaxTextureSize() &&
1039 bitmap.height() <= fContext->getMaxTextureSize());
reed@google.comac10a2d2010-12-22 21:39:39 +00001040
1041 SkAutoLockPixels alp(bitmap);
1042 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
1043 return;
1044 }
1045
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001046 GrSamplerState* sampler = grPaint->getTextureSampler(kBitmapTextureIdx);
1047
1048 sampler->setWrapX(GrSamplerState::kClamp_WrapMode);
1049 sampler->setWrapY(GrSamplerState::kClamp_WrapMode);
1050 sampler->setSampleMode(GrSamplerState::kNormal_SampleMode);
1051 sampler->setMatrix(GrMatrix::I());
reed@google.comac10a2d2010-12-22 21:39:39 +00001052
1053 GrTexture* texture;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001054 SkAutoCachedTexture act(this, bitmap, *sampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +00001055 if (NULL == texture) {
1056 return;
1057 }
1058
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001059 grPaint->setTexture(kShaderTextureIdx, texture);
reed@google.com46799cd2011-02-22 20:56:26 +00001060
reed@google.com20efde72011-05-09 17:00:02 +00001061 GrRect dstRect = SkRect::MakeWH(GrIntToScalar(srcRect.width()),
1062 GrIntToScalar(srcRect.height()));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001063 GrRect paintRect;
junov@google.com6acc9b32011-05-16 18:32:07 +00001064 paintRect.setLTRB(GrFixedToScalar((srcRect.fLeft << 16) / bitmap.width()),
1065 GrFixedToScalar((srcRect.fTop << 16) / bitmap.height()),
1066 GrFixedToScalar((srcRect.fRight << 16) / bitmap.width()),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001067 GrFixedToScalar((srcRect.fBottom << 16) / bitmap.height()));
reed@google.comac10a2d2010-12-22 21:39:39 +00001068
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001069 if (GrSamplerState::kNearest_Filter != sampler->getFilter() &&
junov@google.com6acc9b32011-05-16 18:32:07 +00001070 (srcRect.width() < bitmap.width() ||
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001071 srcRect.height() < bitmap.height())) {
junov@google.com6acc9b32011-05-16 18:32:07 +00001072 // If drawing a subrect of the bitmap and filtering is enabled,
1073 // use a constrained texture domain to avoid color bleeding
1074 GrScalar left, top, right, bottom;
1075 if (srcRect.width() > 1) {
1076 GrScalar border = GR_ScalarHalf / bitmap.width();
1077 left = paintRect.left() + border;
1078 right = paintRect.right() - border;
1079 } else {
1080 left = right = GrScalarHalf(paintRect.left() + paintRect.right());
1081 }
1082 if (srcRect.height() > 1) {
1083 GrScalar border = GR_ScalarHalf / bitmap.height();
1084 top = paintRect.top() + border;
1085 bottom = paintRect.bottom() - border;
1086 } else {
1087 top = bottom = GrScalarHalf(paintRect.top() + paintRect.bottom());
1088 }
1089 GrRect textureDomain;
1090 textureDomain.setLTRB(left, top, right, bottom);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001091 sampler->setTextureDomain(textureDomain);
junov@google.com6acc9b32011-05-16 18:32:07 +00001092 }
1093
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001094 fContext->drawRectToRect(*grPaint, dstRect, paintRect, &m);
reed@google.comac10a2d2010-12-22 21:39:39 +00001095}
1096
1097void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
1098 int left, int top, const SkPaint& paint) {
1099 CHECK_SHOULD_DRAW(draw);
1100
1101 SkAutoLockPixels alp(bitmap);
1102 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
1103 return;
1104 }
1105
bsalomon@google.com5782d712011-01-21 21:03:59 +00001106 GrPaint grPaint;
Scroggod757df22011-05-16 13:11:16 +00001107 if(!this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001108 return;
1109 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001110
bsalomon@google.com5782d712011-01-21 21:03:59 +00001111 GrAutoMatrix avm(fContext, GrMatrix::I());
1112
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001113 GrSamplerState* sampler = grPaint.getTextureSampler(kBitmapTextureIdx);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001114
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001115 GrTexture* texture;
1116 sampler->setClampNoFilter();
1117 SkAutoCachedTexture act(this, bitmap, *sampler, &texture);
1118
1119 grPaint.setTexture(kBitmapTextureIdx, texture);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001120
bsalomon@google.com5782d712011-01-21 21:03:59 +00001121 fContext->drawRectToRect(grPaint,
reed@google.com20efde72011-05-09 17:00:02 +00001122 GrRect::MakeXYWH(GrIntToScalar(left),
1123 GrIntToScalar(top),
1124 GrIntToScalar(bitmap.width()),
1125 GrIntToScalar(bitmap.height())),
1126 GrRect::MakeWH(GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001127}
1128
1129void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
1130 int x, int y, const SkPaint& paint) {
1131 CHECK_SHOULD_DRAW(draw);
1132
bsalomon@google.com5782d712011-01-21 21:03:59 +00001133 GrPaint grPaint;
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001134 if (!((SkGpuDevice*)dev)->bindDeviceAsTexture(&grPaint) ||
Scroggod757df22011-05-16 13:11:16 +00001135 !this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001136 return;
reed@google.comac10a2d2010-12-22 21:39:39 +00001137 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001138
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001139 GrTexture* devTex = grPaint.getTexture(0);
1140 SkASSERT(NULL != devTex);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001141
1142 const SkBitmap& bm = dev->accessBitmap(false);
1143 int w = bm.width();
1144 int h = bm.height();
1145
1146 GrAutoMatrix avm(fContext, GrMatrix::I());
1147
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001148 grPaint.getTextureSampler(kBitmapTextureIdx)->setClampNoFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +00001149
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001150 GrRect dstRect = GrRect::MakeXYWH(GrIntToScalar(x),
1151 GrIntToScalar(y),
1152 GrIntToScalar(w),
1153 GrIntToScalar(h));
1154 // The device being drawn may not fill up its texture (saveLayer uses
1155 // the approximate ).
1156 GrRect srcRect = GrRect::MakeWH(GR_Scalar1 * w / devTex->width(),
1157 GR_Scalar1 * h / devTex->height());
1158
1159 fContext->drawRectToRect(grPaint, dstRect, srcRect);
reed@google.comac10a2d2010-12-22 21:39:39 +00001160}
1161
1162///////////////////////////////////////////////////////////////////////////////
1163
1164// must be in SkCanvas::VertexMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +00001165static const GrPrimitiveType gVertexMode2PrimitiveType[] = {
1166 kTriangles_PrimitiveType,
1167 kTriangleStrip_PrimitiveType,
1168 kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +00001169};
1170
1171void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
1172 int vertexCount, const SkPoint vertices[],
1173 const SkPoint texs[], const SkColor colors[],
1174 SkXfermode* xmode,
1175 const uint16_t indices[], int indexCount,
1176 const SkPaint& paint) {
1177 CHECK_SHOULD_DRAW(draw);
1178
bsalomon@google.com5782d712011-01-21 21:03:59 +00001179 GrPaint grPaint;
1180 SkAutoCachedTexture act;
1181 // we ignore the shader if texs is null.
1182 if (NULL == texs) {
Scroggod757df22011-05-16 13:11:16 +00001183 if (!this->skPaint2GrPaintNoShader(paint,
1184 false,
1185 &grPaint,
1186 NULL == colors)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001187 return;
1188 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001189 } else {
reed@google.com1a2e8d22011-01-21 22:08:29 +00001190 if (!this->skPaint2GrPaintShader(paint, &act,
1191 *draw.fMatrix,
Scroggod757df22011-05-16 13:11:16 +00001192 &grPaint,
1193 NULL == colors)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001194 return;
1195 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001196 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001197
1198 if (NULL != xmode && NULL != texs && NULL != colors) {
1199 SkXfermode::Mode mode;
1200 if (!SkXfermode::IsMode(xmode, &mode) ||
1201 SkXfermode::kMultiply_Mode != mode) {
1202 SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
1203#if 0
1204 return
1205#endif
1206 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001207 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001208
1209#if SK_SCALAR_IS_GR_SCALAR
1210 // even if GrColor and SkColor byte offsets match we need
1211 // to perform pre-multiply.
1212 if (NULL == colors) {
1213 fContext->drawVertices(grPaint,
1214 gVertexMode2PrimitiveType[vmode],
1215 vertexCount,
1216 (GrPoint*) vertices,
1217 (GrPoint*) texs,
1218 NULL,
1219 indices,
1220 indexCount);
1221 } else
1222#endif
1223 {
1224 SkTexCoordSource texSrc(texs);
1225 SkColorSource colSrc(colors);
1226 SkIndexSource idxSrc(indices, indexCount);
1227
1228 fContext->drawCustomVertices(grPaint,
1229 gVertexMode2PrimitiveType[vmode],
1230 SkPositionSource(vertices, vertexCount),
1231 (NULL == texs) ? NULL : &texSrc,
1232 (NULL == colors) ? NULL : &colSrc,
1233 (NULL == indices) ? NULL : &idxSrc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001234 }
1235}
1236
1237///////////////////////////////////////////////////////////////////////////////
1238
1239static void GlyphCacheAuxProc(void* data) {
1240 delete (GrFontScaler*)data;
1241}
1242
1243static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) {
1244 void* auxData;
1245 GrFontScaler* scaler = NULL;
1246 if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
1247 scaler = (GrFontScaler*)auxData;
1248 }
1249 if (NULL == scaler) {
1250 scaler = new SkGrFontScaler(cache);
1251 cache->setAuxProc(GlyphCacheAuxProc, scaler);
1252 }
1253 return scaler;
1254}
1255
1256static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
1257 SkFixed fx, SkFixed fy,
1258 const SkGlyph& glyph) {
1259 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1260
1261 GrSkDrawProcs* procs = (GrSkDrawProcs*)state.fDraw->fProcs;
1262
1263 if (NULL == procs->fFontScaler) {
1264 procs->fFontScaler = get_gr_font_scaler(state.fCache);
1265 }
reed@google.com39ce0ac2011-04-08 15:42:19 +00001266
1267 /*
reed@google.com3b139f52011-06-07 17:56:25 +00001268 * What should we do with fy? (assuming horizontal/latin text)
reed@google.com39ce0ac2011-04-08 15:42:19 +00001269 *
reed@google.com3b139f52011-06-07 17:56:25 +00001270 * The raster code calls SkFixedFloorToFixed on it, as it does with fx.
1271 * It calls that rather than round, because our caller has already added
1272 * SK_FixedHalf, so that calling floor gives us the rounded integer.
1273 *
1274 * Test code between raster and gpu (they should draw the same)
1275 *
1276 * canvas->drawText("Hamburgefons", 12, 0, 16.5f, paint);
1277 *
1278 * Perhaps we should only perform this integralization if there is no
1279 * fExtMatrix...
reed@google.com39ce0ac2011-04-08 15:42:19 +00001280 */
reed@google.com3b139f52011-06-07 17:56:25 +00001281 fy = SkFixedFloorToFixed(fy);
1282
reed@google.comac10a2d2010-12-22 21:39:39 +00001283 procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0),
reed@google.com3b139f52011-06-07 17:56:25 +00001284 SkFixedFloorToFixed(fx), fy,
reed@google.comac10a2d2010-12-22 21:39:39 +00001285 procs->fFontScaler);
1286}
1287
bsalomon@google.com5782d712011-01-21 21:03:59 +00001288SkDrawProcs* SkGpuDevice::initDrawForText(GrTextContext* context) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001289
1290 // deferred allocation
1291 if (NULL == fDrawProcs) {
1292 fDrawProcs = new GrSkDrawProcs;
1293 fDrawProcs->fD1GProc = SkGPU_Draw1Glyph;
1294 fDrawProcs->fContext = fContext;
1295 }
1296
1297 // init our (and GL's) state
1298 fDrawProcs->fTextContext = context;
1299 fDrawProcs->fFontScaler = NULL;
1300 return fDrawProcs;
1301}
1302
1303void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
1304 size_t byteLength, SkScalar x, SkScalar y,
1305 const SkPaint& paint) {
1306 CHECK_SHOULD_DRAW(draw);
1307
1308 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1309 // this guy will just call our drawPath()
1310 draw.drawText((const char*)text, byteLength, x, y, paint);
1311 } else {
reed@google.comac10a2d2010-12-22 21:39:39 +00001312 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001313
1314 GrPaint grPaint;
1315 SkAutoCachedTexture act;
1316
Scroggod757df22011-05-16 13:11:16 +00001317 if (!this->skPaint2GrPaintShader(paint,
1318 &act,
1319 *draw.fMatrix,
1320 &grPaint,
1321 true)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001322 return;
1323 }
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001324 GrTextContext context(fContext, grPaint, draw.fExtMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001325 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001326 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
1327 }
1328}
1329
1330void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
1331 size_t byteLength, const SkScalar pos[],
1332 SkScalar constY, int scalarsPerPos,
1333 const SkPaint& paint) {
1334 CHECK_SHOULD_DRAW(draw);
1335
1336 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1337 // this guy will just call our drawPath()
1338 draw.drawPosText((const char*)text, byteLength, pos, constY,
1339 scalarsPerPos, paint);
1340 } else {
reed@google.comac10a2d2010-12-22 21:39:39 +00001341 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001342
1343 GrPaint grPaint;
1344 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +00001345 if (!this->skPaint2GrPaintShader(paint,
1346 &act,
1347 *draw.fMatrix,
1348 &grPaint,
1349 true)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001350 return;
1351 }
1352
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001353 GrTextContext context(fContext, grPaint, draw.fExtMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001354 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001355 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
1356 scalarsPerPos, paint);
1357 }
1358}
1359
1360void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
1361 size_t len, const SkPath& path,
1362 const SkMatrix* m, const SkPaint& paint) {
1363 CHECK_SHOULD_DRAW(draw);
1364
1365 SkASSERT(draw.fDevice == this);
1366 draw.drawTextOnPath((const char*)text, len, path, m, paint);
1367}
1368
1369///////////////////////////////////////////////////////////////////////////////
1370
reed@google.comf67e4cf2011-03-15 20:56:58 +00001371bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
1372 if (!paint.isLCDRenderText()) {
1373 // we're cool with the paint as is
1374 return false;
1375 }
1376
1377 if (paint.getShader() ||
1378 paint.getXfermode() || // unless its srcover
1379 paint.getMaskFilter() ||
1380 paint.getRasterizer() ||
1381 paint.getColorFilter() ||
1382 paint.getPathEffect() ||
1383 paint.isFakeBoldText() ||
1384 paint.getStyle() != SkPaint::kFill_Style) {
1385 // turn off lcd
1386 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
1387 flags->fHinting = paint.getHinting();
1388 return true;
1389 }
1390 // we're cool with the paint as is
1391 return false;
1392}
1393
1394///////////////////////////////////////////////////////////////////////////////
1395
reed@google.comac10a2d2010-12-22 21:39:39 +00001396SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001397 const GrSamplerState& sampler,
1398 GrTexture** texture,
bsalomon@google.come97f0852011-06-17 13:10:25 +00001399 TexType type) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001400 GrTexture* newTexture = NULL;
1401 GrTextureEntry* entry = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +00001402 GrContext* ctx = this->context();
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001403
bsalomon@google.come97f0852011-06-17 13:10:25 +00001404 if (kBitmap_TexType != type) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001405 const GrTextureDesc desc = {
1406 kRenderTarget_GrTextureFlagBit,
1407 kNone_GrAALevel,
1408 bitmap.width(),
1409 bitmap.height(),
1410 SkGr::Bitmap2PixelConfig(bitmap)
1411 };
bsalomon@google.come97f0852011-06-17 13:10:25 +00001412 if (kSaveLayerDeviceRenderTarget_TexType == type) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001413 // we know layers will only be drawn through drawDevice.
1414 // drawDevice has been made to work with content embedded in a
1415 // larger texture so its okay to use the approximate version.
1416 entry = ctx->findApproximateKeylessTexture(desc);
1417 } else {
bsalomon@google.come97f0852011-06-17 13:10:25 +00001418 SkASSERT(kDeviceRenderTarget_TexType == type);
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001419 entry = ctx->lockKeylessTexture(desc);
1420 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001421 } else {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001422 uint32_t p0, p1;
reed@google.comac10a2d2010-12-22 21:39:39 +00001423 p0 = bitmap.getGenerationID();
1424 p1 = bitmap.pixelRefOffset();
reed@google.comac10a2d2010-12-22 21:39:39 +00001425
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001426 GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
1427 entry = ctx->findAndLockTexture(&key, sampler);
reed@google.comac10a2d2010-12-22 21:39:39 +00001428
reed@google.comac10a2d2010-12-22 21:39:39 +00001429 if (NULL == entry) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001430 entry = sk_gr_create_bitmap_texture(ctx, &key, sampler, bitmap);
1431 if (NULL == entry) {
1432 GrPrintf("---- failed to create texture for cache [%d %d]\n",
1433 bitmap.width(), bitmap.height());
1434 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001435 }
1436 }
1437
1438 if (NULL != entry) {
1439 newTexture = entry->texture();
reed@google.comac10a2d2010-12-22 21:39:39 +00001440 if (texture) {
1441 *texture = newTexture;
1442 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001443 }
1444 return (TexCache*)entry;
1445}
1446
1447void SkGpuDevice::unlockCachedTexture(TexCache* cache) {
1448 this->context()->unlockTexture((GrTextureEntry*)cache);
1449}
1450
bsalomon@google.come97f0852011-06-17 13:10:25 +00001451SkDevice* SkGpuDevice::onCreateCompatibleDevice(SkBitmap::Config config,
1452 int width, int height,
1453 bool isOpaque,
1454 Usage usage) {
1455 return SkNEW_ARGS(SkGpuDevice,(this->context(), config,
1456 width, height, usage));
1457}
1458
1459
reed@google.com7b201d22011-01-11 18:59:23 +00001460///////////////////////////////////////////////////////////////////////////////
1461
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001462SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context,
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001463 GrRenderTarget* rootRenderTarget) {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001464 GrAssert(NULL != context);
1465 GrAssert(NULL != rootRenderTarget);
1466
1467 // check this now rather than passing this value to SkGpuDevice cons.
1468 // we want the rt that is bound *now* in the 3D API, not the one
1469 // at the time of newDevice.
1470 if (SkGpuDevice::Current3DApiRenderTarget() == rootRenderTarget) {
1471 fRootRenderTarget = context->createRenderTargetFrom3DApiState();
1472 } else {
1473 fRootRenderTarget = rootRenderTarget;
1474 rootRenderTarget->ref();
1475 }
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001476
1477 fContext = context;
reed@google.com7b201d22011-01-11 18:59:23 +00001478 context->ref();
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001479
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001480 fRootTexture = NULL;
1481}
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001482
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001483SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context, GrTexture* rootRenderTargetTexture) {
1484 GrAssert(NULL != context);
1485 GrAssert(NULL != rootRenderTargetTexture);
1486 GrAssert(NULL != rootRenderTargetTexture->asRenderTarget());
1487
1488 fRootTexture = rootRenderTargetTexture;
1489 rootRenderTargetTexture->ref();
1490
1491 fRootRenderTarget = rootRenderTargetTexture->asRenderTarget();
1492 fRootRenderTarget->ref();
1493
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001494 fContext = context;
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001495 context->ref();
reed@google.com7b201d22011-01-11 18:59:23 +00001496}
1497
1498SkGpuDeviceFactory::~SkGpuDeviceFactory() {
1499 fContext->unref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001500 fRootRenderTarget->unref();
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001501 GrSafeUnref(fRootTexture);
reed@google.com7b201d22011-01-11 18:59:23 +00001502}
1503
1504SkDevice* SkGpuDeviceFactory::newDevice(SkCanvas*, SkBitmap::Config config,
1505 int width, int height,
1506 bool isOpaque, bool isLayer) {
reed@google.comaf951c92011-06-16 19:10:39 +00001507 if (isLayer) {
1508 return SkNEW_ARGS(SkGpuDevice, (fContext, config, width, height));
1509 } else {
1510 return SkNEW_ARGS(SkGpuDevice, (fContext, fRootRenderTarget));
1511 }
reed@google.com7b201d22011-01-11 18:59:23 +00001512}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001513