blob: 90728b1ddae083d902ee28bdb61daeef46e4f839 [file] [log] [blame]
reed@google.comac10a2d2010-12-22 21:39:39 +00001/*
bsalomon@google.com1da07462011-03-10 14:51:57 +00002 Copyright 2011 Google Inc.
reed@google.comac10a2d2010-12-22 21:39:39 +00003
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17
18#include "GrContext.h"
19#include "GrTextContext.h"
20
reed@google.comac10a2d2010-12-22 21:39:39 +000021#include "SkGpuDevice.h"
reed@google.com7b201d22011-01-11 18:59:23 +000022#include "SkGpuDeviceFactory.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000023#include "SkGrTexturePixelRef.h"
24
25#include "SkDrawProcs.h"
26#include "SkGlyphCache.h"
reed@google.comc9aa5872011-04-05 21:05:37 +000027#include "SkUtils.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000028
29#define CACHE_LAYER_TEXTURES 1
30
31#if 0
32 extern bool (*gShouldDrawProc)();
33 #define CHECK_SHOULD_DRAW(draw) \
34 do { \
35 if (gShouldDrawProc && !gShouldDrawProc()) return; \
36 this->prepareRenderTarget(draw); \
37 } while (0)
38#else
39 #define CHECK_SHOULD_DRAW(draw) this->prepareRenderTarget(draw)
40#endif
41
42class SkAutoExtMatrix {
43public:
44 SkAutoExtMatrix(const SkMatrix* extMatrix) {
45 if (extMatrix) {
46 SkGr::SkMatrix2GrMatrix(*extMatrix, &fMatrix);
47 fExtMatrix = &fMatrix;
48 } else {
49 fExtMatrix = NULL;
50 }
51 }
52 const GrMatrix* extMatrix() const { return fExtMatrix; }
53
54private:
55 GrMatrix fMatrix;
56 GrMatrix* fExtMatrix; // NULL or &fMatrix
57};
58
59///////////////////////////////////////////////////////////////////////////////
60
61SkGpuDevice::SkAutoCachedTexture::
62 SkAutoCachedTexture(SkGpuDevice* device,
63 const SkBitmap& bitmap,
64 const GrSamplerState& sampler,
65 GrTexture** texture) {
66 GrAssert(texture);
67 fTex = NULL;
68 *texture = this->set(device, bitmap, sampler);
69}
70
71SkGpuDevice::SkAutoCachedTexture::SkAutoCachedTexture() {
72 fTex = NULL;
73}
74
75GrTexture* SkGpuDevice::SkAutoCachedTexture::set(SkGpuDevice* device,
76 const SkBitmap& bitmap,
77 const GrSamplerState& sampler) {
78 if (fTex) {
79 fDevice->unlockCachedTexture(fTex);
80 }
81 fDevice = device;
82 GrTexture* texture = (GrTexture*)bitmap.getTexture();
83 if (texture) {
84 // return the native texture
85 fTex = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +000086 } else {
87 // look it up in our cache
88 fTex = device->lockCachedTexture(bitmap, sampler, &texture, false);
89 }
90 return texture;
91}
92
93SkGpuDevice::SkAutoCachedTexture::~SkAutoCachedTexture() {
94 if (fTex) {
95 fDevice->unlockCachedTexture(fTex);
96 }
97}
98
99///////////////////////////////////////////////////////////////////////////////
100
101bool gDoTraceDraw;
102
103struct GrSkDrawProcs : public SkDrawProcs {
104public:
105 GrContext* fContext;
106 GrTextContext* fTextContext;
107 GrFontScaler* fFontScaler; // cached in the skia glyphcache
108};
109
110///////////////////////////////////////////////////////////////////////////////
111
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000112GrRenderTarget* SkGpuDevice::Current3DApiRenderTarget() {
113 return (GrRenderTarget*) -1;
114}
115
116SkGpuDevice::SkGpuDevice(GrContext* context,
117 const SkBitmap& bitmap,
118 GrRenderTarget* renderTargetOrNull)
119 : SkDevice(NULL, bitmap, (NULL == renderTargetOrNull)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000120
121 fNeedPrepareRenderTarget = false;
122 fDrawProcs = NULL;
123
reed@google.com7b201d22011-01-11 18:59:23 +0000124 fContext = context;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000125 fContext->ref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000126
127 fCache = NULL;
128 fTexture = NULL;
129 fRenderTarget = NULL;
130 fNeedClear = false;
131
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000132 if (NULL == renderTargetOrNull) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000133 SkBitmap::Config c = bitmap.config();
134 if (c != SkBitmap::kRGB_565_Config) {
135 c = SkBitmap::kARGB_8888_Config;
136 }
137 SkBitmap bm;
138 bm.setConfig(c, this->width(), this->height());
139
140#if CACHE_LAYER_TEXTURES
141
142 fCache = this->lockCachedTexture(bm, GrSamplerState::ClampNoFilter(),
143 &fTexture, true);
144 if (fCache) {
145 SkASSERT(NULL != fTexture);
bsalomon@google.com1da07462011-03-10 14:51:57 +0000146 SkASSERT(NULL != fTexture->asRenderTarget());
reed@google.comac10a2d2010-12-22 21:39:39 +0000147 }
148#else
149 const GrGpu::TextureDesc desc = {
150 GrGpu::kRenderTarget_TextureFlag,
151 GrGpu::kNone_AALevel,
152 this->width(),
153 this->height(),
154 SkGr::Bitmap2PixelConfig(bm)
155 };
156
157 fTexture = fContext->createUncachedTexture(desc, NULL, 0);
158#endif
159 if (NULL != fTexture) {
160 fRenderTarget = fTexture->asRenderTarget();
161
162 GrAssert(NULL != fRenderTarget);
163
164 // we defer the actual clear until our gainFocus()
165 fNeedClear = true;
166
167 // wrap the bitmap with a pixelref to expose our texture
168 SkGrTexturePixelRef* pr = new SkGrTexturePixelRef(fTexture);
169 this->setPixelRef(pr, 0)->unref();
170 } else {
171 GrPrintf("--- failed to create gpu-offscreen [%d %d]\n",
172 this->width(), this->height());
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000173 GrAssert(false);
reed@google.comac10a2d2010-12-22 21:39:39 +0000174 }
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000175 } else {
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000176 if (Current3DApiRenderTarget() == renderTargetOrNull) {
177 fRenderTarget = fContext->createRenderTargetFrom3DApiState();
178 } else {
179 fRenderTarget = renderTargetOrNull;
180 fRenderTarget->ref();
181 }
182 SkGrRenderTargetPixelRef* pr = new SkGrRenderTargetPixelRef(fRenderTarget);
183 this->setPixelRef(pr, 0)->unref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000184 }
185}
186
187SkGpuDevice::~SkGpuDevice() {
188 if (fDrawProcs) {
189 delete fDrawProcs;
190 }
191
192 if (fCache) {
193 GrAssert(NULL != fTexture);
194 GrAssert(fRenderTarget == fTexture->asRenderTarget());
195 // IMPORTANT: reattach the rendertarget/tex back to the cache.
196 fContext->reattachAndUnlockCachedTexture((GrTextureEntry*)fCache);
197 } else if (NULL != fTexture) {
198 GrAssert(!CACHE_LAYER_TEXTURES);
199 GrAssert(fRenderTarget == fTexture->asRenderTarget());
200 fTexture->unref();
201 } else if (NULL != fRenderTarget) {
202 fRenderTarget->unref();
203 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000204 fContext->unref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000205}
206
reed@google.comac10a2d2010-12-22 21:39:39 +0000207intptr_t SkGpuDevice::getLayerTextureHandle() const {
208 if (fTexture) {
209 return fTexture->getTextureHandle();
210 } else {
211 return 0;
212 }
213}
214///////////////////////////////////////////////////////////////////////////////
215
216void SkGpuDevice::makeRenderTargetCurrent() {
217 fContext->setRenderTarget(fRenderTarget);
218 fContext->flush(true);
219 fNeedPrepareRenderTarget = true;
220}
221
222///////////////////////////////////////////////////////////////////////////////
223
224bool SkGpuDevice::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
225 SkIRect bounds;
226 bounds.set(0, 0, this->width(), this->height());
227 if (!bounds.intersect(srcRect)) {
228 return false;
229 }
230
231 const int w = bounds.width();
232 const int h = bounds.height();
233 SkBitmap tmp;
234 // note we explicitly specify our rowBytes to be snug (no gap between rows)
235 tmp.setConfig(SkBitmap::kARGB_8888_Config, w, h, w * 4);
236 if (!tmp.allocPixels()) {
237 return false;
238 }
239
240 SkAutoLockPixels alp(tmp);
reed@google.comac10a2d2010-12-22 21:39:39 +0000241
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000242 if (!fContext->readRenderTargetPixels(fRenderTarget,
243 bounds.fLeft, bounds.fTop,
244 bounds.width(), bounds.height(),
245 kRGBA_8888_GrPixelConfig,
246 tmp.getPixels())) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000247 return false;
248 }
249
250 tmp.swap(*bitmap);
251 return true;
252}
253
254void SkGpuDevice::writePixels(const SkBitmap& bitmap, int x, int y) {
255 SkAutoLockPixels alp(bitmap);
256 if (!bitmap.readyToDraw()) {
257 return;
258 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000259 GrPixelConfig config = SkGr::BitmapConfig2PixelConfig(bitmap.config(),
260 bitmap.isOpaque());
reed@google.comac10a2d2010-12-22 21:39:39 +0000261 fContext->setRenderTarget(fRenderTarget);
262 // we aren't setting the clip or matrix, so mark as dirty
263 // we don't need to set them for this call and don't have them anyway
264 fNeedPrepareRenderTarget = true;
265
266 fContext->writePixels(x, y, bitmap.width(), bitmap.height(),
267 config, bitmap.getPixels(), bitmap.rowBytes());
268}
269
270///////////////////////////////////////////////////////////////////////////////
271
272static void convert_matrixclip(GrContext* context, const SkMatrix& matrix,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000273 const SkClipStack& clipStack,
reed@google.com6f8f2922011-03-04 22:27:10 +0000274 const SkRegion& clipRegion,
275 const SkIPoint& origin) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000276 GrMatrix grmat;
277 SkGr::SkMatrix2GrMatrix(matrix, &grmat);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000278 context->setMatrix(grmat);
reed@google.comac10a2d2010-12-22 21:39:39 +0000279
280 SkGrClipIterator iter;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000281 iter.reset(clipStack);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000282 const SkIRect& skBounds = clipRegion.getBounds();
283 GrRect bounds;
284 bounds.setLTRB(GrIntToScalar(skBounds.fLeft),
285 GrIntToScalar(skBounds.fTop),
286 GrIntToScalar(skBounds.fRight),
287 GrIntToScalar(skBounds.fBottom));
reed@google.com6f8f2922011-03-04 22:27:10 +0000288 GrClip grc(&iter, GrIntToScalar(-origin.x()), GrIntToScalar(-origin.y()),
289 &bounds);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000290 context->setClip(grc);
reed@google.comac10a2d2010-12-22 21:39:39 +0000291}
292
293// call this ever each draw call, to ensure that the context reflects our state,
294// and not the state from some other canvas/device
295void SkGpuDevice::prepareRenderTarget(const SkDraw& draw) {
296 if (fNeedPrepareRenderTarget ||
bsalomon@google.com5782d712011-01-21 21:03:59 +0000297 fContext->getRenderTarget() != fRenderTarget) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000298
299 fContext->setRenderTarget(fRenderTarget);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000300 SkASSERT(draw.fClipStack);
301 convert_matrixclip(fContext, *draw.fMatrix,
reed@google.com6f8f2922011-03-04 22:27:10 +0000302 *draw.fClipStack, *draw.fClip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000303 fNeedPrepareRenderTarget = false;
304 }
305}
306
reed@google.com46799cd2011-02-22 20:56:26 +0000307void SkGpuDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& clip,
308 const SkClipStack& clipStack) {
309 this->INHERITED::setMatrixClip(matrix, clip, clipStack);
reed@google.comac10a2d2010-12-22 21:39:39 +0000310
reed@google.com6f8f2922011-03-04 22:27:10 +0000311 convert_matrixclip(fContext, matrix, clipStack, clip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000312}
313
314void SkGpuDevice::gainFocus(SkCanvas* canvas, const SkMatrix& matrix,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000315 const SkRegion& clip, const SkClipStack& clipStack) {
316
reed@google.comac10a2d2010-12-22 21:39:39 +0000317 fContext->setRenderTarget(fRenderTarget);
318
bsalomon@google.comd302f142011-03-03 13:54:13 +0000319 this->INHERITED::gainFocus(canvas, matrix, clip, clipStack);
reed@google.comac10a2d2010-12-22 21:39:39 +0000320
reed@google.com6f8f2922011-03-04 22:27:10 +0000321 convert_matrixclip(fContext, matrix, clipStack, clip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000322
323 if (fNeedClear) {
324 fContext->eraseColor(0x0);
325 fNeedClear = false;
326 }
327}
328
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000329bool SkGpuDevice::bindDeviceAsTexture(GrPaint* paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000330 if (NULL != fTexture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000331 paint->setTexture(fTexture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000332 return true;
333 }
334 return false;
335}
336
337///////////////////////////////////////////////////////////////////////////////
338
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000339SK_COMPILE_ASSERT(SkShader::kNone_BitmapType == 0, shader_type_mismatch);
340SK_COMPILE_ASSERT(SkShader::kDefault_BitmapType == 1, shader_type_mismatch);
341SK_COMPILE_ASSERT(SkShader::kRadial_BitmapType == 2, shader_type_mismatch);
342SK_COMPILE_ASSERT(SkShader::kSweep_BitmapType == 3, shader_type_mismatch);
343SK_COMPILE_ASSERT(SkShader::kTwoPointRadial_BitmapType == 4,
344 shader_type_mismatch);
345SK_COMPILE_ASSERT(SkShader::kLast_BitmapType == 4, shader_type_mismatch);
reed@google.comac10a2d2010-12-22 21:39:39 +0000346
bsalomon@google.com5782d712011-01-21 21:03:59 +0000347static const GrSamplerState::SampleMode sk_bmp_type_to_sample_mode[] = {
348 (GrSamplerState::SampleMode) -1, // kNone_BitmapType
349 GrSamplerState::kNormal_SampleMode, // kDefault_BitmapType
350 GrSamplerState::kRadial_SampleMode, // kRadial_BitmapType
351 GrSamplerState::kSweep_SampleMode, // kSweep_BitmapType
352 GrSamplerState::kRadial2_SampleMode, // kTwoPointRadial_BitmapType
353};
354
355bool SkGpuDevice::skPaint2GrPaintNoShader(const SkPaint& skPaint,
356 bool justAlpha,
357 GrPaint* grPaint) {
358
359 grPaint->fDither = skPaint.isDither();
360 grPaint->fAntiAlias = skPaint.isAntiAlias();
361
362 SkXfermode::Coeff sm = SkXfermode::kOne_Coeff;
363 SkXfermode::Coeff dm = SkXfermode::kISA_Coeff;
364
365 SkXfermode* mode = skPaint.getXfermode();
366 if (mode) {
367 if (!mode->asCoeff(&sm, &dm)) {
reed@google.com1a2e8d22011-01-21 22:08:29 +0000368 SkDEBUGCODE(SkDebugf("Unsupported xfer mode.\n");)
bsalomon@google.com5782d712011-01-21 21:03:59 +0000369#if 0
370 return false;
371#endif
372 }
373 }
374 grPaint->fSrcBlendCoeff = sk_blend_to_grblend(sm);
375 grPaint->fDstBlendCoeff = sk_blend_to_grblend(dm);
376
377 if (justAlpha) {
378 uint8_t alpha = skPaint.getAlpha();
379 grPaint->fColor = GrColorPackRGBA(alpha, alpha, alpha, alpha);
380 } else {
381 grPaint->fColor = SkGr::SkColor2GrColor(skPaint.getColor());
382 grPaint->setTexture(NULL);
383 }
384 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000385}
386
bsalomon@google.com5782d712011-01-21 21:03:59 +0000387bool SkGpuDevice::skPaint2GrPaintShader(const SkPaint& skPaint,
388 SkAutoCachedTexture* act,
389 const SkMatrix& ctm,
390 GrPaint* grPaint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000391
bsalomon@google.com5782d712011-01-21 21:03:59 +0000392 SkASSERT(NULL != act);
reed@google.comac10a2d2010-12-22 21:39:39 +0000393
bsalomon@google.com5782d712011-01-21 21:03:59 +0000394 SkShader* shader = skPaint.getShader();
reed@google.comac10a2d2010-12-22 21:39:39 +0000395 if (NULL == shader) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000396 return this->skPaint2GrPaintNoShader(skPaint, false, grPaint);
397 grPaint->setTexture(NULL);
398 return true;
399 } else if (!this->skPaint2GrPaintNoShader(skPaint, true, grPaint)) {
400 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000401 }
402
bsalomon@google.com5782d712011-01-21 21:03:59 +0000403 SkPaint noAlphaPaint(skPaint);
404 noAlphaPaint.setAlpha(255);
405 shader->setContext(this->accessBitmap(false), noAlphaPaint, ctm);
reed@google.comac10a2d2010-12-22 21:39:39 +0000406
reed@google.comac10a2d2010-12-22 21:39:39 +0000407 SkBitmap bitmap;
408 SkMatrix matrix;
409 SkShader::TileMode tileModes[2];
410 SkScalar twoPointParams[3];
411 SkShader::BitmapType bmptype = shader->asABitmap(&bitmap, &matrix,
412 tileModes, twoPointParams);
413
bsalomon@google.com5782d712011-01-21 21:03:59 +0000414 GrSamplerState::SampleMode sampleMode = sk_bmp_type_to_sample_mode[bmptype];
415 if (-1 == sampleMode) {
416 SkDebugf("shader->asABitmap() == kNone_BitmapType\n");
417 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000418 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000419 grPaint->fSampler.setSampleMode(sampleMode);
bsalomon@google.com0748f212011-02-01 22:56:16 +0000420 grPaint->fSampler.setFilter(skPaint.isFilterBitmap());
bsalomon@google.com5782d712011-01-21 21:03:59 +0000421 grPaint->fSampler.setWrapX(sk_tile_mode_to_grwrap(tileModes[0]));
422 grPaint->fSampler.setWrapY(sk_tile_mode_to_grwrap(tileModes[1]));
reed@google.comac10a2d2010-12-22 21:39:39 +0000423 if (GrSamplerState::kRadial2_SampleMode == sampleMode) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000424 grPaint->fSampler.setRadial2Params(twoPointParams[0],
425 twoPointParams[1],
426 twoPointParams[2] < 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000427 }
428
bsalomon@google.com5782d712011-01-21 21:03:59 +0000429 GrTexture* texture = act->set(this, bitmap, grPaint->fSampler);
reed@google.comac10a2d2010-12-22 21:39:39 +0000430 if (NULL == texture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000431 SkDebugf("Couldn't convert bitmap to texture.\n");
432 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000433 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000434 grPaint->setTexture(texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000435
436 // since our texture coords will be in local space, we wack the texture
437 // matrix to map them back into 0...1 before we load it
438 SkMatrix localM;
439 if (shader->getLocalMatrix(&localM)) {
440 SkMatrix inverse;
441 if (localM.invert(&inverse)) {
442 matrix.preConcat(inverse);
443 }
444 }
445 if (SkShader::kDefault_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000446 GrScalar sx = GrFixedToScalar(GR_Fixed1 / bitmap.width());
447 GrScalar sy = GrFixedToScalar(GR_Fixed1 / bitmap.height());
reed@google.comac10a2d2010-12-22 21:39:39 +0000448 matrix.postScale(sx, sy);
reed@google.comac10a2d2010-12-22 21:39:39 +0000449 } else if (SkShader::kRadial_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000450 GrScalar s = GrFixedToScalar(GR_Fixed1 / bitmap.width());
reed@google.comac10a2d2010-12-22 21:39:39 +0000451 matrix.postScale(s, s);
452 }
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000453 GrMatrix grMat;
454 SkGr::SkMatrix2GrMatrix(matrix, &grMat);
455 grPaint->fSampler.setMatrix(grMat);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000456
457 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000458}
459
460///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com5782d712011-01-21 21:03:59 +0000461
462class SkPositionSource {
463public:
464 SkPositionSource(const SkPoint* points, int count)
465 : fPoints(points), fCount(count) {}
466
467 int count() const { return fCount; }
468
469 void writeValue(int i, GrPoint* dstPosition) const {
470 SkASSERT(i < fCount);
471 dstPosition->fX = SkScalarToGrScalar(fPoints[i].fX);
472 dstPosition->fY = SkScalarToGrScalar(fPoints[i].fY);
473 }
474private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000475 const SkPoint* fPoints;
bsalomon@google.com19628322011-02-03 21:30:17 +0000476 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000477};
478
479class SkTexCoordSource {
480public:
481 SkTexCoordSource(const SkPoint* coords)
482 : fCoords(coords) {}
483
484 void writeValue(int i, GrPoint* dstCoord) const {
485 dstCoord->fX = SkScalarToGrScalar(fCoords[i].fX);
486 dstCoord->fY = SkScalarToGrScalar(fCoords[i].fY);
487 }
488private:
489 const SkPoint* fCoords;
490};
491
492class SkColorSource {
493public:
494 SkColorSource(const SkColor* colors) : fColors(colors) {}
495
496 void writeValue(int i, GrColor* dstColor) const {
497 *dstColor = SkGr::SkColor2GrColor(fColors[i]);
498 }
499private:
500 const SkColor* fColors;
501};
502
503class SkIndexSource {
504public:
505 SkIndexSource(const uint16_t* indices, int count)
506 : fIndices(indices), fCount(count) {
507 }
508
509 int count() const { return fCount; }
510
511 void writeValue(int i, uint16_t* dstIndex) const {
512 *dstIndex = fIndices[i];
513 }
514
515private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000516 const uint16_t* fIndices;
bsalomon@google.com19628322011-02-03 21:30:17 +0000517 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000518};
519
520///////////////////////////////////////////////////////////////////////////////
521
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000522#if 0 // not currently being used so don't compile,
523
bsalomon@google.com5782d712011-01-21 21:03:59 +0000524// can be used for positions or texture coordinates
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000525
bsalomon@google.com5782d712011-01-21 21:03:59 +0000526class SkRectFanSource {
527public:
528 SkRectFanSource(const SkRect& rect) : fRect(rect) {}
529
530 int count() const { return 4; }
531
532 void writeValue(int i, GrPoint* dstPoint) const {
533 SkASSERT(i < 4);
534 dstPoint->fX = SkScalarToGrScalar((i % 3) ? fRect.fRight :
535 fRect.fLeft);
536 dstPoint->fY = SkScalarToGrScalar((i < 2) ? fRect.fTop :
537 fRect.fBottom);
538 }
539private:
540 const SkRect& fRect;
541};
542
543class SkIRectFanSource {
544public:
545 SkIRectFanSource(const SkIRect& rect) : fRect(rect) {}
546
547 int count() const { return 4; }
548
549 void writeValue(int i, GrPoint* dstPoint) const {
550 SkASSERT(i < 4);
551 dstPoint->fX = (i % 3) ? GrIntToScalar(fRect.fRight) :
552 GrIntToScalar(fRect.fLeft);
553 dstPoint->fY = (i < 2) ? GrIntToScalar(fRect.fTop) :
554 GrIntToScalar(fRect.fBottom);
555 }
556private:
557 const SkIRect& fRect;
558};
559
560class SkMatRectFanSource {
561public:
562 SkMatRectFanSource(const SkRect& rect, const SkMatrix& matrix)
563 : fRect(rect), fMatrix(matrix) {}
564
565 int count() const { return 4; }
566
567 void writeValue(int i, GrPoint* dstPoint) const {
568 SkASSERT(i < 4);
569
570#if SK_SCALAR_IS_GR_SCALAR
571 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
572 (i < 2) ? fRect.fTop : fRect.fBottom,
573 (SkPoint*)dstPoint);
574#else
575 SkPoint dst;
576 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
577 (i < 2) ? fRect.fTop : fRect.fBottom,
578 &dst);
579 dstPoint->fX = SkScalarToGrScalar(dst.fX);
580 dstPoint->fY = SkScalarToGrScalar(dst.fY);
581#endif
582 }
583private:
584 const SkRect& fRect;
585 const SkMatrix& fMatrix;
586};
587
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000588#endif
589
reed@google.comac10a2d2010-12-22 21:39:39 +0000590///////////////////////////////////////////////////////////////////////////////
591
592void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
593 CHECK_SHOULD_DRAW(draw);
594
bsalomon@google.com5782d712011-01-21 21:03:59 +0000595 GrPaint grPaint;
596 SkAutoCachedTexture act;
597 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000598 return;
599 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000600
601 fContext->drawPaint(grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000602}
603
604// must be in SkCanvas::PointMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +0000605static const GrPrimitiveType gPointMode2PrimtiveType[] = {
606 kPoints_PrimitiveType,
607 kLines_PrimitiveType,
608 kLineStrip_PrimitiveType
reed@google.comac10a2d2010-12-22 21:39:39 +0000609};
610
611void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000612 size_t count, const SkPoint pts[], const SkPaint& paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000613 CHECK_SHOULD_DRAW(draw);
614
615 SkScalar width = paint.getStrokeWidth();
616 if (width < 0) {
617 return;
618 }
619
620 // we only handle hairlines here, else we let the SkDraw call our drawPath()
621 if (width > 0) {
622 draw.drawPoints(mode, count, pts, paint, true);
623 return;
624 }
625
bsalomon@google.com5782d712011-01-21 21:03:59 +0000626 GrPaint grPaint;
627 SkAutoCachedTexture act;
628 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000629 return;
630 }
631
reed@google.comac10a2d2010-12-22 21:39:39 +0000632#if SK_SCALAR_IS_GR_SCALAR
bsalomon@google.com5782d712011-01-21 21:03:59 +0000633 fContext->drawVertices(grPaint,
634 gPointMode2PrimtiveType[mode],
635 count,
636 (GrPoint*)pts,
637 NULL,
638 NULL,
639 NULL,
640 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000641#else
bsalomon@google.com5782d712011-01-21 21:03:59 +0000642 fContext->drawCustomVertices(grPaint,
643 gPointMode2PrimtiveType[mode],
644 SkPositionSource(pts, count));
reed@google.comac10a2d2010-12-22 21:39:39 +0000645#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000646}
647
reed@google.comc9aa5872011-04-05 21:05:37 +0000648///////////////////////////////////////////////////////////////////////////////
649
650static void setInsetFan(GrPoint pts[4], const GrRect& r,
651 GrScalar dx, GrScalar dy) {
652 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy);
653}
654
655static GrColor getColorForMesh(const GrPaint& paint) {
656 if (NULL == paint.getTexture()) {
657 return paint.fColor;
658 } else {
659 unsigned a = GrColorUnpackA(paint.fColor);
660 return GrColorPackRGBA(a, a, a, a);
661 }
662}
663
664static const uint16_t gFillAARectIdx1[] = {
665 0, 1, 5, 5, 4, 0,
666 1, 2, 6, 6, 5, 1,
667 2, 3, 7, 7, 6, 2,
668 3, 0, 4, 4, 7, 3,
669 4, 5, 6, 6, 7, 4,
670};
671
672static void fillDevAARect(GrContext* ctx, const GrPaint& paint,
673 const GrRect& rect) {
674 if (rect.isEmpty()) {
675 return;
676 }
677
678 GrAutoMatrix avm(ctx, GrMatrix::I());
679
680 GrPoint verts[8];
681 GrPoint* texs = NULL;
682 GrColor colors[8];
683
684 setInsetFan(&verts[ 0], rect, -0.5f, -0.5f);
685 setInsetFan(&verts[ 4], rect, 0.5f, 0.5f);
686
687 sk_memset32(&colors[ 0], 0, 4);
688 sk_memset32(&colors[ 4], getColorForMesh(paint), 4);
689
690 ctx->drawVertices(paint, kTriangles_PrimitiveType,
691 8, verts, texs, colors,
692 gFillAARectIdx1, SK_ARRAY_COUNT(gFillAARectIdx1));
693}
694
695static const uint16_t gStrokeAARectIdx[] = {
696 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
697 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
698 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
699 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
700
701 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
702 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
703 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
704 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
705
706 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
707 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
708 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
709 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
710};
711
712static void strokeDevAARect(GrContext* ctx, const GrPaint& paint,
713 const GrRect& rect, const SkPoint& strokeSize) {
714 const GrScalar dx = SkScalarToGrScalar(strokeSize.fX);
715 const GrScalar dy = SkScalarToGrScalar(strokeSize.fY);
716 const GrScalar rx = dx * 0.5f;
717 const GrScalar ry = dy * 0.5f;
718
719 GrScalar spare;
720 {
721 GrScalar w = rect.width() - dx;
722 GrScalar h = rect.height() - dy;
723 spare = GrMin(w, h);
724 }
725
726 if (spare <= 0) {
727 GrRect r(rect);
728 r.inset(-rx, -ry);
729 fillDevAARect(ctx, paint, r);
730 return;
731 }
reed@google.com7de5fc22011-04-06 14:28:02 +0000732
reed@google.comc9aa5872011-04-05 21:05:37 +0000733 GrAutoMatrix avm(ctx, GrMatrix::I());
734
735 GrPoint verts[16];
736 GrPoint* texs = NULL;
737 GrColor colors[16];
738
739 setInsetFan(&verts[ 0], rect, -rx - 0.5f, -ry - 0.5f);
740 setInsetFan(&verts[ 4], rect, -rx + 0.5f, -ry + 0.5f);
741 setInsetFan(&verts[ 8], rect, rx - 0.5f, ry - 0.5f);
742 setInsetFan(&verts[12], rect, rx + 0.5f, ry + 0.5f);
743
744 sk_memset32(&colors[ 0], 0, 4);
745 sk_memset32(&colors[ 4], getColorForMesh(paint), 8);
746 sk_memset32(&colors[12], 0, 4);
747
748 ctx->drawVertices(paint, kTriangles_PrimitiveType,
749 16, verts, texs, colors,
750 gStrokeAARectIdx, SK_ARRAY_COUNT(gStrokeAARectIdx));
751}
752
reed@google.com7de5fc22011-04-06 14:28:02 +0000753/*
754 * If the paint has a texture, preconcat the ctx's inverse, since when we
755 * draw verts which are already in device coordinates, we need to "undo" that
756 * before we run our vertex shaders, which expect the coordinates to be local.
757 */
758static void preConcatInverseToTextureMatrix(GrContext* ctx, GrPaint* paint) {
759 if (paint->getTexture()) {
760 GrMatrix inverse;
761 if (ctx->getMatrix().invert(&inverse)) {
762 paint->fSampler.preConcatMatrix(inverse);
763 }
764 }
765}
766
reed@google.comac10a2d2010-12-22 21:39:39 +0000767void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
768 const SkPaint& paint) {
769 CHECK_SHOULD_DRAW(draw);
770
reed@google.com62ab7ad2011-04-05 14:08:25 +0000771 const SkMatrix& matrix = *draw.fMatrix;
772 SkPoint strokeSize;
773 SkDraw::RectType type = SkDraw::ComputeRectType(paint, matrix, &strokeSize);
reed@google.comac10a2d2010-12-22 21:39:39 +0000774
reed@google.com62ab7ad2011-04-05 14:08:25 +0000775 if (SkDraw::kPath_RectType == type) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000776 SkPath path;
777 path.addRect(rect);
778 this->drawPath(draw, path, paint, NULL, true);
reed@google.com62ab7ad2011-04-05 14:08:25 +0000779 } else {
780 GrPaint grPaint;
781 SkAutoCachedTexture act;
782 if (!this->skPaint2GrPaintShader(paint, &act, matrix, &grPaint)) {
783 return;
784 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000785
reed@google.comc9aa5872011-04-05 21:05:37 +0000786 bool doAA = paint.isAntiAlias();
reed@google.combf86c632011-04-06 13:42:34 +0000787
reed@google.comc9aa5872011-04-05 21:05:37 +0000788 if (SkDraw::kHair_RectType == type && doAA) {
789 strokeSize.set(SK_Scalar1, SK_Scalar1);
790 type = SkDraw::kStroke_RectType;
reed@google.com62ab7ad2011-04-05 14:08:25 +0000791 }
reed@google.comc9aa5872011-04-05 21:05:37 +0000792
793 switch (type) {
794 case SkDraw::kHair_RectType:
795 SkASSERT(!doAA);
796 fContext->drawRect(grPaint, Sk2Gr(rect), 0);
797 break;
798 case SkDraw::kFill_RectType:
799 if (doAA) {
800 SkRect devRect;
801 matrix.mapRect(&devRect, rect);
reed@google.com7de5fc22011-04-06 14:28:02 +0000802 preConcatInverseToTextureMatrix(fContext, &grPaint);
reed@google.comc9aa5872011-04-05 21:05:37 +0000803 fillDevAARect(fContext, grPaint, Sk2Gr(devRect));
804 } else {
805 fContext->drawRect(grPaint, Sk2Gr(rect), -1);
806 }
807 break;
808 case SkDraw::kStroke_RectType:
809 if (doAA) {
810 SkRect devRect;
811 matrix.mapRect(&devRect, rect);
reed@google.com7de5fc22011-04-06 14:28:02 +0000812 preConcatInverseToTextureMatrix(fContext, &grPaint);
reed@google.comc9aa5872011-04-05 21:05:37 +0000813 strokeDevAARect(fContext, grPaint, Sk2Gr(devRect), strokeSize);
814 } else {
815 fContext->drawRect(grPaint, Sk2Gr(rect), paint.getStrokeWidth());
816 }
817 break;
818 default:
819 SkASSERT(!"bad value for RectType");
820 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000821 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000822}
823
reed@google.com69302852011-02-16 18:08:07 +0000824#include "SkMaskFilter.h"
825#include "SkBounder.h"
826
reed@google.com69302852011-02-16 18:08:07 +0000827static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
828 SkMaskFilter* filter, const SkMatrix& matrix,
829 const SkRegion& clip, SkBounder* bounder,
830 GrPaint* grp) {
831 SkMask srcM, dstM;
832
833 if (!SkDraw::DrawToMask(path, &clip.getBounds(), filter, &matrix, &srcM,
834 SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
835 return false;
836 }
837
838 SkAutoMaskImage autoSrc(&srcM, false);
839
840 if (!filter->filterMask(&dstM, srcM, matrix, NULL)) {
841 return false;
842 }
843 // this will free-up dstM when we're done (allocated in filterMask())
844 SkAutoMaskImage autoDst(&dstM, false);
845
846 if (clip.quickReject(dstM.fBounds)) {
847 return false;
848 }
849 if (bounder && !bounder->doIRect(dstM.fBounds)) {
850 return false;
851 }
852
853 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
854 // the current clip (and identity matrix) and grpaint settings
855
reed@google.com0c219b62011-02-16 21:31:18 +0000856 GrAutoMatrix avm(context, GrMatrix::I());
reed@google.com69302852011-02-16 18:08:07 +0000857
858 const GrGpu::TextureDesc desc = {
859 0,
860 GrGpu::kNone_AALevel,
861 dstM.fBounds.width(),
862 dstM.fBounds.height(),
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000863 kAlpha_8_GrPixelConfig
reed@google.com69302852011-02-16 18:08:07 +0000864 };
865
866 GrTexture* texture = context->createUncachedTexture(desc, dstM.fImage,
867 dstM.fRowBytes);
868 if (NULL == texture) {
869 return false;
870 }
871
reed@google.com0c219b62011-02-16 21:31:18 +0000872 grp->setTexture(texture);
873 texture->unref();
874 grp->fSampler.setClampNoFilter();
reed@google.com69302852011-02-16 18:08:07 +0000875
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000876 GrRect d;
877 d.setLTRB(GrIntToScalar(dstM.fBounds.fLeft),
reed@google.com0c219b62011-02-16 21:31:18 +0000878 GrIntToScalar(dstM.fBounds.fTop),
879 GrIntToScalar(dstM.fBounds.fRight),
880 GrIntToScalar(dstM.fBounds.fBottom));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000881 GrRect s;
882 s.setLTRB(0, 0, GR_Scalar1, GR_Scalar1);
883 context->drawRectToRect(*grp, d, s);
reed@google.com69302852011-02-16 18:08:07 +0000884 return true;
885}
reed@google.com69302852011-02-16 18:08:07 +0000886
reed@google.com0c219b62011-02-16 21:31:18 +0000887void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
reed@google.comac10a2d2010-12-22 21:39:39 +0000888 const SkPaint& paint, const SkMatrix* prePathMatrix,
889 bool pathIsMutable) {
890 CHECK_SHOULD_DRAW(draw);
891
bsalomon@google.com5782d712011-01-21 21:03:59 +0000892 GrPaint grPaint;
893 SkAutoCachedTexture act;
894 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000895 return;
896 }
897
reed@google.com0c219b62011-02-16 21:31:18 +0000898 // BEGIN lift from SkDraw::drawPath()
899
900 SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
901 bool doFill = true;
902 SkPath tmpPath;
reed@google.comac10a2d2010-12-22 21:39:39 +0000903
904 if (prePathMatrix) {
reed@google.come3445642011-02-16 23:20:39 +0000905 SkPath* result = pathPtr;
reed@google.com0c219b62011-02-16 21:31:18 +0000906
reed@google.come3445642011-02-16 23:20:39 +0000907 if (!pathIsMutable) {
908 result = &tmpPath;
909 pathIsMutable = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000910 }
reed@google.come3445642011-02-16 23:20:39 +0000911 // should I push prePathMatrix on our MV stack temporarily, instead
912 // of applying it here? See SkDraw.cpp
913 pathPtr->transform(*prePathMatrix, result);
914 pathPtr = result;
reed@google.comac10a2d2010-12-22 21:39:39 +0000915 }
reed@google.com0c219b62011-02-16 21:31:18 +0000916 // at this point we're done with prePathMatrix
917 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
reed@google.comac10a2d2010-12-22 21:39:39 +0000918
bsalomon@google.com04de7822011-03-25 18:04:43 +0000919 // This "if" is not part of the SkDraw::drawPath() lift.
920 // When we get a 1.0 wide stroke we hairline stroke it instead of creating
921 // a new stroked-path. This is motivated by canvas2D sites that draw
922 // lines as 1.0 wide stroked paths. We can consider doing an alpha-modulated-
923 // hairline for width < 1.0 when AA is enabled.
924 static const int gMatrixMask = ~(SkMatrix::kIdentity_Mask |
925 SkMatrix::kTranslate_Mask);
926 if (!paint.getPathEffect() &&
927 SkPaint::kStroke_Style == paint.getStyle() &&
928 !(draw.fMatrix->getType() & gMatrixMask) &&
929 SK_Scalar1 == paint.getStrokeWidth()) {
930 doFill = false;
931 }
932
933 if (doFill && (paint.getPathEffect() ||
934 paint.getStyle() != SkPaint::kFill_Style)) {
reed@google.com0c219b62011-02-16 21:31:18 +0000935 doFill = paint.getFillPath(*pathPtr, &tmpPath);
936 pathPtr = &tmpPath;
937 }
938
939 // END lift from SkDraw::drawPath()
940
reed@google.com69302852011-02-16 18:08:07 +0000941 if (paint.getMaskFilter()) {
reed@google.com0c219b62011-02-16 21:31:18 +0000942 // avoid possibly allocating a new path in transform if we can
943 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
944
945 // transform the path into device space
reed@google.come3445642011-02-16 23:20:39 +0000946 pathPtr->transform(*draw.fMatrix, devPathPtr);
reed@google.com0c219b62011-02-16 21:31:18 +0000947
948 drawWithMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
reed@google.com69302852011-02-16 18:08:07 +0000949 *draw.fMatrix, *draw.fClip, draw.fBounder, &grPaint);
950 return;
951 }
reed@google.com69302852011-02-16 18:08:07 +0000952
bsalomon@google.comffca4002011-02-22 20:34:01 +0000953 GrPathFill fill = kHairLine_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000954
reed@google.com0c219b62011-02-16 21:31:18 +0000955 if (doFill) {
956 switch (pathPtr->getFillType()) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000957 case SkPath::kWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000958 fill = kWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000959 break;
960 case SkPath::kEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000961 fill = kEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000962 break;
963 case SkPath::kInverseWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000964 fill = kInverseWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000965 break;
966 case SkPath::kInverseEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000967 fill = kInverseEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000968 break;
969 default:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000970 SkDebugf("Unsupported path fill type\n");
reed@google.comac10a2d2010-12-22 21:39:39 +0000971 return;
972 }
973 }
974
reed@google.com0c219b62011-02-16 21:31:18 +0000975 SkGrPathIter iter(*pathPtr);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000976 fContext->drawPath(grPaint, &iter, fill);
reed@google.comac10a2d2010-12-22 21:39:39 +0000977}
978
reed@google.comac10a2d2010-12-22 21:39:39 +0000979void SkGpuDevice::drawBitmap(const SkDraw& draw,
980 const SkBitmap& bitmap,
981 const SkIRect* srcRectPtr,
982 const SkMatrix& m,
983 const SkPaint& paint) {
984 CHECK_SHOULD_DRAW(draw);
985
986 SkIRect srcRect;
987 if (NULL == srcRectPtr) {
988 srcRect.set(0, 0, bitmap.width(), bitmap.height());
989 } else {
990 srcRect = *srcRectPtr;
991 }
992
bsalomon@google.com5782d712011-01-21 21:03:59 +0000993 GrPaint grPaint;
994 if (!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
995 return;
996 }
997 grPaint.fSampler.setFilter(paint.isFilterBitmap());
998
reed@google.com02a7e6c2011-01-28 21:21:49 +0000999 const int maxTextureDim = fContext->getMaxTextureDimension();
1000 if (bitmap.getTexture() || (bitmap.width() <= maxTextureDim &&
1001 bitmap.height() <= maxTextureDim)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001002 // take the fast case
bsalomon@google.com5782d712011-01-21 21:03:59 +00001003 this->internalDrawBitmap(draw, bitmap, srcRect, m, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +00001004 return;
1005 }
1006
1007 // undo the translate done by SkCanvas
1008 int DX = SkMax32(0, srcRect.fLeft);
1009 int DY = SkMax32(0, srcRect.fTop);
1010 // compute clip bounds in local coordinates
1011 SkIRect clipRect;
1012 {
1013 SkRect r;
1014 r.set(draw.fClip->getBounds());
1015 SkMatrix matrix, inverse;
1016 matrix.setConcat(*draw.fMatrix, m);
1017 if (!matrix.invert(&inverse)) {
1018 return;
1019 }
1020 inverse.mapRect(&r);
1021 r.roundOut(&clipRect);
1022 // apply the canvas' translate to our local clip
1023 clipRect.offset(DX, DY);
1024 }
1025
reed@google.com02a7e6c2011-01-28 21:21:49 +00001026 int nx = bitmap.width() / maxTextureDim;
1027 int ny = bitmap.height() / maxTextureDim;
reed@google.comac10a2d2010-12-22 21:39:39 +00001028 for (int x = 0; x <= nx; x++) {
1029 for (int y = 0; y <= ny; y++) {
1030 SkIRect tileR;
reed@google.com02a7e6c2011-01-28 21:21:49 +00001031 tileR.set(x * maxTextureDim, y * maxTextureDim,
1032 (x + 1) * maxTextureDim, (y + 1) * maxTextureDim);
reed@google.comac10a2d2010-12-22 21:39:39 +00001033 if (!SkIRect::Intersects(tileR, clipRect)) {
1034 continue;
1035 }
1036
1037 SkIRect srcR = tileR;
1038 if (!srcR.intersect(srcRect)) {
1039 continue;
1040 }
1041
1042 SkBitmap tmpB;
1043 if (bitmap.extractSubset(&tmpB, tileR)) {
1044 // now offset it to make it "local" to our tmp bitmap
1045 srcR.offset(-tileR.fLeft, -tileR.fTop);
1046
1047 SkMatrix tmpM(m);
1048 {
1049 int dx = tileR.fLeft - DX + SkMax32(0, srcR.fLeft);
1050 int dy = tileR.fTop - DY + SkMax32(0, srcR.fTop);
1051 tmpM.preTranslate(SkIntToScalar(dx), SkIntToScalar(dy));
1052 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001053 this->internalDrawBitmap(draw, tmpB, srcR, tmpM, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +00001054 }
1055 }
1056 }
1057}
1058
1059/*
1060 * This is called by drawBitmap(), which has to handle images that may be too
1061 * large to be represented by a single texture.
1062 *
bsalomon@google.com5782d712011-01-21 21:03:59 +00001063 * internalDrawBitmap assumes that the specified bitmap will fit in a texture
1064 * and that non-texture portion of the GrPaint has already been setup.
reed@google.comac10a2d2010-12-22 21:39:39 +00001065 */
1066void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
1067 const SkBitmap& bitmap,
1068 const SkIRect& srcRect,
1069 const SkMatrix& m,
bsalomon@google.com5782d712011-01-21 21:03:59 +00001070 GrPaint* grPaint) {
reed@google.com02a7e6c2011-01-28 21:21:49 +00001071 SkASSERT(bitmap.width() <= fContext->getMaxTextureDimension() &&
1072 bitmap.height() <= fContext->getMaxTextureDimension());
reed@google.comac10a2d2010-12-22 21:39:39 +00001073
1074 SkAutoLockPixels alp(bitmap);
1075 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
1076 return;
1077 }
1078
bsalomon@google.com5782d712011-01-21 21:03:59 +00001079 grPaint->fSampler.setWrapX(GrSamplerState::kClamp_WrapMode);
1080 grPaint->fSampler.setWrapY(GrSamplerState::kClamp_WrapMode);
1081 grPaint->fSampler.setSampleMode(GrSamplerState::kNormal_SampleMode);
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001082 grPaint->fSampler.setMatrix(GrMatrix::I());
reed@google.comac10a2d2010-12-22 21:39:39 +00001083
1084 GrTexture* texture;
bsalomon@google.com5782d712011-01-21 21:03:59 +00001085 SkAutoCachedTexture act(this, bitmap, grPaint->fSampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +00001086 if (NULL == texture) {
1087 return;
1088 }
1089
bsalomon@google.com5782d712011-01-21 21:03:59 +00001090 grPaint->setTexture(texture);
reed@google.com46799cd2011-02-22 20:56:26 +00001091
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +00001092 GrRect dstRect(0, 0, GrIntToScalar(srcRect.width()), GrIntToScalar(srcRect.height()));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001093 GrRect paintRect;
1094 paintRect.setLTRB(GrFixedToScalar((srcRect.fLeft << 16) / bitmap.width()),
1095 GrFixedToScalar((srcRect.fTop << 16) / bitmap.height()),
1096 GrFixedToScalar((srcRect.fRight << 16) / bitmap.width()),
1097 GrFixedToScalar((srcRect.fBottom << 16) / bitmap.height()));
reed@google.comac10a2d2010-12-22 21:39:39 +00001098
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +00001099 GrMatrix grMat;
1100 SkGr::SkMatrix2GrMatrix(m, &grMat);
reed@google.comac10a2d2010-12-22 21:39:39 +00001101
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +00001102 fContext->drawRectToRect(*grPaint, dstRect, paintRect, &grMat);
reed@google.comac10a2d2010-12-22 21:39:39 +00001103}
1104
1105void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
1106 int left, int top, const SkPaint& paint) {
1107 CHECK_SHOULD_DRAW(draw);
1108
1109 SkAutoLockPixels alp(bitmap);
1110 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
1111 return;
1112 }
1113
bsalomon@google.com5782d712011-01-21 21:03:59 +00001114 GrPaint grPaint;
1115 if(!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
1116 return;
1117 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001118
bsalomon@google.com5782d712011-01-21 21:03:59 +00001119 GrAutoMatrix avm(fContext, GrMatrix::I());
1120
1121 GrTexture* texture;
1122 grPaint.fSampler.setClampNoFilter();
1123 SkAutoCachedTexture act(this, bitmap, grPaint.fSampler, &texture);
1124
bsalomon@google.com5782d712011-01-21 21:03:59 +00001125 grPaint.setTexture(texture);
1126
bsalomon@google.com5782d712011-01-21 21:03:59 +00001127 fContext->drawRectToRect(grPaint,
1128 GrRect(GrIntToScalar(left), GrIntToScalar(top),
1129 GrIntToScalar(left + bitmap.width()),
1130 GrIntToScalar(top + bitmap.height())),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001131 GrRect(0, 0, GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001132}
1133
1134void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
1135 int x, int y, const SkPaint& paint) {
1136 CHECK_SHOULD_DRAW(draw);
1137
bsalomon@google.com5782d712011-01-21 21:03:59 +00001138 GrPaint grPaint;
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001139 if (!((SkGpuDevice*)dev)->bindDeviceAsTexture(&grPaint) ||
bsalomon@google.com5782d712011-01-21 21:03:59 +00001140 !this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
1141 return;
reed@google.comac10a2d2010-12-22 21:39:39 +00001142 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001143
1144 SkASSERT(NULL != grPaint.getTexture());
1145
1146 const SkBitmap& bm = dev->accessBitmap(false);
1147 int w = bm.width();
1148 int h = bm.height();
1149
1150 GrAutoMatrix avm(fContext, GrMatrix::I());
1151
1152 grPaint.fSampler.setClampNoFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +00001153
1154 fContext->drawRectToRect(grPaint,
reed@google.com1a2e8d22011-01-21 22:08:29 +00001155 GrRect(GrIntToScalar(x),
1156 GrIntToScalar(y),
1157 GrIntToScalar(x + w),
bsalomon@google.com5782d712011-01-21 21:03:59 +00001158 GrIntToScalar(y + h)),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001159 GrRect(0, 0, GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001160}
1161
1162///////////////////////////////////////////////////////////////////////////////
1163
1164// must be in SkCanvas::VertexMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +00001165static const GrPrimitiveType gVertexMode2PrimitiveType[] = {
1166 kTriangles_PrimitiveType,
1167 kTriangleStrip_PrimitiveType,
1168 kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +00001169};
1170
1171void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
1172 int vertexCount, const SkPoint vertices[],
1173 const SkPoint texs[], const SkColor colors[],
1174 SkXfermode* xmode,
1175 const uint16_t indices[], int indexCount,
1176 const SkPaint& paint) {
1177 CHECK_SHOULD_DRAW(draw);
1178
bsalomon@google.com5782d712011-01-21 21:03:59 +00001179 GrPaint grPaint;
1180 SkAutoCachedTexture act;
1181 // we ignore the shader if texs is null.
1182 if (NULL == texs) {
1183 if (!this->skPaint2GrPaintNoShader(paint, false, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001184 return;
1185 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001186 } else {
reed@google.com1a2e8d22011-01-21 22:08:29 +00001187 if (!this->skPaint2GrPaintShader(paint, &act,
1188 *draw.fMatrix,
bsalomon@google.com5782d712011-01-21 21:03:59 +00001189 &grPaint)) {
1190 return;
1191 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001192 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001193
1194 if (NULL != xmode && NULL != texs && NULL != colors) {
1195 SkXfermode::Mode mode;
1196 if (!SkXfermode::IsMode(xmode, &mode) ||
1197 SkXfermode::kMultiply_Mode != mode) {
1198 SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
1199#if 0
1200 return
1201#endif
1202 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001203 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001204
1205#if SK_SCALAR_IS_GR_SCALAR
1206 // even if GrColor and SkColor byte offsets match we need
1207 // to perform pre-multiply.
1208 if (NULL == colors) {
1209 fContext->drawVertices(grPaint,
1210 gVertexMode2PrimitiveType[vmode],
1211 vertexCount,
1212 (GrPoint*) vertices,
1213 (GrPoint*) texs,
1214 NULL,
1215 indices,
1216 indexCount);
1217 } else
1218#endif
1219 {
1220 SkTexCoordSource texSrc(texs);
1221 SkColorSource colSrc(colors);
1222 SkIndexSource idxSrc(indices, indexCount);
1223
1224 fContext->drawCustomVertices(grPaint,
1225 gVertexMode2PrimitiveType[vmode],
1226 SkPositionSource(vertices, vertexCount),
1227 (NULL == texs) ? NULL : &texSrc,
1228 (NULL == colors) ? NULL : &colSrc,
1229 (NULL == indices) ? NULL : &idxSrc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001230 }
1231}
1232
1233///////////////////////////////////////////////////////////////////////////////
1234
1235static void GlyphCacheAuxProc(void* data) {
1236 delete (GrFontScaler*)data;
1237}
1238
1239static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) {
1240 void* auxData;
1241 GrFontScaler* scaler = NULL;
1242 if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
1243 scaler = (GrFontScaler*)auxData;
1244 }
1245 if (NULL == scaler) {
1246 scaler = new SkGrFontScaler(cache);
1247 cache->setAuxProc(GlyphCacheAuxProc, scaler);
1248 }
1249 return scaler;
1250}
1251
1252static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
1253 SkFixed fx, SkFixed fy,
1254 const SkGlyph& glyph) {
1255 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1256
1257 GrSkDrawProcs* procs = (GrSkDrawProcs*)state.fDraw->fProcs;
1258
1259 if (NULL == procs->fFontScaler) {
1260 procs->fFontScaler = get_gr_font_scaler(state.fCache);
1261 }
1262 procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0),
1263 SkIntToFixed(SkFixedFloor(fx)), fy,
1264 procs->fFontScaler);
1265}
1266
bsalomon@google.com5782d712011-01-21 21:03:59 +00001267SkDrawProcs* SkGpuDevice::initDrawForText(GrTextContext* context) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001268
1269 // deferred allocation
1270 if (NULL == fDrawProcs) {
1271 fDrawProcs = new GrSkDrawProcs;
1272 fDrawProcs->fD1GProc = SkGPU_Draw1Glyph;
1273 fDrawProcs->fContext = fContext;
1274 }
1275
1276 // init our (and GL's) state
1277 fDrawProcs->fTextContext = context;
1278 fDrawProcs->fFontScaler = NULL;
1279 return fDrawProcs;
1280}
1281
1282void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
1283 size_t byteLength, SkScalar x, SkScalar y,
1284 const SkPaint& paint) {
1285 CHECK_SHOULD_DRAW(draw);
1286
1287 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1288 // this guy will just call our drawPath()
1289 draw.drawText((const char*)text, byteLength, x, y, paint);
1290 } else {
1291 SkAutoExtMatrix aem(draw.fExtMatrix);
1292 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001293
1294 GrPaint grPaint;
1295 SkAutoCachedTexture act;
1296
1297 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1298 return;
1299 }
1300 GrTextContext context(fContext, grPaint, aem.extMatrix());
1301 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001302 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
1303 }
1304}
1305
1306void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
1307 size_t byteLength, const SkScalar pos[],
1308 SkScalar constY, int scalarsPerPos,
1309 const SkPaint& paint) {
1310 CHECK_SHOULD_DRAW(draw);
1311
1312 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1313 // this guy will just call our drawPath()
1314 draw.drawPosText((const char*)text, byteLength, pos, constY,
1315 scalarsPerPos, paint);
1316 } else {
1317 SkAutoExtMatrix aem(draw.fExtMatrix);
1318 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001319
1320 GrPaint grPaint;
1321 SkAutoCachedTexture act;
1322 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1323 return;
1324 }
1325
1326 GrTextContext context(fContext, grPaint, aem.extMatrix());
1327 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001328 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
1329 scalarsPerPos, paint);
1330 }
1331}
1332
1333void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
1334 size_t len, const SkPath& path,
1335 const SkMatrix* m, const SkPaint& paint) {
1336 CHECK_SHOULD_DRAW(draw);
1337
1338 SkASSERT(draw.fDevice == this);
1339 draw.drawTextOnPath((const char*)text, len, path, m, paint);
1340}
1341
1342///////////////////////////////////////////////////////////////////////////////
1343
reed@google.comf67e4cf2011-03-15 20:56:58 +00001344bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
1345 if (!paint.isLCDRenderText()) {
1346 // we're cool with the paint as is
1347 return false;
1348 }
1349
1350 if (paint.getShader() ||
1351 paint.getXfermode() || // unless its srcover
1352 paint.getMaskFilter() ||
1353 paint.getRasterizer() ||
1354 paint.getColorFilter() ||
1355 paint.getPathEffect() ||
1356 paint.isFakeBoldText() ||
1357 paint.getStyle() != SkPaint::kFill_Style) {
1358 // turn off lcd
1359 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
1360 flags->fHinting = paint.getHinting();
1361 return true;
1362 }
1363 // we're cool with the paint as is
1364 return false;
1365}
1366
1367///////////////////////////////////////////////////////////////////////////////
1368
reed@google.comac10a2d2010-12-22 21:39:39 +00001369SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
1370 const GrSamplerState& sampler,
1371 GrTexture** texture,
1372 bool forDeviceRenderTarget) {
1373 GrContext* ctx = this->context();
1374 uint32_t p0, p1;
1375 if (forDeviceRenderTarget) {
1376 p0 = p1 = -1;
1377 } else {
1378 p0 = bitmap.getGenerationID();
1379 p1 = bitmap.pixelRefOffset();
1380 }
1381
1382 GrTexture* newTexture = NULL;
1383 GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
1384 GrTextureEntry* entry = ctx->findAndLockTexture(&key, sampler);
1385
1386 if (NULL == entry) {
1387
1388 if (forDeviceRenderTarget) {
1389 const GrGpu::TextureDesc desc = {
1390 GrGpu::kRenderTarget_TextureFlag,
1391 GrGpu::kNone_AALevel,
1392 bitmap.width(),
1393 bitmap.height(),
1394 SkGr::Bitmap2PixelConfig(bitmap)
1395 };
1396 entry = ctx->createAndLockTexture(&key, sampler, desc, NULL, 0);
1397
1398 } else {
1399 entry = sk_gr_create_bitmap_texture(ctx, &key, sampler, bitmap);
1400 }
1401 if (NULL == entry) {
1402 GrPrintf("---- failed to create texture for cache [%d %d]\n",
1403 bitmap.width(), bitmap.height());
1404 }
1405 }
1406
1407 if (NULL != entry) {
1408 newTexture = entry->texture();
reed@google.comac10a2d2010-12-22 21:39:39 +00001409 if (texture) {
1410 *texture = newTexture;
1411 }
1412 // IMPORTANT: We can't allow another SkGpuDevice to get this
1413 // cache entry until this one is destroyed!
1414 if (forDeviceRenderTarget) {
1415 ctx->detachCachedTexture(entry);
1416 }
1417 }
1418 return (TexCache*)entry;
1419}
1420
1421void SkGpuDevice::unlockCachedTexture(TexCache* cache) {
1422 this->context()->unlockTexture((GrTextureEntry*)cache);
1423}
1424
reed@google.com7b201d22011-01-11 18:59:23 +00001425///////////////////////////////////////////////////////////////////////////////
1426
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001427SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context,
1428 GrRenderTarget* rootRenderTarget)
1429 : fContext(context) {
1430
1431 GrAssert(NULL != context);
1432 GrAssert(NULL != rootRenderTarget);
1433
1434 // check this now rather than passing this value to SkGpuDevice cons.
1435 // we want the rt that is bound *now* in the 3D API, not the one
1436 // at the time of newDevice.
1437 if (SkGpuDevice::Current3DApiRenderTarget() == rootRenderTarget) {
1438 fRootRenderTarget = context->createRenderTargetFrom3DApiState();
1439 } else {
1440 fRootRenderTarget = rootRenderTarget;
1441 rootRenderTarget->ref();
1442 }
reed@google.com7b201d22011-01-11 18:59:23 +00001443 context->ref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001444
reed@google.com7b201d22011-01-11 18:59:23 +00001445}
1446
1447SkGpuDeviceFactory::~SkGpuDeviceFactory() {
1448 fContext->unref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001449 fRootRenderTarget->unref();
reed@google.com7b201d22011-01-11 18:59:23 +00001450}
1451
1452SkDevice* SkGpuDeviceFactory::newDevice(SkCanvas*, SkBitmap::Config config,
1453 int width, int height,
1454 bool isOpaque, bool isLayer) {
1455 SkBitmap bm;
1456 bm.setConfig(config, width, height);
1457 bm.setIsOpaque(isOpaque);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001458 return new SkGpuDevice(fContext, bm, isLayer ? NULL : fRootRenderTarget);
reed@google.com7b201d22011-01-11 18:59:23 +00001459}
reed@google.comac10a2d2010-12-22 21:39:39 +00001460