blob: 189b692ddea84061178d212f3dfeef822d7f318c [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
79 fTex = device->lockCachedTexture(bitmap, sampler, &texture, false);
80 }
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,
169 int height, bool isForSaveLayer)
170: 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
189
reed@google.comaf951c92011-06-16 19:10:39 +0000190 fCache = this->lockCachedTexture(bm, GrSamplerState::ClampNoFilter(),
191 &fTexture, true, isForSaveLayer);
192 if (fCache) {
193 SkASSERT(NULL != fTexture);
194 SkASSERT(NULL != fTexture->asRenderTarget());
195 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000196#else
reed@google.comaf951c92011-06-16 19:10:39 +0000197 const GrTextureDesc desc = {
198 kRenderTarget_GrTextureFlagBit,
199 kNone_GrAALevel,
200 width,
201 height,
202 SkGr::Bitmap2PixelConfig(bm)
203 };
reed@google.comac10a2d2010-12-22 21:39:39 +0000204
reed@google.comaf951c92011-06-16 19:10:39 +0000205 fTexture = fContext->createUncachedTexture(desc, NULL, 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000206#endif
reed@google.comaf951c92011-06-16 19:10:39 +0000207 if (NULL != fTexture) {
208 fRenderTarget = fTexture->asRenderTarget();
reed@google.comac10a2d2010-12-22 21:39:39 +0000209
reed@google.comaf951c92011-06-16 19:10:39 +0000210 GrAssert(NULL != fRenderTarget);
reed@google.comac10a2d2010-12-22 21:39:39 +0000211
reed@google.comaf951c92011-06-16 19:10:39 +0000212 // we defer the actual clear until our gainFocus()
213 fNeedClear = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000214
reed@google.comaf951c92011-06-16 19:10:39 +0000215 // wrap the bitmap with a pixelref to expose our texture
216 SkGrTexturePixelRef* pr = new SkGrTexturePixelRef(fTexture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000217 this->setPixelRef(pr, 0)->unref();
reed@google.comaf951c92011-06-16 19:10:39 +0000218 } else {
219 GrPrintf("--- failed to create gpu-offscreen [%d %d]\n",
220 width, height);
221 GrAssert(false);
reed@google.comac10a2d2010-12-22 21:39:39 +0000222 }
223}
224
225SkGpuDevice::~SkGpuDevice() {
226 if (fDrawProcs) {
227 delete fDrawProcs;
228 }
229
230 if (fCache) {
231 GrAssert(NULL != fTexture);
232 GrAssert(fRenderTarget == fTexture->asRenderTarget());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000233 fContext->unlockTexture((GrTextureEntry*)fCache);
reed@google.comac10a2d2010-12-22 21:39:39 +0000234 } else if (NULL != fTexture) {
235 GrAssert(!CACHE_LAYER_TEXTURES);
236 GrAssert(fRenderTarget == fTexture->asRenderTarget());
237 fTexture->unref();
238 } else if (NULL != fRenderTarget) {
239 fRenderTarget->unref();
240 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000241 fContext->unref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000242}
243
reed@google.comac10a2d2010-12-22 21:39:39 +0000244intptr_t SkGpuDevice::getLayerTextureHandle() const {
245 if (fTexture) {
246 return fTexture->getTextureHandle();
247 } else {
248 return 0;
249 }
250}
mike@reedtribe.orgea4ac972011-04-26 11:48:33 +0000251
252SkDeviceFactory* SkGpuDevice::onNewDeviceFactory() {
253 return SkNEW_ARGS(SkGpuDeviceFactory, (fContext, fRenderTarget));
254}
255
reed@google.comac10a2d2010-12-22 21:39:39 +0000256///////////////////////////////////////////////////////////////////////////////
257
258void SkGpuDevice::makeRenderTargetCurrent() {
259 fContext->setRenderTarget(fRenderTarget);
260 fContext->flush(true);
261 fNeedPrepareRenderTarget = true;
262}
263
264///////////////////////////////////////////////////////////////////////////////
265
266bool SkGpuDevice::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
267 SkIRect bounds;
268 bounds.set(0, 0, this->width(), this->height());
269 if (!bounds.intersect(srcRect)) {
270 return false;
271 }
272
273 const int w = bounds.width();
274 const int h = bounds.height();
275 SkBitmap tmp;
276 // note we explicitly specify our rowBytes to be snug (no gap between rows)
277 tmp.setConfig(SkBitmap::kARGB_8888_Config, w, h, w * 4);
278 if (!tmp.allocPixels()) {
279 return false;
280 }
281
Scroggo813c33c2011-04-07 20:56:21 +0000282 tmp.lockPixels();
reed@google.comac10a2d2010-12-22 21:39:39 +0000283
Scroggoeb176032011-04-07 21:11:49 +0000284 bool read = fContext->readRenderTargetPixels(fRenderTarget,
285 bounds.fLeft, bounds.fTop,
286 bounds.width(), bounds.height(),
287 kRGBA_8888_GrPixelConfig,
288 tmp.getPixels());
Scroggo813c33c2011-04-07 20:56:21 +0000289 tmp.unlockPixels();
290 if (!read) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000291 return false;
292 }
293
294 tmp.swap(*bitmap);
295 return true;
296}
297
298void SkGpuDevice::writePixels(const SkBitmap& bitmap, int x, int y) {
299 SkAutoLockPixels alp(bitmap);
300 if (!bitmap.readyToDraw()) {
301 return;
302 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000303 GrPixelConfig config = SkGr::BitmapConfig2PixelConfig(bitmap.config(),
304 bitmap.isOpaque());
reed@google.comac10a2d2010-12-22 21:39:39 +0000305 fContext->setRenderTarget(fRenderTarget);
306 // we aren't setting the clip or matrix, so mark as dirty
307 // we don't need to set them for this call and don't have them anyway
308 fNeedPrepareRenderTarget = true;
309
310 fContext->writePixels(x, y, bitmap.width(), bitmap.height(),
311 config, bitmap.getPixels(), bitmap.rowBytes());
312}
313
314///////////////////////////////////////////////////////////////////////////////
315
316static void convert_matrixclip(GrContext* context, const SkMatrix& matrix,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000317 const SkClipStack& clipStack,
reed@google.com6f8f2922011-03-04 22:27:10 +0000318 const SkRegion& clipRegion,
319 const SkIPoint& origin) {
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000320 context->setMatrix(matrix);
reed@google.comac10a2d2010-12-22 21:39:39 +0000321
322 SkGrClipIterator iter;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000323 iter.reset(clipStack);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000324 const SkIRect& skBounds = clipRegion.getBounds();
325 GrRect bounds;
326 bounds.setLTRB(GrIntToScalar(skBounds.fLeft),
327 GrIntToScalar(skBounds.fTop),
328 GrIntToScalar(skBounds.fRight),
329 GrIntToScalar(skBounds.fBottom));
reed@google.com6f8f2922011-03-04 22:27:10 +0000330 GrClip grc(&iter, GrIntToScalar(-origin.x()), GrIntToScalar(-origin.y()),
331 &bounds);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000332 context->setClip(grc);
reed@google.comac10a2d2010-12-22 21:39:39 +0000333}
334
335// call this ever each draw call, to ensure that the context reflects our state,
336// and not the state from some other canvas/device
337void SkGpuDevice::prepareRenderTarget(const SkDraw& draw) {
338 if (fNeedPrepareRenderTarget ||
bsalomon@google.com5782d712011-01-21 21:03:59 +0000339 fContext->getRenderTarget() != fRenderTarget) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000340
341 fContext->setRenderTarget(fRenderTarget);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000342 SkASSERT(draw.fClipStack);
343 convert_matrixclip(fContext, *draw.fMatrix,
reed@google.com6f8f2922011-03-04 22:27:10 +0000344 *draw.fClipStack, *draw.fClip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000345 fNeedPrepareRenderTarget = false;
346 }
347}
348
reed@google.com46799cd2011-02-22 20:56:26 +0000349void SkGpuDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& clip,
350 const SkClipStack& clipStack) {
351 this->INHERITED::setMatrixClip(matrix, clip, clipStack);
bsalomon@google.coma7bf6e22011-04-11 19:20:46 +0000352 // We don't need to set them now because the context may not reflect this device.
353 fNeedPrepareRenderTarget = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000354}
355
356void SkGpuDevice::gainFocus(SkCanvas* canvas, const SkMatrix& matrix,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000357 const SkRegion& clip, const SkClipStack& clipStack) {
358
reed@google.comac10a2d2010-12-22 21:39:39 +0000359 fContext->setRenderTarget(fRenderTarget);
360
bsalomon@google.comd302f142011-03-03 13:54:13 +0000361 this->INHERITED::gainFocus(canvas, matrix, clip, clipStack);
reed@google.comac10a2d2010-12-22 21:39:39 +0000362
reed@google.com6f8f2922011-03-04 22:27:10 +0000363 convert_matrixclip(fContext, matrix, clipStack, clip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000364
365 if (fNeedClear) {
bsalomon@google.com31a58402011-04-27 21:00:02 +0000366 fContext->clear(NULL, 0x0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000367 fNeedClear = false;
368 }
369}
370
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000371bool SkGpuDevice::bindDeviceAsTexture(GrPaint* paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000372 if (NULL != fTexture) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000373 paint->setTexture(kBitmapTextureIdx, fTexture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000374 return true;
375 }
376 return false;
377}
378
379///////////////////////////////////////////////////////////////////////////////
380
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000381SK_COMPILE_ASSERT(SkShader::kNone_BitmapType == 0, shader_type_mismatch);
382SK_COMPILE_ASSERT(SkShader::kDefault_BitmapType == 1, shader_type_mismatch);
383SK_COMPILE_ASSERT(SkShader::kRadial_BitmapType == 2, shader_type_mismatch);
384SK_COMPILE_ASSERT(SkShader::kSweep_BitmapType == 3, shader_type_mismatch);
385SK_COMPILE_ASSERT(SkShader::kTwoPointRadial_BitmapType == 4,
386 shader_type_mismatch);
387SK_COMPILE_ASSERT(SkShader::kLast_BitmapType == 4, shader_type_mismatch);
reed@google.comac10a2d2010-12-22 21:39:39 +0000388
bsalomon@google.com5782d712011-01-21 21:03:59 +0000389static const GrSamplerState::SampleMode sk_bmp_type_to_sample_mode[] = {
390 (GrSamplerState::SampleMode) -1, // kNone_BitmapType
391 GrSamplerState::kNormal_SampleMode, // kDefault_BitmapType
392 GrSamplerState::kRadial_SampleMode, // kRadial_BitmapType
393 GrSamplerState::kSweep_SampleMode, // kSweep_BitmapType
394 GrSamplerState::kRadial2_SampleMode, // kTwoPointRadial_BitmapType
395};
396
397bool SkGpuDevice::skPaint2GrPaintNoShader(const SkPaint& skPaint,
398 bool justAlpha,
Scroggod757df22011-05-16 13:11:16 +0000399 GrPaint* grPaint,
400 bool constantColor) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000401
402 grPaint->fDither = skPaint.isDither();
403 grPaint->fAntiAlias = skPaint.isAntiAlias();
404
405 SkXfermode::Coeff sm = SkXfermode::kOne_Coeff;
406 SkXfermode::Coeff dm = SkXfermode::kISA_Coeff;
407
408 SkXfermode* mode = skPaint.getXfermode();
409 if (mode) {
410 if (!mode->asCoeff(&sm, &dm)) {
reed@google.com1a2e8d22011-01-21 22:08:29 +0000411 SkDEBUGCODE(SkDebugf("Unsupported xfer mode.\n");)
bsalomon@google.com5782d712011-01-21 21:03:59 +0000412#if 0
413 return false;
414#endif
415 }
416 }
417 grPaint->fSrcBlendCoeff = sk_blend_to_grblend(sm);
418 grPaint->fDstBlendCoeff = sk_blend_to_grblend(dm);
419
420 if (justAlpha) {
421 uint8_t alpha = skPaint.getAlpha();
422 grPaint->fColor = GrColorPackRGBA(alpha, alpha, alpha, alpha);
Scroggod757df22011-05-16 13:11:16 +0000423 // justAlpha is currently set to true only if there is a texture,
424 // so constantColor should not also be true.
425 GrAssert(!constantColor);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000426 } else {
427 grPaint->fColor = SkGr::SkColor2GrColor(skPaint.getColor());
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000428 grPaint->setTexture(kShaderTextureIdx, NULL);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000429 }
Scroggo97c88c22011-05-11 14:05:25 +0000430 SkColorFilter* colorFilter = skPaint.getColorFilter();
431 SkColor color;
432 SkXfermode::Mode filterMode;
433 if (colorFilter != NULL && colorFilter->asColorMode(&color, &filterMode)) {
Scroggod757df22011-05-16 13:11:16 +0000434 if (!constantColor) {
435 grPaint->fColorFilterColor = SkGr::SkColor2GrColor(color);
436 grPaint->fColorFilterXfermode = filterMode;
437 return true;
438 }
439 SkColor filtered = colorFilter->filterColor(skPaint.getColor());
440 grPaint->fColor = SkGr::SkColor2GrColor(filtered);
Scroggo97c88c22011-05-11 14:05:25 +0000441 }
Scroggod757df22011-05-16 13:11:16 +0000442 grPaint->resetColorFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +0000443 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000444}
445
bsalomon@google.com5782d712011-01-21 21:03:59 +0000446bool SkGpuDevice::skPaint2GrPaintShader(const SkPaint& skPaint,
447 SkAutoCachedTexture* act,
448 const SkMatrix& ctm,
Scroggod757df22011-05-16 13:11:16 +0000449 GrPaint* grPaint,
450 bool constantColor) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000451
bsalomon@google.com5782d712011-01-21 21:03:59 +0000452 SkASSERT(NULL != act);
reed@google.comac10a2d2010-12-22 21:39:39 +0000453
bsalomon@google.com5782d712011-01-21 21:03:59 +0000454 SkShader* shader = skPaint.getShader();
reed@google.comac10a2d2010-12-22 21:39:39 +0000455 if (NULL == shader) {
Scroggod757df22011-05-16 13:11:16 +0000456 return this->skPaint2GrPaintNoShader(skPaint,
457 false,
458 grPaint,
459 constantColor);
460 } else if (!this->skPaint2GrPaintNoShader(skPaint, true, grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000461 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000462 }
463
bsalomon@google.com5782d712011-01-21 21:03:59 +0000464 SkPaint noAlphaPaint(skPaint);
465 noAlphaPaint.setAlpha(255);
466 shader->setContext(this->accessBitmap(false), noAlphaPaint, ctm);
reed@google.comac10a2d2010-12-22 21:39:39 +0000467
reed@google.comac10a2d2010-12-22 21:39:39 +0000468 SkBitmap bitmap;
469 SkMatrix matrix;
470 SkShader::TileMode tileModes[2];
471 SkScalar twoPointParams[3];
472 SkShader::BitmapType bmptype = shader->asABitmap(&bitmap, &matrix,
473 tileModes, twoPointParams);
474
bsalomon@google.com5782d712011-01-21 21:03:59 +0000475 GrSamplerState::SampleMode sampleMode = sk_bmp_type_to_sample_mode[bmptype];
476 if (-1 == sampleMode) {
477 SkDebugf("shader->asABitmap() == kNone_BitmapType\n");
478 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000479 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000480 GrSamplerState* sampler = grPaint->getTextureSampler(kShaderTextureIdx);
481 sampler->setSampleMode(sampleMode);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000482 if (skPaint.isFilterBitmap()) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000483 sampler->setFilter(GrSamplerState::kBilinear_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000484 } else {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000485 sampler->setFilter(GrSamplerState::kNearest_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000486 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000487 sampler->setWrapX(sk_tile_mode_to_grwrap(tileModes[0]));
488 sampler->setWrapY(sk_tile_mode_to_grwrap(tileModes[1]));
reed@google.comac10a2d2010-12-22 21:39:39 +0000489 if (GrSamplerState::kRadial2_SampleMode == sampleMode) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000490 sampler->setRadial2Params(twoPointParams[0],
491 twoPointParams[1],
492 twoPointParams[2] < 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000493 }
494
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000495 GrTexture* texture = act->set(this, bitmap, *sampler);
reed@google.comac10a2d2010-12-22 21:39:39 +0000496 if (NULL == texture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000497 SkDebugf("Couldn't convert bitmap to texture.\n");
498 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000499 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000500 grPaint->setTexture(kShaderTextureIdx, texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000501
502 // since our texture coords will be in local space, we wack the texture
503 // matrix to map them back into 0...1 before we load it
504 SkMatrix localM;
505 if (shader->getLocalMatrix(&localM)) {
506 SkMatrix inverse;
507 if (localM.invert(&inverse)) {
508 matrix.preConcat(inverse);
509 }
510 }
511 if (SkShader::kDefault_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000512 GrScalar sx = GrFixedToScalar(GR_Fixed1 / bitmap.width());
513 GrScalar sy = GrFixedToScalar(GR_Fixed1 / bitmap.height());
reed@google.comac10a2d2010-12-22 21:39:39 +0000514 matrix.postScale(sx, sy);
reed@google.comac10a2d2010-12-22 21:39:39 +0000515 } else if (SkShader::kRadial_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000516 GrScalar s = GrFixedToScalar(GR_Fixed1 / bitmap.width());
reed@google.comac10a2d2010-12-22 21:39:39 +0000517 matrix.postScale(s, s);
518 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000519 sampler->setMatrix(matrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000520
521 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000522}
523
524///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com5782d712011-01-21 21:03:59 +0000525
526class SkPositionSource {
527public:
528 SkPositionSource(const SkPoint* points, int count)
529 : fPoints(points), fCount(count) {}
530
531 int count() const { return fCount; }
532
533 void writeValue(int i, GrPoint* dstPosition) const {
534 SkASSERT(i < fCount);
535 dstPosition->fX = SkScalarToGrScalar(fPoints[i].fX);
536 dstPosition->fY = SkScalarToGrScalar(fPoints[i].fY);
537 }
538private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000539 const SkPoint* fPoints;
bsalomon@google.com19628322011-02-03 21:30:17 +0000540 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000541};
542
543class SkTexCoordSource {
544public:
545 SkTexCoordSource(const SkPoint* coords)
546 : fCoords(coords) {}
547
548 void writeValue(int i, GrPoint* dstCoord) const {
549 dstCoord->fX = SkScalarToGrScalar(fCoords[i].fX);
550 dstCoord->fY = SkScalarToGrScalar(fCoords[i].fY);
551 }
552private:
553 const SkPoint* fCoords;
554};
555
556class SkColorSource {
557public:
558 SkColorSource(const SkColor* colors) : fColors(colors) {}
559
560 void writeValue(int i, GrColor* dstColor) const {
561 *dstColor = SkGr::SkColor2GrColor(fColors[i]);
562 }
563private:
564 const SkColor* fColors;
565};
566
567class SkIndexSource {
568public:
569 SkIndexSource(const uint16_t* indices, int count)
570 : fIndices(indices), fCount(count) {
571 }
572
573 int count() const { return fCount; }
574
575 void writeValue(int i, uint16_t* dstIndex) const {
576 *dstIndex = fIndices[i];
577 }
578
579private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000580 const uint16_t* fIndices;
bsalomon@google.com19628322011-02-03 21:30:17 +0000581 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000582};
583
584///////////////////////////////////////////////////////////////////////////////
585
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000586#if 0 // not currently being used so don't compile,
587
bsalomon@google.com5782d712011-01-21 21:03:59 +0000588// can be used for positions or texture coordinates
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000589
bsalomon@google.com5782d712011-01-21 21:03:59 +0000590class SkRectFanSource {
591public:
592 SkRectFanSource(const SkRect& rect) : fRect(rect) {}
593
594 int count() const { return 4; }
595
596 void writeValue(int i, GrPoint* dstPoint) const {
597 SkASSERT(i < 4);
598 dstPoint->fX = SkScalarToGrScalar((i % 3) ? fRect.fRight :
599 fRect.fLeft);
600 dstPoint->fY = SkScalarToGrScalar((i < 2) ? fRect.fTop :
601 fRect.fBottom);
602 }
603private:
604 const SkRect& fRect;
605};
606
607class SkIRectFanSource {
608public:
609 SkIRectFanSource(const SkIRect& rect) : fRect(rect) {}
610
611 int count() const { return 4; }
612
613 void writeValue(int i, GrPoint* dstPoint) const {
614 SkASSERT(i < 4);
615 dstPoint->fX = (i % 3) ? GrIntToScalar(fRect.fRight) :
616 GrIntToScalar(fRect.fLeft);
617 dstPoint->fY = (i < 2) ? GrIntToScalar(fRect.fTop) :
618 GrIntToScalar(fRect.fBottom);
619 }
620private:
621 const SkIRect& fRect;
622};
623
624class SkMatRectFanSource {
625public:
626 SkMatRectFanSource(const SkRect& rect, const SkMatrix& matrix)
627 : fRect(rect), fMatrix(matrix) {}
628
629 int count() const { return 4; }
630
631 void writeValue(int i, GrPoint* dstPoint) const {
632 SkASSERT(i < 4);
633
634#if SK_SCALAR_IS_GR_SCALAR
635 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
636 (i < 2) ? fRect.fTop : fRect.fBottom,
637 (SkPoint*)dstPoint);
638#else
639 SkPoint dst;
640 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
641 (i < 2) ? fRect.fTop : fRect.fBottom,
642 &dst);
643 dstPoint->fX = SkScalarToGrScalar(dst.fX);
644 dstPoint->fY = SkScalarToGrScalar(dst.fY);
645#endif
646 }
647private:
648 const SkRect& fRect;
649 const SkMatrix& fMatrix;
650};
651
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000652#endif
653
reed@google.comac10a2d2010-12-22 21:39:39 +0000654///////////////////////////////////////////////////////////////////////////////
655
bsalomon@google.com398109c2011-04-14 18:40:27 +0000656void SkGpuDevice::clear(SkColor color) {
bsalomon@google.com31a58402011-04-27 21:00:02 +0000657 fContext->clear(NULL, color);
bsalomon@google.com398109c2011-04-14 18:40:27 +0000658}
659
reed@google.comac10a2d2010-12-22 21:39:39 +0000660void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
661 CHECK_SHOULD_DRAW(draw);
662
bsalomon@google.com5782d712011-01-21 21:03:59 +0000663 GrPaint grPaint;
664 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000665 if (!this->skPaint2GrPaintShader(paint,
666 &act,
667 *draw.fMatrix,
668 &grPaint,
669 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000670 return;
671 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000672
673 fContext->drawPaint(grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000674}
675
676// must be in SkCanvas::PointMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +0000677static const GrPrimitiveType gPointMode2PrimtiveType[] = {
678 kPoints_PrimitiveType,
679 kLines_PrimitiveType,
680 kLineStrip_PrimitiveType
reed@google.comac10a2d2010-12-22 21:39:39 +0000681};
682
683void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000684 size_t count, const SkPoint pts[], const SkPaint& paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000685 CHECK_SHOULD_DRAW(draw);
686
687 SkScalar width = paint.getStrokeWidth();
688 if (width < 0) {
689 return;
690 }
691
692 // we only handle hairlines here, else we let the SkDraw call our drawPath()
693 if (width > 0) {
694 draw.drawPoints(mode, count, pts, paint, true);
695 return;
696 }
697
bsalomon@google.com5782d712011-01-21 21:03:59 +0000698 GrPaint grPaint;
699 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000700 if (!this->skPaint2GrPaintShader(paint,
701 &act,
702 *draw.fMatrix,
703 &grPaint,
704 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000705 return;
706 }
707
reed@google.comac10a2d2010-12-22 21:39:39 +0000708#if SK_SCALAR_IS_GR_SCALAR
bsalomon@google.com5782d712011-01-21 21:03:59 +0000709 fContext->drawVertices(grPaint,
710 gPointMode2PrimtiveType[mode],
711 count,
712 (GrPoint*)pts,
713 NULL,
714 NULL,
715 NULL,
716 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000717#else
bsalomon@google.com5782d712011-01-21 21:03:59 +0000718 fContext->drawCustomVertices(grPaint,
719 gPointMode2PrimtiveType[mode],
720 SkPositionSource(pts, count));
reed@google.comac10a2d2010-12-22 21:39:39 +0000721#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000722}
723
reed@google.comc9aa5872011-04-05 21:05:37 +0000724///////////////////////////////////////////////////////////////////////////////
725
reed@google.comac10a2d2010-12-22 21:39:39 +0000726void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
727 const SkPaint& paint) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000728 CHECK_SHOULD_DRAW(draw);
729
730 bool doStroke = paint.getStyle() == SkPaint::kStroke_Style;
731 SkScalar width = paint.getStrokeWidth();
732
733 /*
734 We have special code for hairline strokes, miter-strokes, and fills.
735 Anything else we just call our path code.
736 */
737 bool usePath = doStroke && width > 0 &&
738 paint.getStrokeJoin() != SkPaint::kMiter_Join;
739 // another reason we might need to call drawPath...
740 if (paint.getMaskFilter()) {
741 usePath = true;
742 }
reed@google.com67db6642011-05-26 11:46:35 +0000743 // until we aa rotated rects...
744 if (!usePath && paint.isAntiAlias() && !draw.fMatrix->rectStaysRect()) {
745 usePath = true;
746 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000747
748 if (usePath) {
749 SkPath path;
750 path.addRect(rect);
751 this->drawPath(draw, path, paint, NULL, true);
752 return;
753 }
754
755 GrPaint grPaint;
756 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000757 if (!this->skPaint2GrPaintShader(paint,
758 &act,
759 *draw.fMatrix,
760 &grPaint,
761 true)) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000762 return;
763 }
reed@google.com20efde72011-05-09 17:00:02 +0000764 fContext->drawRect(grPaint, rect, doStroke ? width : -1);
reed@google.comac10a2d2010-12-22 21:39:39 +0000765}
766
reed@google.com69302852011-02-16 18:08:07 +0000767#include "SkMaskFilter.h"
768#include "SkBounder.h"
769
reed@google.com69302852011-02-16 18:08:07 +0000770static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
771 SkMaskFilter* filter, const SkMatrix& matrix,
772 const SkRegion& clip, SkBounder* bounder,
773 GrPaint* grp) {
774 SkMask srcM, dstM;
775
776 if (!SkDraw::DrawToMask(path, &clip.getBounds(), filter, &matrix, &srcM,
777 SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
778 return false;
779 }
780
781 SkAutoMaskImage autoSrc(&srcM, false);
782
783 if (!filter->filterMask(&dstM, srcM, matrix, NULL)) {
784 return false;
785 }
786 // this will free-up dstM when we're done (allocated in filterMask())
787 SkAutoMaskImage autoDst(&dstM, false);
788
789 if (clip.quickReject(dstM.fBounds)) {
790 return false;
791 }
792 if (bounder && !bounder->doIRect(dstM.fBounds)) {
793 return false;
794 }
795
796 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
797 // the current clip (and identity matrix) and grpaint settings
798
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000799 // used to compute inverse view, if necessary
800 GrMatrix ivm = context->getMatrix();
801
reed@google.com0c219b62011-02-16 21:31:18 +0000802 GrAutoMatrix avm(context, GrMatrix::I());
reed@google.com69302852011-02-16 18:08:07 +0000803
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000804 const GrTextureDesc desc = {
805 kNone_GrTextureFlags,
806 kNone_GrAALevel,
reed@google.com69302852011-02-16 18:08:07 +0000807 dstM.fBounds.width(),
808 dstM.fBounds.height(),
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000809 kAlpha_8_GrPixelConfig
reed@google.com69302852011-02-16 18:08:07 +0000810 };
811
812 GrTexture* texture = context->createUncachedTexture(desc, dstM.fImage,
813 dstM.fRowBytes);
814 if (NULL == texture) {
815 return false;
816 }
817
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000818 if (grp->hasTextureOrMask() && ivm.invert(&ivm)) {
819 grp->preConcatActiveSamplerMatrices(ivm);
820 }
821
822 static const int MASK_IDX = GrPaint::kMaxMasks - 1;
823 // we assume the last mask index is available for use
824 GrAssert(NULL == grp->getMask(MASK_IDX));
825 grp->setMask(MASK_IDX, texture);
reed@google.com0c219b62011-02-16 21:31:18 +0000826 texture->unref();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000827 grp->getMaskSampler(MASK_IDX)->setClampNoFilter();
reed@google.com69302852011-02-16 18:08:07 +0000828
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000829 GrRect d;
830 d.setLTRB(GrIntToScalar(dstM.fBounds.fLeft),
reed@google.com0c219b62011-02-16 21:31:18 +0000831 GrIntToScalar(dstM.fBounds.fTop),
832 GrIntToScalar(dstM.fBounds.fRight),
833 GrIntToScalar(dstM.fBounds.fBottom));
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000834
835 GrMatrix m;
836 m.setTranslate(-dstM.fBounds.fLeft, -dstM.fBounds.fTop);
837 m.postIDiv(dstM.fBounds.width(), dstM.fBounds.height());
838 grp->getMaskSampler(MASK_IDX)->setMatrix(m);
839
840 context->drawRect(*grp, d);
reed@google.com69302852011-02-16 18:08:07 +0000841 return true;
842}
reed@google.com69302852011-02-16 18:08:07 +0000843
reed@google.com0c219b62011-02-16 21:31:18 +0000844void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
reed@google.comac10a2d2010-12-22 21:39:39 +0000845 const SkPaint& paint, const SkMatrix* prePathMatrix,
846 bool pathIsMutable) {
847 CHECK_SHOULD_DRAW(draw);
848
bsalomon@google.com5782d712011-01-21 21:03:59 +0000849 GrPaint grPaint;
850 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000851 if (!this->skPaint2GrPaintShader(paint,
852 &act,
853 *draw.fMatrix,
854 &grPaint,
855 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000856 return;
857 }
858
reed@google.com0c219b62011-02-16 21:31:18 +0000859 // BEGIN lift from SkDraw::drawPath()
860
861 SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
862 bool doFill = true;
863 SkPath tmpPath;
reed@google.comac10a2d2010-12-22 21:39:39 +0000864
865 if (prePathMatrix) {
reed@google.come3445642011-02-16 23:20:39 +0000866 SkPath* result = pathPtr;
reed@google.com0c219b62011-02-16 21:31:18 +0000867
reed@google.come3445642011-02-16 23:20:39 +0000868 if (!pathIsMutable) {
869 result = &tmpPath;
870 pathIsMutable = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000871 }
reed@google.come3445642011-02-16 23:20:39 +0000872 // should I push prePathMatrix on our MV stack temporarily, instead
873 // of applying it here? See SkDraw.cpp
874 pathPtr->transform(*prePathMatrix, result);
875 pathPtr = result;
reed@google.comac10a2d2010-12-22 21:39:39 +0000876 }
reed@google.com0c219b62011-02-16 21:31:18 +0000877 // at this point we're done with prePathMatrix
878 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
reed@google.comac10a2d2010-12-22 21:39:39 +0000879
bsalomon@google.com04de7822011-03-25 18:04:43 +0000880 // This "if" is not part of the SkDraw::drawPath() lift.
881 // When we get a 1.0 wide stroke we hairline stroke it instead of creating
882 // a new stroked-path. This is motivated by canvas2D sites that draw
883 // lines as 1.0 wide stroked paths. We can consider doing an alpha-modulated-
884 // hairline for width < 1.0 when AA is enabled.
885 static const int gMatrixMask = ~(SkMatrix::kIdentity_Mask |
886 SkMatrix::kTranslate_Mask);
887 if (!paint.getPathEffect() &&
888 SkPaint::kStroke_Style == paint.getStyle() &&
889 !(draw.fMatrix->getType() & gMatrixMask) &&
890 SK_Scalar1 == paint.getStrokeWidth()) {
891 doFill = false;
892 }
893
894 if (doFill && (paint.getPathEffect() ||
895 paint.getStyle() != SkPaint::kFill_Style)) {
reed@google.com0c219b62011-02-16 21:31:18 +0000896 doFill = paint.getFillPath(*pathPtr, &tmpPath);
897 pathPtr = &tmpPath;
898 }
899
900 // END lift from SkDraw::drawPath()
901
reed@google.com69302852011-02-16 18:08:07 +0000902 if (paint.getMaskFilter()) {
reed@google.com0c219b62011-02-16 21:31:18 +0000903 // avoid possibly allocating a new path in transform if we can
904 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
905
906 // transform the path into device space
reed@google.come3445642011-02-16 23:20:39 +0000907 pathPtr->transform(*draw.fMatrix, devPathPtr);
reed@google.com0c219b62011-02-16 21:31:18 +0000908
909 drawWithMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
reed@google.com69302852011-02-16 18:08:07 +0000910 *draw.fMatrix, *draw.fClip, draw.fBounder, &grPaint);
911 return;
912 }
reed@google.com69302852011-02-16 18:08:07 +0000913
bsalomon@google.comffca4002011-02-22 20:34:01 +0000914 GrPathFill fill = kHairLine_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000915
reed@google.com0c219b62011-02-16 21:31:18 +0000916 if (doFill) {
917 switch (pathPtr->getFillType()) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000918 case SkPath::kWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000919 fill = kWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000920 break;
921 case SkPath::kEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000922 fill = kEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000923 break;
924 case SkPath::kInverseWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000925 fill = kInverseWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000926 break;
927 case SkPath::kInverseEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000928 fill = kInverseEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000929 break;
930 default:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000931 SkDebugf("Unsupported path fill type\n");
reed@google.comac10a2d2010-12-22 21:39:39 +0000932 return;
933 }
934 }
935
reed@google.com07f3ee12011-05-16 17:21:57 +0000936 fContext->drawPath(grPaint, *pathPtr, fill);
reed@google.comac10a2d2010-12-22 21:39:39 +0000937}
938
reed@google.comac10a2d2010-12-22 21:39:39 +0000939void SkGpuDevice::drawBitmap(const SkDraw& draw,
940 const SkBitmap& bitmap,
941 const SkIRect* srcRectPtr,
942 const SkMatrix& m,
943 const SkPaint& paint) {
944 CHECK_SHOULD_DRAW(draw);
945
946 SkIRect srcRect;
947 if (NULL == srcRectPtr) {
948 srcRect.set(0, 0, bitmap.width(), bitmap.height());
949 } else {
950 srcRect = *srcRectPtr;
951 }
952
bsalomon@google.com5782d712011-01-21 21:03:59 +0000953 GrPaint grPaint;
Scroggod757df22011-05-16 13:11:16 +0000954 if (!this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000955 return;
956 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000957 GrSamplerState* sampler = grPaint.getTextureSampler(kBitmapTextureIdx);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000958 if (paint.isFilterBitmap()) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000959 sampler->setFilter(GrSamplerState::kBilinear_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000960 } else {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000961 sampler->setFilter(GrSamplerState::kNearest_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000962 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000963
bsalomon@google.com91958362011-06-13 17:58:13 +0000964 const int maxTextureSize = fContext->getMaxTextureSize();
965 if (bitmap.getTexture() || (bitmap.width() <= maxTextureSize &&
966 bitmap.height() <= maxTextureSize)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000967 // take the fast case
bsalomon@google.com5782d712011-01-21 21:03:59 +0000968 this->internalDrawBitmap(draw, bitmap, srcRect, m, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000969 return;
970 }
971
972 // undo the translate done by SkCanvas
973 int DX = SkMax32(0, srcRect.fLeft);
974 int DY = SkMax32(0, srcRect.fTop);
975 // compute clip bounds in local coordinates
976 SkIRect clipRect;
977 {
978 SkRect r;
979 r.set(draw.fClip->getBounds());
980 SkMatrix matrix, inverse;
981 matrix.setConcat(*draw.fMatrix, m);
982 if (!matrix.invert(&inverse)) {
983 return;
984 }
985 inverse.mapRect(&r);
986 r.roundOut(&clipRect);
987 // apply the canvas' translate to our local clip
988 clipRect.offset(DX, DY);
989 }
990
bsalomon@google.com91958362011-06-13 17:58:13 +0000991 int nx = bitmap.width() / maxTextureSize;
992 int ny = bitmap.height() / maxTextureSize;
reed@google.comac10a2d2010-12-22 21:39:39 +0000993 for (int x = 0; x <= nx; x++) {
994 for (int y = 0; y <= ny; y++) {
995 SkIRect tileR;
bsalomon@google.com91958362011-06-13 17:58:13 +0000996 tileR.set(x * maxTextureSize, y * maxTextureSize,
997 (x + 1) * maxTextureSize, (y + 1) * maxTextureSize);
reed@google.comac10a2d2010-12-22 21:39:39 +0000998 if (!SkIRect::Intersects(tileR, clipRect)) {
999 continue;
1000 }
1001
1002 SkIRect srcR = tileR;
1003 if (!srcR.intersect(srcRect)) {
1004 continue;
1005 }
1006
1007 SkBitmap tmpB;
1008 if (bitmap.extractSubset(&tmpB, tileR)) {
1009 // now offset it to make it "local" to our tmp bitmap
1010 srcR.offset(-tileR.fLeft, -tileR.fTop);
1011
1012 SkMatrix tmpM(m);
1013 {
1014 int dx = tileR.fLeft - DX + SkMax32(0, srcR.fLeft);
1015 int dy = tileR.fTop - DY + SkMax32(0, srcR.fTop);
1016 tmpM.preTranslate(SkIntToScalar(dx), SkIntToScalar(dy));
1017 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001018 this->internalDrawBitmap(draw, tmpB, srcR, tmpM, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +00001019 }
1020 }
1021 }
1022}
1023
1024/*
1025 * This is called by drawBitmap(), which has to handle images that may be too
1026 * large to be represented by a single texture.
1027 *
bsalomon@google.com5782d712011-01-21 21:03:59 +00001028 * internalDrawBitmap assumes that the specified bitmap will fit in a texture
1029 * and that non-texture portion of the GrPaint has already been setup.
reed@google.comac10a2d2010-12-22 21:39:39 +00001030 */
1031void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
1032 const SkBitmap& bitmap,
1033 const SkIRect& srcRect,
1034 const SkMatrix& m,
bsalomon@google.com5782d712011-01-21 21:03:59 +00001035 GrPaint* grPaint) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001036 SkASSERT(bitmap.width() <= fContext->getMaxTextureSize() &&
1037 bitmap.height() <= fContext->getMaxTextureSize());
reed@google.comac10a2d2010-12-22 21:39:39 +00001038
1039 SkAutoLockPixels alp(bitmap);
1040 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
1041 return;
1042 }
1043
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001044 GrSamplerState* sampler = grPaint->getTextureSampler(kBitmapTextureIdx);
1045
1046 sampler->setWrapX(GrSamplerState::kClamp_WrapMode);
1047 sampler->setWrapY(GrSamplerState::kClamp_WrapMode);
1048 sampler->setSampleMode(GrSamplerState::kNormal_SampleMode);
1049 sampler->setMatrix(GrMatrix::I());
reed@google.comac10a2d2010-12-22 21:39:39 +00001050
1051 GrTexture* texture;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001052 SkAutoCachedTexture act(this, bitmap, *sampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +00001053 if (NULL == texture) {
1054 return;
1055 }
1056
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001057 grPaint->setTexture(kShaderTextureIdx, texture);
reed@google.com46799cd2011-02-22 20:56:26 +00001058
reed@google.com20efde72011-05-09 17:00:02 +00001059 GrRect dstRect = SkRect::MakeWH(GrIntToScalar(srcRect.width()),
1060 GrIntToScalar(srcRect.height()));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001061 GrRect paintRect;
junov@google.com6acc9b32011-05-16 18:32:07 +00001062 paintRect.setLTRB(GrFixedToScalar((srcRect.fLeft << 16) / bitmap.width()),
1063 GrFixedToScalar((srcRect.fTop << 16) / bitmap.height()),
1064 GrFixedToScalar((srcRect.fRight << 16) / bitmap.width()),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001065 GrFixedToScalar((srcRect.fBottom << 16) / bitmap.height()));
reed@google.comac10a2d2010-12-22 21:39:39 +00001066
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001067 if (GrSamplerState::kNearest_Filter != sampler->getFilter() &&
junov@google.com6acc9b32011-05-16 18:32:07 +00001068 (srcRect.width() < bitmap.width() ||
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001069 srcRect.height() < bitmap.height())) {
junov@google.com6acc9b32011-05-16 18:32:07 +00001070 // If drawing a subrect of the bitmap and filtering is enabled,
1071 // use a constrained texture domain to avoid color bleeding
1072 GrScalar left, top, right, bottom;
1073 if (srcRect.width() > 1) {
1074 GrScalar border = GR_ScalarHalf / bitmap.width();
1075 left = paintRect.left() + border;
1076 right = paintRect.right() - border;
1077 } else {
1078 left = right = GrScalarHalf(paintRect.left() + paintRect.right());
1079 }
1080 if (srcRect.height() > 1) {
1081 GrScalar border = GR_ScalarHalf / bitmap.height();
1082 top = paintRect.top() + border;
1083 bottom = paintRect.bottom() - border;
1084 } else {
1085 top = bottom = GrScalarHalf(paintRect.top() + paintRect.bottom());
1086 }
1087 GrRect textureDomain;
1088 textureDomain.setLTRB(left, top, right, bottom);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001089 sampler->setTextureDomain(textureDomain);
junov@google.com6acc9b32011-05-16 18:32:07 +00001090 }
1091
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001092 fContext->drawRectToRect(*grPaint, dstRect, paintRect, &m);
reed@google.comac10a2d2010-12-22 21:39:39 +00001093}
1094
1095void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
1096 int left, int top, const SkPaint& paint) {
1097 CHECK_SHOULD_DRAW(draw);
1098
1099 SkAutoLockPixels alp(bitmap);
1100 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
1101 return;
1102 }
1103
bsalomon@google.com5782d712011-01-21 21:03:59 +00001104 GrPaint grPaint;
Scroggod757df22011-05-16 13:11:16 +00001105 if(!this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001106 return;
1107 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001108
bsalomon@google.com5782d712011-01-21 21:03:59 +00001109 GrAutoMatrix avm(fContext, GrMatrix::I());
1110
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001111 GrSamplerState* sampler = grPaint.getTextureSampler(kBitmapTextureIdx);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001112
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001113 GrTexture* texture;
1114 sampler->setClampNoFilter();
1115 SkAutoCachedTexture act(this, bitmap, *sampler, &texture);
1116
1117 grPaint.setTexture(kBitmapTextureIdx, texture);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001118
bsalomon@google.com5782d712011-01-21 21:03:59 +00001119 fContext->drawRectToRect(grPaint,
reed@google.com20efde72011-05-09 17:00:02 +00001120 GrRect::MakeXYWH(GrIntToScalar(left),
1121 GrIntToScalar(top),
1122 GrIntToScalar(bitmap.width()),
1123 GrIntToScalar(bitmap.height())),
1124 GrRect::MakeWH(GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001125}
1126
1127void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
1128 int x, int y, const SkPaint& paint) {
1129 CHECK_SHOULD_DRAW(draw);
1130
bsalomon@google.com5782d712011-01-21 21:03:59 +00001131 GrPaint grPaint;
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001132 if (!((SkGpuDevice*)dev)->bindDeviceAsTexture(&grPaint) ||
Scroggod757df22011-05-16 13:11:16 +00001133 !this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001134 return;
reed@google.comac10a2d2010-12-22 21:39:39 +00001135 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001136
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001137 GrTexture* devTex = grPaint.getTexture(0);
1138 SkASSERT(NULL != devTex);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001139
1140 const SkBitmap& bm = dev->accessBitmap(false);
1141 int w = bm.width();
1142 int h = bm.height();
1143
1144 GrAutoMatrix avm(fContext, GrMatrix::I());
1145
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001146 grPaint.getTextureSampler(kBitmapTextureIdx)->setClampNoFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +00001147
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001148 GrRect dstRect = GrRect::MakeXYWH(GrIntToScalar(x),
1149 GrIntToScalar(y),
1150 GrIntToScalar(w),
1151 GrIntToScalar(h));
1152 // The device being drawn may not fill up its texture (saveLayer uses
1153 // the approximate ).
1154 GrRect srcRect = GrRect::MakeWH(GR_Scalar1 * w / devTex->width(),
1155 GR_Scalar1 * h / devTex->height());
1156
1157 fContext->drawRectToRect(grPaint, dstRect, srcRect);
reed@google.comac10a2d2010-12-22 21:39:39 +00001158}
1159
1160///////////////////////////////////////////////////////////////////////////////
1161
1162// must be in SkCanvas::VertexMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +00001163static const GrPrimitiveType gVertexMode2PrimitiveType[] = {
1164 kTriangles_PrimitiveType,
1165 kTriangleStrip_PrimitiveType,
1166 kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +00001167};
1168
1169void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
1170 int vertexCount, const SkPoint vertices[],
1171 const SkPoint texs[], const SkColor colors[],
1172 SkXfermode* xmode,
1173 const uint16_t indices[], int indexCount,
1174 const SkPaint& paint) {
1175 CHECK_SHOULD_DRAW(draw);
1176
bsalomon@google.com5782d712011-01-21 21:03:59 +00001177 GrPaint grPaint;
1178 SkAutoCachedTexture act;
1179 // we ignore the shader if texs is null.
1180 if (NULL == texs) {
Scroggod757df22011-05-16 13:11:16 +00001181 if (!this->skPaint2GrPaintNoShader(paint,
1182 false,
1183 &grPaint,
1184 NULL == colors)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001185 return;
1186 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001187 } else {
reed@google.com1a2e8d22011-01-21 22:08:29 +00001188 if (!this->skPaint2GrPaintShader(paint, &act,
1189 *draw.fMatrix,
Scroggod757df22011-05-16 13:11:16 +00001190 &grPaint,
1191 NULL == colors)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001192 return;
1193 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001194 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001195
1196 if (NULL != xmode && NULL != texs && NULL != colors) {
1197 SkXfermode::Mode mode;
1198 if (!SkXfermode::IsMode(xmode, &mode) ||
1199 SkXfermode::kMultiply_Mode != mode) {
1200 SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
1201#if 0
1202 return
1203#endif
1204 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001205 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001206
1207#if SK_SCALAR_IS_GR_SCALAR
1208 // even if GrColor and SkColor byte offsets match we need
1209 // to perform pre-multiply.
1210 if (NULL == colors) {
1211 fContext->drawVertices(grPaint,
1212 gVertexMode2PrimitiveType[vmode],
1213 vertexCount,
1214 (GrPoint*) vertices,
1215 (GrPoint*) texs,
1216 NULL,
1217 indices,
1218 indexCount);
1219 } else
1220#endif
1221 {
1222 SkTexCoordSource texSrc(texs);
1223 SkColorSource colSrc(colors);
1224 SkIndexSource idxSrc(indices, indexCount);
1225
1226 fContext->drawCustomVertices(grPaint,
1227 gVertexMode2PrimitiveType[vmode],
1228 SkPositionSource(vertices, vertexCount),
1229 (NULL == texs) ? NULL : &texSrc,
1230 (NULL == colors) ? NULL : &colSrc,
1231 (NULL == indices) ? NULL : &idxSrc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001232 }
1233}
1234
1235///////////////////////////////////////////////////////////////////////////////
1236
1237static void GlyphCacheAuxProc(void* data) {
1238 delete (GrFontScaler*)data;
1239}
1240
1241static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) {
1242 void* auxData;
1243 GrFontScaler* scaler = NULL;
1244 if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
1245 scaler = (GrFontScaler*)auxData;
1246 }
1247 if (NULL == scaler) {
1248 scaler = new SkGrFontScaler(cache);
1249 cache->setAuxProc(GlyphCacheAuxProc, scaler);
1250 }
1251 return scaler;
1252}
1253
1254static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
1255 SkFixed fx, SkFixed fy,
1256 const SkGlyph& glyph) {
1257 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1258
1259 GrSkDrawProcs* procs = (GrSkDrawProcs*)state.fDraw->fProcs;
1260
1261 if (NULL == procs->fFontScaler) {
1262 procs->fFontScaler = get_gr_font_scaler(state.fCache);
1263 }
reed@google.com39ce0ac2011-04-08 15:42:19 +00001264
1265 /*
reed@google.com3b139f52011-06-07 17:56:25 +00001266 * What should we do with fy? (assuming horizontal/latin text)
reed@google.com39ce0ac2011-04-08 15:42:19 +00001267 *
reed@google.com3b139f52011-06-07 17:56:25 +00001268 * The raster code calls SkFixedFloorToFixed on it, as it does with fx.
1269 * It calls that rather than round, because our caller has already added
1270 * SK_FixedHalf, so that calling floor gives us the rounded integer.
1271 *
1272 * Test code between raster and gpu (they should draw the same)
1273 *
1274 * canvas->drawText("Hamburgefons", 12, 0, 16.5f, paint);
1275 *
1276 * Perhaps we should only perform this integralization if there is no
1277 * fExtMatrix...
reed@google.com39ce0ac2011-04-08 15:42:19 +00001278 */
reed@google.com3b139f52011-06-07 17:56:25 +00001279 fy = SkFixedFloorToFixed(fy);
1280
reed@google.comac10a2d2010-12-22 21:39:39 +00001281 procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0),
reed@google.com3b139f52011-06-07 17:56:25 +00001282 SkFixedFloorToFixed(fx), fy,
reed@google.comac10a2d2010-12-22 21:39:39 +00001283 procs->fFontScaler);
1284}
1285
bsalomon@google.com5782d712011-01-21 21:03:59 +00001286SkDrawProcs* SkGpuDevice::initDrawForText(GrTextContext* context) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001287
1288 // deferred allocation
1289 if (NULL == fDrawProcs) {
1290 fDrawProcs = new GrSkDrawProcs;
1291 fDrawProcs->fD1GProc = SkGPU_Draw1Glyph;
1292 fDrawProcs->fContext = fContext;
1293 }
1294
1295 // init our (and GL's) state
1296 fDrawProcs->fTextContext = context;
1297 fDrawProcs->fFontScaler = NULL;
1298 return fDrawProcs;
1299}
1300
1301void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
1302 size_t byteLength, SkScalar x, SkScalar y,
1303 const SkPaint& paint) {
1304 CHECK_SHOULD_DRAW(draw);
1305
1306 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1307 // this guy will just call our drawPath()
1308 draw.drawText((const char*)text, byteLength, x, y, paint);
1309 } else {
reed@google.comac10a2d2010-12-22 21:39:39 +00001310 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001311
1312 GrPaint grPaint;
1313 SkAutoCachedTexture act;
1314
Scroggod757df22011-05-16 13:11:16 +00001315 if (!this->skPaint2GrPaintShader(paint,
1316 &act,
1317 *draw.fMatrix,
1318 &grPaint,
1319 true)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001320 return;
1321 }
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001322 GrTextContext context(fContext, grPaint, draw.fExtMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001323 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001324 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
1325 }
1326}
1327
1328void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
1329 size_t byteLength, const SkScalar pos[],
1330 SkScalar constY, int scalarsPerPos,
1331 const SkPaint& paint) {
1332 CHECK_SHOULD_DRAW(draw);
1333
1334 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1335 // this guy will just call our drawPath()
1336 draw.drawPosText((const char*)text, byteLength, pos, constY,
1337 scalarsPerPos, paint);
1338 } else {
reed@google.comac10a2d2010-12-22 21:39:39 +00001339 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001340
1341 GrPaint grPaint;
1342 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +00001343 if (!this->skPaint2GrPaintShader(paint,
1344 &act,
1345 *draw.fMatrix,
1346 &grPaint,
1347 true)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001348 return;
1349 }
1350
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001351 GrTextContext context(fContext, grPaint, draw.fExtMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001352 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001353 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
1354 scalarsPerPos, paint);
1355 }
1356}
1357
1358void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
1359 size_t len, const SkPath& path,
1360 const SkMatrix* m, const SkPaint& paint) {
1361 CHECK_SHOULD_DRAW(draw);
1362
1363 SkASSERT(draw.fDevice == this);
1364 draw.drawTextOnPath((const char*)text, len, path, m, paint);
1365}
1366
1367///////////////////////////////////////////////////////////////////////////////
1368
reed@google.comf67e4cf2011-03-15 20:56:58 +00001369bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
1370 if (!paint.isLCDRenderText()) {
1371 // we're cool with the paint as is
1372 return false;
1373 }
1374
1375 if (paint.getShader() ||
1376 paint.getXfermode() || // unless its srcover
1377 paint.getMaskFilter() ||
1378 paint.getRasterizer() ||
1379 paint.getColorFilter() ||
1380 paint.getPathEffect() ||
1381 paint.isFakeBoldText() ||
1382 paint.getStyle() != SkPaint::kFill_Style) {
1383 // turn off lcd
1384 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
1385 flags->fHinting = paint.getHinting();
1386 return true;
1387 }
1388 // we're cool with the paint as is
1389 return false;
1390}
1391
1392///////////////////////////////////////////////////////////////////////////////
1393
reed@google.comac10a2d2010-12-22 21:39:39 +00001394SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001395 const GrSamplerState& sampler,
1396 GrTexture** texture,
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001397 bool forDeviceRenderTarget,
1398 bool isSaveLayer) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001399 GrTexture* newTexture = NULL;
1400 GrTextureEntry* entry = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +00001401 GrContext* ctx = this->context();
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001402
reed@google.comac10a2d2010-12-22 21:39:39 +00001403 if (forDeviceRenderTarget) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001404 const GrTextureDesc desc = {
1405 kRenderTarget_GrTextureFlagBit,
1406 kNone_GrAALevel,
1407 bitmap.width(),
1408 bitmap.height(),
1409 SkGr::Bitmap2PixelConfig(bitmap)
1410 };
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001411 if (isSaveLayer) {
1412 // we know layers will only be drawn through drawDevice.
1413 // drawDevice has been made to work with content embedded in a
1414 // larger texture so its okay to use the approximate version.
1415 entry = ctx->findApproximateKeylessTexture(desc);
1416 } else {
1417 entry = ctx->lockKeylessTexture(desc);
1418 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001419 } else {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001420 uint32_t p0, p1;
reed@google.comac10a2d2010-12-22 21:39:39 +00001421 p0 = bitmap.getGenerationID();
1422 p1 = bitmap.pixelRefOffset();
reed@google.comac10a2d2010-12-22 21:39:39 +00001423
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001424 GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
1425 entry = ctx->findAndLockTexture(&key, sampler);
reed@google.comac10a2d2010-12-22 21:39:39 +00001426
reed@google.comac10a2d2010-12-22 21:39:39 +00001427 if (NULL == entry) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001428 entry = sk_gr_create_bitmap_texture(ctx, &key, sampler, bitmap);
1429 if (NULL == entry) {
1430 GrPrintf("---- failed to create texture for cache [%d %d]\n",
1431 bitmap.width(), bitmap.height());
1432 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001433 }
1434 }
1435
1436 if (NULL != entry) {
1437 newTexture = entry->texture();
reed@google.comac10a2d2010-12-22 21:39:39 +00001438 if (texture) {
1439 *texture = newTexture;
1440 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001441 }
1442 return (TexCache*)entry;
1443}
1444
1445void SkGpuDevice::unlockCachedTexture(TexCache* cache) {
1446 this->context()->unlockTexture((GrTextureEntry*)cache);
1447}
1448
reed@google.com7b201d22011-01-11 18:59:23 +00001449///////////////////////////////////////////////////////////////////////////////
1450
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001451SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context,
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001452 GrRenderTarget* rootRenderTarget) {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001453 GrAssert(NULL != context);
1454 GrAssert(NULL != rootRenderTarget);
1455
1456 // check this now rather than passing this value to SkGpuDevice cons.
1457 // we want the rt that is bound *now* in the 3D API, not the one
1458 // at the time of newDevice.
1459 if (SkGpuDevice::Current3DApiRenderTarget() == rootRenderTarget) {
1460 fRootRenderTarget = context->createRenderTargetFrom3DApiState();
1461 } else {
1462 fRootRenderTarget = rootRenderTarget;
1463 rootRenderTarget->ref();
1464 }
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001465
1466 fContext = context;
reed@google.com7b201d22011-01-11 18:59:23 +00001467 context->ref();
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001468
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001469 fRootTexture = NULL;
1470}
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001471
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001472SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context, GrTexture* rootRenderTargetTexture) {
1473 GrAssert(NULL != context);
1474 GrAssert(NULL != rootRenderTargetTexture);
1475 GrAssert(NULL != rootRenderTargetTexture->asRenderTarget());
1476
1477 fRootTexture = rootRenderTargetTexture;
1478 rootRenderTargetTexture->ref();
1479
1480 fRootRenderTarget = rootRenderTargetTexture->asRenderTarget();
1481 fRootRenderTarget->ref();
1482
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001483 fContext = context;
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001484 context->ref();
reed@google.com7b201d22011-01-11 18:59:23 +00001485}
1486
1487SkGpuDeviceFactory::~SkGpuDeviceFactory() {
1488 fContext->unref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001489 fRootRenderTarget->unref();
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001490 GrSafeUnref(fRootTexture);
reed@google.com7b201d22011-01-11 18:59:23 +00001491}
1492
1493SkDevice* SkGpuDeviceFactory::newDevice(SkCanvas*, SkBitmap::Config config,
1494 int width, int height,
1495 bool isOpaque, bool isLayer) {
reed@google.comaf951c92011-06-16 19:10:39 +00001496 if (isLayer) {
1497 return SkNEW_ARGS(SkGpuDevice, (fContext, config, width, height));
1498 } else {
1499 return SkNEW_ARGS(SkGpuDevice, (fContext, fRootRenderTarget));
1500 }
reed@google.com7b201d22011-01-11 18:59:23 +00001501}