blob: 360fa3429c94c224776b240959ce2d7d6cacf272 [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
reed@google.comac10a2d2010-12-22 21:39:39 +000043///////////////////////////////////////////////////////////////////////////////
44
45SkGpuDevice::SkAutoCachedTexture::
46 SkAutoCachedTexture(SkGpuDevice* device,
47 const SkBitmap& bitmap,
48 const GrSamplerState& sampler,
49 GrTexture** texture) {
50 GrAssert(texture);
51 fTex = NULL;
52 *texture = this->set(device, bitmap, sampler);
53}
54
55SkGpuDevice::SkAutoCachedTexture::SkAutoCachedTexture() {
56 fTex = NULL;
57}
58
59GrTexture* SkGpuDevice::SkAutoCachedTexture::set(SkGpuDevice* device,
60 const SkBitmap& bitmap,
61 const GrSamplerState& sampler) {
62 if (fTex) {
63 fDevice->unlockCachedTexture(fTex);
64 }
65 fDevice = device;
66 GrTexture* texture = (GrTexture*)bitmap.getTexture();
67 if (texture) {
68 // return the native texture
69 fTex = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +000070 } else {
71 // look it up in our cache
72 fTex = device->lockCachedTexture(bitmap, sampler, &texture, false);
73 }
74 return texture;
75}
76
77SkGpuDevice::SkAutoCachedTexture::~SkAutoCachedTexture() {
78 if (fTex) {
79 fDevice->unlockCachedTexture(fTex);
80 }
81}
82
83///////////////////////////////////////////////////////////////////////////////
84
85bool gDoTraceDraw;
86
87struct GrSkDrawProcs : public SkDrawProcs {
88public:
89 GrContext* fContext;
90 GrTextContext* fTextContext;
91 GrFontScaler* fFontScaler; // cached in the skia glyphcache
92};
93
94///////////////////////////////////////////////////////////////////////////////
95
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +000096GrRenderTarget* SkGpuDevice::Current3DApiRenderTarget() {
97 return (GrRenderTarget*) -1;
98}
99
100SkGpuDevice::SkGpuDevice(GrContext* context,
101 const SkBitmap& bitmap,
102 GrRenderTarget* renderTargetOrNull)
103 : SkDevice(NULL, bitmap, (NULL == renderTargetOrNull)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000104
105 fNeedPrepareRenderTarget = false;
106 fDrawProcs = NULL;
107
reed@google.com7b201d22011-01-11 18:59:23 +0000108 fContext = context;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000109 fContext->ref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000110
111 fCache = NULL;
112 fTexture = NULL;
113 fRenderTarget = NULL;
114 fNeedClear = false;
115
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000116 if (NULL == renderTargetOrNull) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000117 SkBitmap::Config c = bitmap.config();
118 if (c != SkBitmap::kRGB_565_Config) {
119 c = SkBitmap::kARGB_8888_Config;
120 }
121 SkBitmap bm;
122 bm.setConfig(c, this->width(), this->height());
123
124#if CACHE_LAYER_TEXTURES
125
126 fCache = this->lockCachedTexture(bm, GrSamplerState::ClampNoFilter(),
127 &fTexture, true);
128 if (fCache) {
129 SkASSERT(NULL != fTexture);
bsalomon@google.com1da07462011-03-10 14:51:57 +0000130 SkASSERT(NULL != fTexture->asRenderTarget());
reed@google.comac10a2d2010-12-22 21:39:39 +0000131 }
132#else
133 const GrGpu::TextureDesc desc = {
134 GrGpu::kRenderTarget_TextureFlag,
135 GrGpu::kNone_AALevel,
136 this->width(),
137 this->height(),
138 SkGr::Bitmap2PixelConfig(bm)
139 };
140
141 fTexture = fContext->createUncachedTexture(desc, NULL, 0);
142#endif
143 if (NULL != fTexture) {
144 fRenderTarget = fTexture->asRenderTarget();
145
146 GrAssert(NULL != fRenderTarget);
147
148 // we defer the actual clear until our gainFocus()
149 fNeedClear = true;
150
151 // wrap the bitmap with a pixelref to expose our texture
152 SkGrTexturePixelRef* pr = new SkGrTexturePixelRef(fTexture);
153 this->setPixelRef(pr, 0)->unref();
154 } else {
155 GrPrintf("--- failed to create gpu-offscreen [%d %d]\n",
156 this->width(), this->height());
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000157 GrAssert(false);
reed@google.comac10a2d2010-12-22 21:39:39 +0000158 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000159 } else {
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000160 if (Current3DApiRenderTarget() == renderTargetOrNull) {
161 fRenderTarget = fContext->createRenderTargetFrom3DApiState();
162 } else {
163 fRenderTarget = renderTargetOrNull;
164 fRenderTarget->ref();
165 }
166 SkGrRenderTargetPixelRef* pr = new SkGrRenderTargetPixelRef(fRenderTarget);
167 this->setPixelRef(pr, 0)->unref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000168 }
169}
170
171SkGpuDevice::~SkGpuDevice() {
172 if (fDrawProcs) {
173 delete fDrawProcs;
174 }
175
176 if (fCache) {
177 GrAssert(NULL != fTexture);
178 GrAssert(fRenderTarget == fTexture->asRenderTarget());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000179 fContext->unlockTexture((GrTextureEntry*)fCache);
reed@google.comac10a2d2010-12-22 21:39:39 +0000180 } else if (NULL != fTexture) {
181 GrAssert(!CACHE_LAYER_TEXTURES);
182 GrAssert(fRenderTarget == fTexture->asRenderTarget());
183 fTexture->unref();
184 } else if (NULL != fRenderTarget) {
185 fRenderTarget->unref();
186 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000187 fContext->unref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000188}
189
reed@google.comac10a2d2010-12-22 21:39:39 +0000190intptr_t SkGpuDevice::getLayerTextureHandle() const {
191 if (fTexture) {
192 return fTexture->getTextureHandle();
193 } else {
194 return 0;
195 }
196}
mike@reedtribe.orgea4ac972011-04-26 11:48:33 +0000197
198SkDeviceFactory* SkGpuDevice::onNewDeviceFactory() {
199 return SkNEW_ARGS(SkGpuDeviceFactory, (fContext, fRenderTarget));
200}
201
reed@google.comac10a2d2010-12-22 21:39:39 +0000202///////////////////////////////////////////////////////////////////////////////
203
204void SkGpuDevice::makeRenderTargetCurrent() {
205 fContext->setRenderTarget(fRenderTarget);
206 fContext->flush(true);
207 fNeedPrepareRenderTarget = true;
208}
209
210///////////////////////////////////////////////////////////////////////////////
211
212bool SkGpuDevice::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
213 SkIRect bounds;
214 bounds.set(0, 0, this->width(), this->height());
215 if (!bounds.intersect(srcRect)) {
216 return false;
217 }
218
219 const int w = bounds.width();
220 const int h = bounds.height();
221 SkBitmap tmp;
222 // note we explicitly specify our rowBytes to be snug (no gap between rows)
223 tmp.setConfig(SkBitmap::kARGB_8888_Config, w, h, w * 4);
224 if (!tmp.allocPixels()) {
225 return false;
226 }
227
Scroggo813c33c2011-04-07 20:56:21 +0000228 tmp.lockPixels();
reed@google.comac10a2d2010-12-22 21:39:39 +0000229
Scroggoeb176032011-04-07 21:11:49 +0000230 bool read = fContext->readRenderTargetPixels(fRenderTarget,
231 bounds.fLeft, bounds.fTop,
232 bounds.width(), bounds.height(),
233 kRGBA_8888_GrPixelConfig,
234 tmp.getPixels());
Scroggo813c33c2011-04-07 20:56:21 +0000235 tmp.unlockPixels();
236 if (!read) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000237 return false;
238 }
239
240 tmp.swap(*bitmap);
241 return true;
242}
243
244void SkGpuDevice::writePixels(const SkBitmap& bitmap, int x, int y) {
245 SkAutoLockPixels alp(bitmap);
246 if (!bitmap.readyToDraw()) {
247 return;
248 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000249 GrPixelConfig config = SkGr::BitmapConfig2PixelConfig(bitmap.config(),
250 bitmap.isOpaque());
reed@google.comac10a2d2010-12-22 21:39:39 +0000251 fContext->setRenderTarget(fRenderTarget);
252 // we aren't setting the clip or matrix, so mark as dirty
253 // we don't need to set them for this call and don't have them anyway
254 fNeedPrepareRenderTarget = true;
255
256 fContext->writePixels(x, y, bitmap.width(), bitmap.height(),
257 config, bitmap.getPixels(), bitmap.rowBytes());
258}
259
260///////////////////////////////////////////////////////////////////////////////
261
262static void convert_matrixclip(GrContext* context, const SkMatrix& matrix,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000263 const SkClipStack& clipStack,
reed@google.com6f8f2922011-03-04 22:27:10 +0000264 const SkRegion& clipRegion,
265 const SkIPoint& origin) {
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000266 context->setMatrix(matrix);
reed@google.comac10a2d2010-12-22 21:39:39 +0000267
268 SkGrClipIterator iter;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000269 iter.reset(clipStack);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000270 const SkIRect& skBounds = clipRegion.getBounds();
271 GrRect bounds;
272 bounds.setLTRB(GrIntToScalar(skBounds.fLeft),
273 GrIntToScalar(skBounds.fTop),
274 GrIntToScalar(skBounds.fRight),
275 GrIntToScalar(skBounds.fBottom));
reed@google.com6f8f2922011-03-04 22:27:10 +0000276 GrClip grc(&iter, GrIntToScalar(-origin.x()), GrIntToScalar(-origin.y()),
277 &bounds);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000278 context->setClip(grc);
reed@google.comac10a2d2010-12-22 21:39:39 +0000279}
280
281// call this ever each draw call, to ensure that the context reflects our state,
282// and not the state from some other canvas/device
283void SkGpuDevice::prepareRenderTarget(const SkDraw& draw) {
284 if (fNeedPrepareRenderTarget ||
bsalomon@google.com5782d712011-01-21 21:03:59 +0000285 fContext->getRenderTarget() != fRenderTarget) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000286
287 fContext->setRenderTarget(fRenderTarget);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000288 SkASSERT(draw.fClipStack);
289 convert_matrixclip(fContext, *draw.fMatrix,
reed@google.com6f8f2922011-03-04 22:27:10 +0000290 *draw.fClipStack, *draw.fClip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000291 fNeedPrepareRenderTarget = false;
292 }
293}
294
reed@google.com46799cd2011-02-22 20:56:26 +0000295void SkGpuDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& clip,
296 const SkClipStack& clipStack) {
297 this->INHERITED::setMatrixClip(matrix, clip, clipStack);
bsalomon@google.coma7bf6e22011-04-11 19:20:46 +0000298 // We don't need to set them now because the context may not reflect this device.
299 fNeedPrepareRenderTarget = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000300}
301
302void SkGpuDevice::gainFocus(SkCanvas* canvas, const SkMatrix& matrix,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000303 const SkRegion& clip, const SkClipStack& clipStack) {
304
reed@google.comac10a2d2010-12-22 21:39:39 +0000305 fContext->setRenderTarget(fRenderTarget);
306
bsalomon@google.comd302f142011-03-03 13:54:13 +0000307 this->INHERITED::gainFocus(canvas, matrix, clip, clipStack);
reed@google.comac10a2d2010-12-22 21:39:39 +0000308
reed@google.com6f8f2922011-03-04 22:27:10 +0000309 convert_matrixclip(fContext, matrix, clipStack, clip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000310
311 if (fNeedClear) {
bsalomon@google.com31a58402011-04-27 21:00:02 +0000312 fContext->clear(NULL, 0x0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000313 fNeedClear = false;
314 }
315}
316
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000317bool SkGpuDevice::bindDeviceAsTexture(GrPaint* paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000318 if (NULL != fTexture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000319 paint->setTexture(fTexture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000320 return true;
321 }
322 return false;
323}
324
325///////////////////////////////////////////////////////////////////////////////
326
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000327SK_COMPILE_ASSERT(SkShader::kNone_BitmapType == 0, shader_type_mismatch);
328SK_COMPILE_ASSERT(SkShader::kDefault_BitmapType == 1, shader_type_mismatch);
329SK_COMPILE_ASSERT(SkShader::kRadial_BitmapType == 2, shader_type_mismatch);
330SK_COMPILE_ASSERT(SkShader::kSweep_BitmapType == 3, shader_type_mismatch);
331SK_COMPILE_ASSERT(SkShader::kTwoPointRadial_BitmapType == 4,
332 shader_type_mismatch);
333SK_COMPILE_ASSERT(SkShader::kLast_BitmapType == 4, shader_type_mismatch);
reed@google.comac10a2d2010-12-22 21:39:39 +0000334
bsalomon@google.com5782d712011-01-21 21:03:59 +0000335static const GrSamplerState::SampleMode sk_bmp_type_to_sample_mode[] = {
336 (GrSamplerState::SampleMode) -1, // kNone_BitmapType
337 GrSamplerState::kNormal_SampleMode, // kDefault_BitmapType
338 GrSamplerState::kRadial_SampleMode, // kRadial_BitmapType
339 GrSamplerState::kSweep_SampleMode, // kSweep_BitmapType
340 GrSamplerState::kRadial2_SampleMode, // kTwoPointRadial_BitmapType
341};
342
343bool SkGpuDevice::skPaint2GrPaintNoShader(const SkPaint& skPaint,
344 bool justAlpha,
Scroggod757df22011-05-16 13:11:16 +0000345 GrPaint* grPaint,
346 bool constantColor) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000347
348 grPaint->fDither = skPaint.isDither();
349 grPaint->fAntiAlias = skPaint.isAntiAlias();
350
351 SkXfermode::Coeff sm = SkXfermode::kOne_Coeff;
352 SkXfermode::Coeff dm = SkXfermode::kISA_Coeff;
353
354 SkXfermode* mode = skPaint.getXfermode();
355 if (mode) {
356 if (!mode->asCoeff(&sm, &dm)) {
reed@google.com1a2e8d22011-01-21 22:08:29 +0000357 SkDEBUGCODE(SkDebugf("Unsupported xfer mode.\n");)
bsalomon@google.com5782d712011-01-21 21:03:59 +0000358#if 0
359 return false;
360#endif
361 }
362 }
363 grPaint->fSrcBlendCoeff = sk_blend_to_grblend(sm);
364 grPaint->fDstBlendCoeff = sk_blend_to_grblend(dm);
365
366 if (justAlpha) {
367 uint8_t alpha = skPaint.getAlpha();
368 grPaint->fColor = GrColorPackRGBA(alpha, alpha, alpha, alpha);
Scroggod757df22011-05-16 13:11:16 +0000369 // justAlpha is currently set to true only if there is a texture,
370 // so constantColor should not also be true.
371 GrAssert(!constantColor);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000372 } else {
373 grPaint->fColor = SkGr::SkColor2GrColor(skPaint.getColor());
374 grPaint->setTexture(NULL);
375 }
Scroggo97c88c22011-05-11 14:05:25 +0000376 SkColorFilter* colorFilter = skPaint.getColorFilter();
377 SkColor color;
378 SkXfermode::Mode filterMode;
379 if (colorFilter != NULL && colorFilter->asColorMode(&color, &filterMode)) {
Scroggod757df22011-05-16 13:11:16 +0000380 if (!constantColor) {
381 grPaint->fColorFilterColor = SkGr::SkColor2GrColor(color);
382 grPaint->fColorFilterXfermode = filterMode;
383 return true;
384 }
385 SkColor filtered = colorFilter->filterColor(skPaint.getColor());
386 grPaint->fColor = SkGr::SkColor2GrColor(filtered);
Scroggo97c88c22011-05-11 14:05:25 +0000387 }
Scroggod757df22011-05-16 13:11:16 +0000388 grPaint->resetColorFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +0000389 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000390}
391
bsalomon@google.com5782d712011-01-21 21:03:59 +0000392bool SkGpuDevice::skPaint2GrPaintShader(const SkPaint& skPaint,
393 SkAutoCachedTexture* act,
394 const SkMatrix& ctm,
Scroggod757df22011-05-16 13:11:16 +0000395 GrPaint* grPaint,
396 bool constantColor) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000397
bsalomon@google.com5782d712011-01-21 21:03:59 +0000398 SkASSERT(NULL != act);
reed@google.comac10a2d2010-12-22 21:39:39 +0000399
bsalomon@google.com5782d712011-01-21 21:03:59 +0000400 SkShader* shader = skPaint.getShader();
reed@google.comac10a2d2010-12-22 21:39:39 +0000401 if (NULL == shader) {
Scroggod757df22011-05-16 13:11:16 +0000402 return this->skPaint2GrPaintNoShader(skPaint,
403 false,
404 grPaint,
405 constantColor);
406 } else if (!this->skPaint2GrPaintNoShader(skPaint, true, grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000407 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000408 }
409
bsalomon@google.com5782d712011-01-21 21:03:59 +0000410 SkPaint noAlphaPaint(skPaint);
411 noAlphaPaint.setAlpha(255);
412 shader->setContext(this->accessBitmap(false), noAlphaPaint, ctm);
reed@google.comac10a2d2010-12-22 21:39:39 +0000413
reed@google.comac10a2d2010-12-22 21:39:39 +0000414 SkBitmap bitmap;
415 SkMatrix matrix;
416 SkShader::TileMode tileModes[2];
417 SkScalar twoPointParams[3];
418 SkShader::BitmapType bmptype = shader->asABitmap(&bitmap, &matrix,
419 tileModes, twoPointParams);
420
bsalomon@google.com5782d712011-01-21 21:03:59 +0000421 GrSamplerState::SampleMode sampleMode = sk_bmp_type_to_sample_mode[bmptype];
422 if (-1 == sampleMode) {
423 SkDebugf("shader->asABitmap() == kNone_BitmapType\n");
424 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000425 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000426 grPaint->fSampler.setSampleMode(sampleMode);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000427 if (skPaint.isFilterBitmap()) {
428 grPaint->fSampler.setFilter(GrSamplerState::kBilinear_Filter);
429 } else {
430 grPaint->fSampler.setFilter(GrSamplerState::kNearest_Filter);
431 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000432 grPaint->fSampler.setWrapX(sk_tile_mode_to_grwrap(tileModes[0]));
433 grPaint->fSampler.setWrapY(sk_tile_mode_to_grwrap(tileModes[1]));
reed@google.comac10a2d2010-12-22 21:39:39 +0000434 if (GrSamplerState::kRadial2_SampleMode == sampleMode) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000435 grPaint->fSampler.setRadial2Params(twoPointParams[0],
436 twoPointParams[1],
437 twoPointParams[2] < 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000438 }
439
bsalomon@google.com5782d712011-01-21 21:03:59 +0000440 GrTexture* texture = act->set(this, bitmap, grPaint->fSampler);
reed@google.comac10a2d2010-12-22 21:39:39 +0000441 if (NULL == texture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000442 SkDebugf("Couldn't convert bitmap to texture.\n");
443 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000444 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000445 grPaint->setTexture(texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000446
447 // since our texture coords will be in local space, we wack the texture
448 // matrix to map them back into 0...1 before we load it
449 SkMatrix localM;
450 if (shader->getLocalMatrix(&localM)) {
451 SkMatrix inverse;
452 if (localM.invert(&inverse)) {
453 matrix.preConcat(inverse);
454 }
455 }
456 if (SkShader::kDefault_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000457 GrScalar sx = GrFixedToScalar(GR_Fixed1 / bitmap.width());
458 GrScalar sy = GrFixedToScalar(GR_Fixed1 / bitmap.height());
reed@google.comac10a2d2010-12-22 21:39:39 +0000459 matrix.postScale(sx, sy);
reed@google.comac10a2d2010-12-22 21:39:39 +0000460 } else if (SkShader::kRadial_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000461 GrScalar s = GrFixedToScalar(GR_Fixed1 / bitmap.width());
reed@google.comac10a2d2010-12-22 21:39:39 +0000462 matrix.postScale(s, s);
463 }
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000464 grPaint->fSampler.setMatrix(matrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000465
466 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000467}
468
469///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com5782d712011-01-21 21:03:59 +0000470
471class SkPositionSource {
472public:
473 SkPositionSource(const SkPoint* points, int count)
474 : fPoints(points), fCount(count) {}
475
476 int count() const { return fCount; }
477
478 void writeValue(int i, GrPoint* dstPosition) const {
479 SkASSERT(i < fCount);
480 dstPosition->fX = SkScalarToGrScalar(fPoints[i].fX);
481 dstPosition->fY = SkScalarToGrScalar(fPoints[i].fY);
482 }
483private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000484 const SkPoint* fPoints;
bsalomon@google.com19628322011-02-03 21:30:17 +0000485 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000486};
487
488class SkTexCoordSource {
489public:
490 SkTexCoordSource(const SkPoint* coords)
491 : fCoords(coords) {}
492
493 void writeValue(int i, GrPoint* dstCoord) const {
494 dstCoord->fX = SkScalarToGrScalar(fCoords[i].fX);
495 dstCoord->fY = SkScalarToGrScalar(fCoords[i].fY);
496 }
497private:
498 const SkPoint* fCoords;
499};
500
501class SkColorSource {
502public:
503 SkColorSource(const SkColor* colors) : fColors(colors) {}
504
505 void writeValue(int i, GrColor* dstColor) const {
506 *dstColor = SkGr::SkColor2GrColor(fColors[i]);
507 }
508private:
509 const SkColor* fColors;
510};
511
512class SkIndexSource {
513public:
514 SkIndexSource(const uint16_t* indices, int count)
515 : fIndices(indices), fCount(count) {
516 }
517
518 int count() const { return fCount; }
519
520 void writeValue(int i, uint16_t* dstIndex) const {
521 *dstIndex = fIndices[i];
522 }
523
524private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000525 const uint16_t* fIndices;
bsalomon@google.com19628322011-02-03 21:30:17 +0000526 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000527};
528
529///////////////////////////////////////////////////////////////////////////////
530
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000531#if 0 // not currently being used so don't compile,
532
bsalomon@google.com5782d712011-01-21 21:03:59 +0000533// can be used for positions or texture coordinates
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000534
bsalomon@google.com5782d712011-01-21 21:03:59 +0000535class SkRectFanSource {
536public:
537 SkRectFanSource(const SkRect& rect) : fRect(rect) {}
538
539 int count() const { return 4; }
540
541 void writeValue(int i, GrPoint* dstPoint) const {
542 SkASSERT(i < 4);
543 dstPoint->fX = SkScalarToGrScalar((i % 3) ? fRect.fRight :
544 fRect.fLeft);
545 dstPoint->fY = SkScalarToGrScalar((i < 2) ? fRect.fTop :
546 fRect.fBottom);
547 }
548private:
549 const SkRect& fRect;
550};
551
552class SkIRectFanSource {
553public:
554 SkIRectFanSource(const SkIRect& rect) : fRect(rect) {}
555
556 int count() const { return 4; }
557
558 void writeValue(int i, GrPoint* dstPoint) const {
559 SkASSERT(i < 4);
560 dstPoint->fX = (i % 3) ? GrIntToScalar(fRect.fRight) :
561 GrIntToScalar(fRect.fLeft);
562 dstPoint->fY = (i < 2) ? GrIntToScalar(fRect.fTop) :
563 GrIntToScalar(fRect.fBottom);
564 }
565private:
566 const SkIRect& fRect;
567};
568
569class SkMatRectFanSource {
570public:
571 SkMatRectFanSource(const SkRect& rect, const SkMatrix& matrix)
572 : fRect(rect), fMatrix(matrix) {}
573
574 int count() const { return 4; }
575
576 void writeValue(int i, GrPoint* dstPoint) const {
577 SkASSERT(i < 4);
578
579#if SK_SCALAR_IS_GR_SCALAR
580 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
581 (i < 2) ? fRect.fTop : fRect.fBottom,
582 (SkPoint*)dstPoint);
583#else
584 SkPoint dst;
585 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
586 (i < 2) ? fRect.fTop : fRect.fBottom,
587 &dst);
588 dstPoint->fX = SkScalarToGrScalar(dst.fX);
589 dstPoint->fY = SkScalarToGrScalar(dst.fY);
590#endif
591 }
592private:
593 const SkRect& fRect;
594 const SkMatrix& fMatrix;
595};
596
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000597#endif
598
reed@google.comac10a2d2010-12-22 21:39:39 +0000599///////////////////////////////////////////////////////////////////////////////
600
bsalomon@google.com398109c2011-04-14 18:40:27 +0000601void SkGpuDevice::clear(SkColor color) {
bsalomon@google.com31a58402011-04-27 21:00:02 +0000602 fContext->clear(NULL, color);
bsalomon@google.com398109c2011-04-14 18:40:27 +0000603}
604
reed@google.comac10a2d2010-12-22 21:39:39 +0000605void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
606 CHECK_SHOULD_DRAW(draw);
607
bsalomon@google.com5782d712011-01-21 21:03:59 +0000608 GrPaint grPaint;
609 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000610 if (!this->skPaint2GrPaintShader(paint,
611 &act,
612 *draw.fMatrix,
613 &grPaint,
614 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000615 return;
616 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000617
618 fContext->drawPaint(grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000619}
620
621// must be in SkCanvas::PointMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +0000622static const GrPrimitiveType gPointMode2PrimtiveType[] = {
623 kPoints_PrimitiveType,
624 kLines_PrimitiveType,
625 kLineStrip_PrimitiveType
reed@google.comac10a2d2010-12-22 21:39:39 +0000626};
627
628void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000629 size_t count, const SkPoint pts[], const SkPaint& paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000630 CHECK_SHOULD_DRAW(draw);
631
632 SkScalar width = paint.getStrokeWidth();
633 if (width < 0) {
634 return;
635 }
636
637 // we only handle hairlines here, else we let the SkDraw call our drawPath()
638 if (width > 0) {
639 draw.drawPoints(mode, count, pts, paint, true);
640 return;
641 }
642
bsalomon@google.com5782d712011-01-21 21:03:59 +0000643 GrPaint grPaint;
644 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000645 if (!this->skPaint2GrPaintShader(paint,
646 &act,
647 *draw.fMatrix,
648 &grPaint,
649 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000650 return;
651 }
652
reed@google.comac10a2d2010-12-22 21:39:39 +0000653#if SK_SCALAR_IS_GR_SCALAR
bsalomon@google.com5782d712011-01-21 21:03:59 +0000654 fContext->drawVertices(grPaint,
655 gPointMode2PrimtiveType[mode],
656 count,
657 (GrPoint*)pts,
658 NULL,
659 NULL,
660 NULL,
661 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000662#else
bsalomon@google.com5782d712011-01-21 21:03:59 +0000663 fContext->drawCustomVertices(grPaint,
664 gPointMode2PrimtiveType[mode],
665 SkPositionSource(pts, count));
reed@google.comac10a2d2010-12-22 21:39:39 +0000666#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000667}
668
reed@google.comc9aa5872011-04-05 21:05:37 +0000669///////////////////////////////////////////////////////////////////////////////
670
reed@google.comac10a2d2010-12-22 21:39:39 +0000671void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
672 const SkPaint& paint) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000673 CHECK_SHOULD_DRAW(draw);
674
675 bool doStroke = paint.getStyle() == SkPaint::kStroke_Style;
676 SkScalar width = paint.getStrokeWidth();
677
678 /*
679 We have special code for hairline strokes, miter-strokes, and fills.
680 Anything else we just call our path code.
681 */
682 bool usePath = doStroke && width > 0 &&
683 paint.getStrokeJoin() != SkPaint::kMiter_Join;
684 // another reason we might need to call drawPath...
685 if (paint.getMaskFilter()) {
686 usePath = true;
687 }
688
689 if (usePath) {
690 SkPath path;
691 path.addRect(rect);
692 this->drawPath(draw, path, paint, NULL, true);
693 return;
694 }
695
696 GrPaint grPaint;
697 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000698 if (!this->skPaint2GrPaintShader(paint,
699 &act,
700 *draw.fMatrix,
701 &grPaint,
702 true)) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000703 return;
704 }
reed@google.com20efde72011-05-09 17:00:02 +0000705 fContext->drawRect(grPaint, rect, doStroke ? width : -1);
reed@google.comac10a2d2010-12-22 21:39:39 +0000706}
707
reed@google.com69302852011-02-16 18:08:07 +0000708#include "SkMaskFilter.h"
709#include "SkBounder.h"
710
reed@google.com69302852011-02-16 18:08:07 +0000711static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
712 SkMaskFilter* filter, const SkMatrix& matrix,
713 const SkRegion& clip, SkBounder* bounder,
714 GrPaint* grp) {
715 SkMask srcM, dstM;
716
717 if (!SkDraw::DrawToMask(path, &clip.getBounds(), filter, &matrix, &srcM,
718 SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
719 return false;
720 }
721
722 SkAutoMaskImage autoSrc(&srcM, false);
723
724 if (!filter->filterMask(&dstM, srcM, matrix, NULL)) {
725 return false;
726 }
727 // this will free-up dstM when we're done (allocated in filterMask())
728 SkAutoMaskImage autoDst(&dstM, false);
729
730 if (clip.quickReject(dstM.fBounds)) {
731 return false;
732 }
733 if (bounder && !bounder->doIRect(dstM.fBounds)) {
734 return false;
735 }
736
737 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
738 // the current clip (and identity matrix) and grpaint settings
739
reed@google.com0c219b62011-02-16 21:31:18 +0000740 GrAutoMatrix avm(context, GrMatrix::I());
reed@google.com69302852011-02-16 18:08:07 +0000741
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000742 const GrTextureDesc desc = {
743 kNone_GrTextureFlags,
744 kNone_GrAALevel,
reed@google.com69302852011-02-16 18:08:07 +0000745 dstM.fBounds.width(),
746 dstM.fBounds.height(),
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000747 kAlpha_8_GrPixelConfig
reed@google.com69302852011-02-16 18:08:07 +0000748 };
749
750 GrTexture* texture = context->createUncachedTexture(desc, dstM.fImage,
751 dstM.fRowBytes);
752 if (NULL == texture) {
753 return false;
754 }
755
reed@google.com0c219b62011-02-16 21:31:18 +0000756 grp->setTexture(texture);
757 texture->unref();
758 grp->fSampler.setClampNoFilter();
reed@google.com69302852011-02-16 18:08:07 +0000759
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000760 GrRect d;
761 d.setLTRB(GrIntToScalar(dstM.fBounds.fLeft),
reed@google.com0c219b62011-02-16 21:31:18 +0000762 GrIntToScalar(dstM.fBounds.fTop),
763 GrIntToScalar(dstM.fBounds.fRight),
764 GrIntToScalar(dstM.fBounds.fBottom));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000765 GrRect s;
766 s.setLTRB(0, 0, GR_Scalar1, GR_Scalar1);
767 context->drawRectToRect(*grp, d, s);
reed@google.com69302852011-02-16 18:08:07 +0000768 return true;
769}
reed@google.com69302852011-02-16 18:08:07 +0000770
reed@google.com0c219b62011-02-16 21:31:18 +0000771void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
reed@google.comac10a2d2010-12-22 21:39:39 +0000772 const SkPaint& paint, const SkMatrix* prePathMatrix,
773 bool pathIsMutable) {
774 CHECK_SHOULD_DRAW(draw);
775
bsalomon@google.com5782d712011-01-21 21:03:59 +0000776 GrPaint grPaint;
777 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000778 if (!this->skPaint2GrPaintShader(paint,
779 &act,
780 *draw.fMatrix,
781 &grPaint,
782 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000783 return;
784 }
785
reed@google.com0c219b62011-02-16 21:31:18 +0000786 // BEGIN lift from SkDraw::drawPath()
787
788 SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
789 bool doFill = true;
790 SkPath tmpPath;
reed@google.comac10a2d2010-12-22 21:39:39 +0000791
792 if (prePathMatrix) {
reed@google.come3445642011-02-16 23:20:39 +0000793 SkPath* result = pathPtr;
reed@google.com0c219b62011-02-16 21:31:18 +0000794
reed@google.come3445642011-02-16 23:20:39 +0000795 if (!pathIsMutable) {
796 result = &tmpPath;
797 pathIsMutable = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000798 }
reed@google.come3445642011-02-16 23:20:39 +0000799 // should I push prePathMatrix on our MV stack temporarily, instead
800 // of applying it here? See SkDraw.cpp
801 pathPtr->transform(*prePathMatrix, result);
802 pathPtr = result;
reed@google.comac10a2d2010-12-22 21:39:39 +0000803 }
reed@google.com0c219b62011-02-16 21:31:18 +0000804 // at this point we're done with prePathMatrix
805 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
reed@google.comac10a2d2010-12-22 21:39:39 +0000806
bsalomon@google.com04de7822011-03-25 18:04:43 +0000807 // This "if" is not part of the SkDraw::drawPath() lift.
808 // When we get a 1.0 wide stroke we hairline stroke it instead of creating
809 // a new stroked-path. This is motivated by canvas2D sites that draw
810 // lines as 1.0 wide stroked paths. We can consider doing an alpha-modulated-
811 // hairline for width < 1.0 when AA is enabled.
812 static const int gMatrixMask = ~(SkMatrix::kIdentity_Mask |
813 SkMatrix::kTranslate_Mask);
814 if (!paint.getPathEffect() &&
815 SkPaint::kStroke_Style == paint.getStyle() &&
816 !(draw.fMatrix->getType() & gMatrixMask) &&
817 SK_Scalar1 == paint.getStrokeWidth()) {
818 doFill = false;
819 }
820
821 if (doFill && (paint.getPathEffect() ||
822 paint.getStyle() != SkPaint::kFill_Style)) {
reed@google.com0c219b62011-02-16 21:31:18 +0000823 doFill = paint.getFillPath(*pathPtr, &tmpPath);
824 pathPtr = &tmpPath;
825 }
826
827 // END lift from SkDraw::drawPath()
828
reed@google.com69302852011-02-16 18:08:07 +0000829 if (paint.getMaskFilter()) {
reed@google.com0c219b62011-02-16 21:31:18 +0000830 // avoid possibly allocating a new path in transform if we can
831 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
832
833 // transform the path into device space
reed@google.come3445642011-02-16 23:20:39 +0000834 pathPtr->transform(*draw.fMatrix, devPathPtr);
reed@google.com0c219b62011-02-16 21:31:18 +0000835
836 drawWithMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
reed@google.com69302852011-02-16 18:08:07 +0000837 *draw.fMatrix, *draw.fClip, draw.fBounder, &grPaint);
838 return;
839 }
reed@google.com69302852011-02-16 18:08:07 +0000840
bsalomon@google.comffca4002011-02-22 20:34:01 +0000841 GrPathFill fill = kHairLine_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000842
reed@google.com0c219b62011-02-16 21:31:18 +0000843 if (doFill) {
844 switch (pathPtr->getFillType()) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000845 case SkPath::kWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000846 fill = kWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000847 break;
848 case SkPath::kEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000849 fill = kEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000850 break;
851 case SkPath::kInverseWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000852 fill = kInverseWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000853 break;
854 case SkPath::kInverseEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000855 fill = kInverseEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000856 break;
857 default:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000858 SkDebugf("Unsupported path fill type\n");
reed@google.comac10a2d2010-12-22 21:39:39 +0000859 return;
860 }
861 }
862
reed@google.com07f3ee12011-05-16 17:21:57 +0000863 fContext->drawPath(grPaint, *pathPtr, fill);
reed@google.comac10a2d2010-12-22 21:39:39 +0000864}
865
reed@google.comac10a2d2010-12-22 21:39:39 +0000866void SkGpuDevice::drawBitmap(const SkDraw& draw,
867 const SkBitmap& bitmap,
868 const SkIRect* srcRectPtr,
869 const SkMatrix& m,
870 const SkPaint& paint) {
871 CHECK_SHOULD_DRAW(draw);
872
873 SkIRect srcRect;
874 if (NULL == srcRectPtr) {
875 srcRect.set(0, 0, bitmap.width(), bitmap.height());
876 } else {
877 srcRect = *srcRectPtr;
878 }
879
bsalomon@google.com5782d712011-01-21 21:03:59 +0000880 GrPaint grPaint;
Scroggod757df22011-05-16 13:11:16 +0000881 if (!this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000882 return;
883 }
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000884 if (paint.isFilterBitmap()) {
885 grPaint.fSampler.setFilter(GrSamplerState::kBilinear_Filter);
886 } else {
887 grPaint.fSampler.setFilter(GrSamplerState::kNearest_Filter);
888 }
889
bsalomon@google.com5782d712011-01-21 21:03:59 +0000890
reed@google.com02a7e6c2011-01-28 21:21:49 +0000891 const int maxTextureDim = fContext->getMaxTextureDimension();
892 if (bitmap.getTexture() || (bitmap.width() <= maxTextureDim &&
893 bitmap.height() <= maxTextureDim)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000894 // take the fast case
bsalomon@google.com5782d712011-01-21 21:03:59 +0000895 this->internalDrawBitmap(draw, bitmap, srcRect, m, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000896 return;
897 }
898
899 // undo the translate done by SkCanvas
900 int DX = SkMax32(0, srcRect.fLeft);
901 int DY = SkMax32(0, srcRect.fTop);
902 // compute clip bounds in local coordinates
903 SkIRect clipRect;
904 {
905 SkRect r;
906 r.set(draw.fClip->getBounds());
907 SkMatrix matrix, inverse;
908 matrix.setConcat(*draw.fMatrix, m);
909 if (!matrix.invert(&inverse)) {
910 return;
911 }
912 inverse.mapRect(&r);
913 r.roundOut(&clipRect);
914 // apply the canvas' translate to our local clip
915 clipRect.offset(DX, DY);
916 }
917
reed@google.com02a7e6c2011-01-28 21:21:49 +0000918 int nx = bitmap.width() / maxTextureDim;
919 int ny = bitmap.height() / maxTextureDim;
reed@google.comac10a2d2010-12-22 21:39:39 +0000920 for (int x = 0; x <= nx; x++) {
921 for (int y = 0; y <= ny; y++) {
922 SkIRect tileR;
reed@google.com02a7e6c2011-01-28 21:21:49 +0000923 tileR.set(x * maxTextureDim, y * maxTextureDim,
924 (x + 1) * maxTextureDim, (y + 1) * maxTextureDim);
reed@google.comac10a2d2010-12-22 21:39:39 +0000925 if (!SkIRect::Intersects(tileR, clipRect)) {
926 continue;
927 }
928
929 SkIRect srcR = tileR;
930 if (!srcR.intersect(srcRect)) {
931 continue;
932 }
933
934 SkBitmap tmpB;
935 if (bitmap.extractSubset(&tmpB, tileR)) {
936 // now offset it to make it "local" to our tmp bitmap
937 srcR.offset(-tileR.fLeft, -tileR.fTop);
938
939 SkMatrix tmpM(m);
940 {
941 int dx = tileR.fLeft - DX + SkMax32(0, srcR.fLeft);
942 int dy = tileR.fTop - DY + SkMax32(0, srcR.fTop);
943 tmpM.preTranslate(SkIntToScalar(dx), SkIntToScalar(dy));
944 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000945 this->internalDrawBitmap(draw, tmpB, srcR, tmpM, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000946 }
947 }
948 }
949}
950
951/*
952 * This is called by drawBitmap(), which has to handle images that may be too
953 * large to be represented by a single texture.
954 *
bsalomon@google.com5782d712011-01-21 21:03:59 +0000955 * internalDrawBitmap assumes that the specified bitmap will fit in a texture
956 * and that non-texture portion of the GrPaint has already been setup.
reed@google.comac10a2d2010-12-22 21:39:39 +0000957 */
958void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
959 const SkBitmap& bitmap,
960 const SkIRect& srcRect,
961 const SkMatrix& m,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000962 GrPaint* grPaint) {
reed@google.com02a7e6c2011-01-28 21:21:49 +0000963 SkASSERT(bitmap.width() <= fContext->getMaxTextureDimension() &&
964 bitmap.height() <= fContext->getMaxTextureDimension());
reed@google.comac10a2d2010-12-22 21:39:39 +0000965
966 SkAutoLockPixels alp(bitmap);
967 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
968 return;
969 }
970
bsalomon@google.com5782d712011-01-21 21:03:59 +0000971 grPaint->fSampler.setWrapX(GrSamplerState::kClamp_WrapMode);
972 grPaint->fSampler.setWrapY(GrSamplerState::kClamp_WrapMode);
973 grPaint->fSampler.setSampleMode(GrSamplerState::kNormal_SampleMode);
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000974 grPaint->fSampler.setMatrix(GrMatrix::I());
reed@google.comac10a2d2010-12-22 21:39:39 +0000975
976 GrTexture* texture;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000977 SkAutoCachedTexture act(this, bitmap, grPaint->fSampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000978 if (NULL == texture) {
979 return;
980 }
981
bsalomon@google.com5782d712011-01-21 21:03:59 +0000982 grPaint->setTexture(texture);
reed@google.com46799cd2011-02-22 20:56:26 +0000983
reed@google.com20efde72011-05-09 17:00:02 +0000984 GrRect dstRect = SkRect::MakeWH(GrIntToScalar(srcRect.width()),
985 GrIntToScalar(srcRect.height()));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000986 GrRect paintRect;
junov@google.com6acc9b32011-05-16 18:32:07 +0000987 paintRect.setLTRB(GrFixedToScalar((srcRect.fLeft << 16) / bitmap.width()),
988 GrFixedToScalar((srcRect.fTop << 16) / bitmap.height()),
989 GrFixedToScalar((srcRect.fRight << 16) / bitmap.width()),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000990 GrFixedToScalar((srcRect.fBottom << 16) / bitmap.height()));
reed@google.comac10a2d2010-12-22 21:39:39 +0000991
junov@google.com6acc9b32011-05-16 18:32:07 +0000992 if (GrSamplerState::kNearest_Filter != grPaint->fSampler.getFilter() &&
993 (srcRect.width() < bitmap.width() ||
994 srcRect.height() < bitmap.height())) {
995 // If drawing a subrect of the bitmap and filtering is enabled,
996 // use a constrained texture domain to avoid color bleeding
997 GrScalar left, top, right, bottom;
998 if (srcRect.width() > 1) {
999 GrScalar border = GR_ScalarHalf / bitmap.width();
1000 left = paintRect.left() + border;
1001 right = paintRect.right() - border;
1002 } else {
1003 left = right = GrScalarHalf(paintRect.left() + paintRect.right());
1004 }
1005 if (srcRect.height() > 1) {
1006 GrScalar border = GR_ScalarHalf / bitmap.height();
1007 top = paintRect.top() + border;
1008 bottom = paintRect.bottom() - border;
1009 } else {
1010 top = bottom = GrScalarHalf(paintRect.top() + paintRect.bottom());
1011 }
1012 GrRect textureDomain;
1013 textureDomain.setLTRB(left, top, right, bottom);
1014 grPaint->fSampler.setTextureDomain(textureDomain);
1015 }
1016
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001017 fContext->drawRectToRect(*grPaint, dstRect, paintRect, &m);
reed@google.comac10a2d2010-12-22 21:39:39 +00001018}
1019
1020void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
1021 int left, int top, const SkPaint& paint) {
1022 CHECK_SHOULD_DRAW(draw);
1023
1024 SkAutoLockPixels alp(bitmap);
1025 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
1026 return;
1027 }
1028
bsalomon@google.com5782d712011-01-21 21:03:59 +00001029 GrPaint grPaint;
Scroggod757df22011-05-16 13:11:16 +00001030 if(!this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001031 return;
1032 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001033
bsalomon@google.com5782d712011-01-21 21:03:59 +00001034 GrAutoMatrix avm(fContext, GrMatrix::I());
1035
1036 GrTexture* texture;
1037 grPaint.fSampler.setClampNoFilter();
1038 SkAutoCachedTexture act(this, bitmap, grPaint.fSampler, &texture);
1039
bsalomon@google.com5782d712011-01-21 21:03:59 +00001040 grPaint.setTexture(texture);
1041
bsalomon@google.com5782d712011-01-21 21:03:59 +00001042 fContext->drawRectToRect(grPaint,
reed@google.com20efde72011-05-09 17:00:02 +00001043 GrRect::MakeXYWH(GrIntToScalar(left),
1044 GrIntToScalar(top),
1045 GrIntToScalar(bitmap.width()),
1046 GrIntToScalar(bitmap.height())),
1047 GrRect::MakeWH(GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001048}
1049
1050void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
1051 int x, int y, const SkPaint& paint) {
1052 CHECK_SHOULD_DRAW(draw);
1053
bsalomon@google.com5782d712011-01-21 21:03:59 +00001054 GrPaint grPaint;
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001055 if (!((SkGpuDevice*)dev)->bindDeviceAsTexture(&grPaint) ||
Scroggod757df22011-05-16 13:11:16 +00001056 !this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001057 return;
reed@google.comac10a2d2010-12-22 21:39:39 +00001058 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001059
1060 SkASSERT(NULL != grPaint.getTexture());
1061
1062 const SkBitmap& bm = dev->accessBitmap(false);
1063 int w = bm.width();
1064 int h = bm.height();
1065
1066 GrAutoMatrix avm(fContext, GrMatrix::I());
1067
1068 grPaint.fSampler.setClampNoFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +00001069
1070 fContext->drawRectToRect(grPaint,
reed@google.com20efde72011-05-09 17:00:02 +00001071 GrRect::MakeXYWH(GrIntToScalar(x),
1072 GrIntToScalar(y),
1073 GrIntToScalar(w),
1074 GrIntToScalar(h)),
1075 GrRect::MakeWH(GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001076}
1077
1078///////////////////////////////////////////////////////////////////////////////
1079
1080// must be in SkCanvas::VertexMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +00001081static const GrPrimitiveType gVertexMode2PrimitiveType[] = {
1082 kTriangles_PrimitiveType,
1083 kTriangleStrip_PrimitiveType,
1084 kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +00001085};
1086
1087void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
1088 int vertexCount, const SkPoint vertices[],
1089 const SkPoint texs[], const SkColor colors[],
1090 SkXfermode* xmode,
1091 const uint16_t indices[], int indexCount,
1092 const SkPaint& paint) {
1093 CHECK_SHOULD_DRAW(draw);
1094
bsalomon@google.com5782d712011-01-21 21:03:59 +00001095 GrPaint grPaint;
1096 SkAutoCachedTexture act;
1097 // we ignore the shader if texs is null.
1098 if (NULL == texs) {
Scroggod757df22011-05-16 13:11:16 +00001099 if (!this->skPaint2GrPaintNoShader(paint,
1100 false,
1101 &grPaint,
1102 NULL == colors)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001103 return;
1104 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001105 } else {
reed@google.com1a2e8d22011-01-21 22:08:29 +00001106 if (!this->skPaint2GrPaintShader(paint, &act,
1107 *draw.fMatrix,
Scroggod757df22011-05-16 13:11:16 +00001108 &grPaint,
1109 NULL == colors)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001110 return;
1111 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001112 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001113
1114 if (NULL != xmode && NULL != texs && NULL != colors) {
1115 SkXfermode::Mode mode;
1116 if (!SkXfermode::IsMode(xmode, &mode) ||
1117 SkXfermode::kMultiply_Mode != mode) {
1118 SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
1119#if 0
1120 return
1121#endif
1122 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001123 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001124
1125#if SK_SCALAR_IS_GR_SCALAR
1126 // even if GrColor and SkColor byte offsets match we need
1127 // to perform pre-multiply.
1128 if (NULL == colors) {
1129 fContext->drawVertices(grPaint,
1130 gVertexMode2PrimitiveType[vmode],
1131 vertexCount,
1132 (GrPoint*) vertices,
1133 (GrPoint*) texs,
1134 NULL,
1135 indices,
1136 indexCount);
1137 } else
1138#endif
1139 {
1140 SkTexCoordSource texSrc(texs);
1141 SkColorSource colSrc(colors);
1142 SkIndexSource idxSrc(indices, indexCount);
1143
1144 fContext->drawCustomVertices(grPaint,
1145 gVertexMode2PrimitiveType[vmode],
1146 SkPositionSource(vertices, vertexCount),
1147 (NULL == texs) ? NULL : &texSrc,
1148 (NULL == colors) ? NULL : &colSrc,
1149 (NULL == indices) ? NULL : &idxSrc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001150 }
1151}
1152
1153///////////////////////////////////////////////////////////////////////////////
1154
1155static void GlyphCacheAuxProc(void* data) {
1156 delete (GrFontScaler*)data;
1157}
1158
1159static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) {
1160 void* auxData;
1161 GrFontScaler* scaler = NULL;
1162 if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
1163 scaler = (GrFontScaler*)auxData;
1164 }
1165 if (NULL == scaler) {
1166 scaler = new SkGrFontScaler(cache);
1167 cache->setAuxProc(GlyphCacheAuxProc, scaler);
1168 }
1169 return scaler;
1170}
1171
1172static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
1173 SkFixed fx, SkFixed fy,
1174 const SkGlyph& glyph) {
1175 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1176
1177 GrSkDrawProcs* procs = (GrSkDrawProcs*)state.fDraw->fProcs;
1178
1179 if (NULL == procs->fFontScaler) {
1180 procs->fFontScaler = get_gr_font_scaler(state.fCache);
1181 }
reed@google.com39ce0ac2011-04-08 15:42:19 +00001182
1183 /*
1184 * Skia calls us with fx,fy already biased by 1/2. It does this to speed
1185 * up rounding these, so that all of its procs (like us) can just call
1186 * SkFixedFloor and get the "rounded" value.
1187 *
1188 * We take advantage of that for fx, where we pass a rounded value, but
1189 * we want the fractional fy, so we have to unbias it first.
1190 */
reed@google.comac10a2d2010-12-22 21:39:39 +00001191 procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0),
reed@google.com39ce0ac2011-04-08 15:42:19 +00001192 SkIntToFixed(SkFixedFloor(fx)),
1193 fy - SK_FixedHalf,
reed@google.comac10a2d2010-12-22 21:39:39 +00001194 procs->fFontScaler);
1195}
1196
bsalomon@google.com5782d712011-01-21 21:03:59 +00001197SkDrawProcs* SkGpuDevice::initDrawForText(GrTextContext* context) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001198
1199 // deferred allocation
1200 if (NULL == fDrawProcs) {
1201 fDrawProcs = new GrSkDrawProcs;
1202 fDrawProcs->fD1GProc = SkGPU_Draw1Glyph;
1203 fDrawProcs->fContext = fContext;
1204 }
1205
1206 // init our (and GL's) state
1207 fDrawProcs->fTextContext = context;
1208 fDrawProcs->fFontScaler = NULL;
1209 return fDrawProcs;
1210}
1211
1212void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
1213 size_t byteLength, SkScalar x, SkScalar y,
1214 const SkPaint& paint) {
1215 CHECK_SHOULD_DRAW(draw);
1216
1217 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1218 // this guy will just call our drawPath()
1219 draw.drawText((const char*)text, byteLength, x, y, paint);
1220 } else {
reed@google.comac10a2d2010-12-22 21:39:39 +00001221 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001222
1223 GrPaint grPaint;
1224 SkAutoCachedTexture act;
1225
Scroggod757df22011-05-16 13:11:16 +00001226 if (!this->skPaint2GrPaintShader(paint,
1227 &act,
1228 *draw.fMatrix,
1229 &grPaint,
1230 true)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001231 return;
1232 }
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001233 GrTextContext context(fContext, grPaint, draw.fExtMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001234 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001235 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
1236 }
1237}
1238
1239void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
1240 size_t byteLength, const SkScalar pos[],
1241 SkScalar constY, int scalarsPerPos,
1242 const SkPaint& paint) {
1243 CHECK_SHOULD_DRAW(draw);
1244
1245 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1246 // this guy will just call our drawPath()
1247 draw.drawPosText((const char*)text, byteLength, pos, constY,
1248 scalarsPerPos, paint);
1249 } else {
reed@google.comac10a2d2010-12-22 21:39:39 +00001250 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001251
1252 GrPaint grPaint;
1253 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +00001254 if (!this->skPaint2GrPaintShader(paint,
1255 &act,
1256 *draw.fMatrix,
1257 &grPaint,
1258 true)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001259 return;
1260 }
1261
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001262 GrTextContext context(fContext, grPaint, draw.fExtMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001263 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001264 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
1265 scalarsPerPos, paint);
1266 }
1267}
1268
1269void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
1270 size_t len, const SkPath& path,
1271 const SkMatrix* m, const SkPaint& paint) {
1272 CHECK_SHOULD_DRAW(draw);
1273
1274 SkASSERT(draw.fDevice == this);
1275 draw.drawTextOnPath((const char*)text, len, path, m, paint);
1276}
1277
1278///////////////////////////////////////////////////////////////////////////////
1279
reed@google.comf67e4cf2011-03-15 20:56:58 +00001280bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
1281 if (!paint.isLCDRenderText()) {
1282 // we're cool with the paint as is
1283 return false;
1284 }
1285
1286 if (paint.getShader() ||
1287 paint.getXfermode() || // unless its srcover
1288 paint.getMaskFilter() ||
1289 paint.getRasterizer() ||
1290 paint.getColorFilter() ||
1291 paint.getPathEffect() ||
1292 paint.isFakeBoldText() ||
1293 paint.getStyle() != SkPaint::kFill_Style) {
1294 // turn off lcd
1295 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
1296 flags->fHinting = paint.getHinting();
1297 return true;
1298 }
1299 // we're cool with the paint as is
1300 return false;
1301}
1302
1303///////////////////////////////////////////////////////////////////////////////
1304
reed@google.comac10a2d2010-12-22 21:39:39 +00001305SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001306 const GrSamplerState& sampler,
1307 GrTexture** texture,
1308 bool forDeviceRenderTarget) {
1309 GrTexture* newTexture = NULL;
1310 GrTextureEntry* entry = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +00001311 GrContext* ctx = this->context();
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001312
reed@google.comac10a2d2010-12-22 21:39:39 +00001313 if (forDeviceRenderTarget) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001314 const GrTextureDesc desc = {
1315 kRenderTarget_GrTextureFlagBit,
1316 kNone_GrAALevel,
1317 bitmap.width(),
1318 bitmap.height(),
1319 SkGr::Bitmap2PixelConfig(bitmap)
1320 };
bsalomon@google.coma39f4042011-04-26 13:18:16 +00001321 entry = ctx->lockKeylessTexture(desc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001322 } else {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001323 uint32_t p0, p1;
reed@google.comac10a2d2010-12-22 21:39:39 +00001324 p0 = bitmap.getGenerationID();
1325 p1 = bitmap.pixelRefOffset();
reed@google.comac10a2d2010-12-22 21:39:39 +00001326
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001327 GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
1328 entry = ctx->findAndLockTexture(&key, sampler);
reed@google.comac10a2d2010-12-22 21:39:39 +00001329
reed@google.comac10a2d2010-12-22 21:39:39 +00001330 if (NULL == entry) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001331 entry = sk_gr_create_bitmap_texture(ctx, &key, sampler, bitmap);
1332 if (NULL == entry) {
1333 GrPrintf("---- failed to create texture for cache [%d %d]\n",
1334 bitmap.width(), bitmap.height());
1335 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001336 }
1337 }
1338
1339 if (NULL != entry) {
1340 newTexture = entry->texture();
reed@google.comac10a2d2010-12-22 21:39:39 +00001341 if (texture) {
1342 *texture = newTexture;
1343 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001344 }
1345 return (TexCache*)entry;
1346}
1347
1348void SkGpuDevice::unlockCachedTexture(TexCache* cache) {
1349 this->context()->unlockTexture((GrTextureEntry*)cache);
1350}
1351
reed@google.com7b201d22011-01-11 18:59:23 +00001352///////////////////////////////////////////////////////////////////////////////
1353
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001354SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context,
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001355 GrRenderTarget* rootRenderTarget) {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001356 GrAssert(NULL != context);
1357 GrAssert(NULL != rootRenderTarget);
1358
1359 // check this now rather than passing this value to SkGpuDevice cons.
1360 // we want the rt that is bound *now* in the 3D API, not the one
1361 // at the time of newDevice.
1362 if (SkGpuDevice::Current3DApiRenderTarget() == rootRenderTarget) {
1363 fRootRenderTarget = context->createRenderTargetFrom3DApiState();
1364 } else {
1365 fRootRenderTarget = rootRenderTarget;
1366 rootRenderTarget->ref();
1367 }
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001368
1369 fContext = context;
reed@google.com7b201d22011-01-11 18:59:23 +00001370 context->ref();
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001371
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001372 fRootTexture = NULL;
1373}
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001374
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001375SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context, GrTexture* rootRenderTargetTexture) {
1376 GrAssert(NULL != context);
1377 GrAssert(NULL != rootRenderTargetTexture);
1378 GrAssert(NULL != rootRenderTargetTexture->asRenderTarget());
1379
1380 fRootTexture = rootRenderTargetTexture;
1381 rootRenderTargetTexture->ref();
1382
1383 fRootRenderTarget = rootRenderTargetTexture->asRenderTarget();
1384 fRootRenderTarget->ref();
1385
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001386 fContext = context;
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001387 context->ref();
reed@google.com7b201d22011-01-11 18:59:23 +00001388}
1389
1390SkGpuDeviceFactory::~SkGpuDeviceFactory() {
1391 fContext->unref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001392 fRootRenderTarget->unref();
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001393 GrSafeUnref(fRootTexture);
reed@google.com7b201d22011-01-11 18:59:23 +00001394}
1395
1396SkDevice* SkGpuDeviceFactory::newDevice(SkCanvas*, SkBitmap::Config config,
1397 int width, int height,
1398 bool isOpaque, bool isLayer) {
1399 SkBitmap bm;
1400 bm.setConfig(config, width, height);
1401 bm.setIsOpaque(isOpaque);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001402 return new SkGpuDevice(fContext, bm, isLayer ? NULL : fRootRenderTarget);
reed@google.com7b201d22011-01-11 18:59:23 +00001403}