blob: 2d50c3652de7748cadfe7c1d0aac3efce2cc04bc [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
Scroggo813c33c2011-04-07 20:56:21 +0000240 tmp.lockPixels();
reed@google.comac10a2d2010-12-22 21:39:39 +0000241
Scroggoeb176032011-04-07 21:11:49 +0000242 bool read = fContext->readRenderTargetPixels(fRenderTarget,
243 bounds.fLeft, bounds.fTop,
244 bounds.width(), bounds.height(),
245 kRGBA_8888_GrPixelConfig,
246 tmp.getPixels());
Scroggo813c33c2011-04-07 20:56:21 +0000247 tmp.unlockPixels();
248 if (!read) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000249 return false;
250 }
251
252 tmp.swap(*bitmap);
253 return true;
254}
255
256void SkGpuDevice::writePixels(const SkBitmap& bitmap, int x, int y) {
257 SkAutoLockPixels alp(bitmap);
258 if (!bitmap.readyToDraw()) {
259 return;
260 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000261 GrPixelConfig config = SkGr::BitmapConfig2PixelConfig(bitmap.config(),
262 bitmap.isOpaque());
reed@google.comac10a2d2010-12-22 21:39:39 +0000263 fContext->setRenderTarget(fRenderTarget);
264 // we aren't setting the clip or matrix, so mark as dirty
265 // we don't need to set them for this call and don't have them anyway
266 fNeedPrepareRenderTarget = true;
267
268 fContext->writePixels(x, y, bitmap.width(), bitmap.height(),
269 config, bitmap.getPixels(), bitmap.rowBytes());
270}
271
272///////////////////////////////////////////////////////////////////////////////
273
274static void convert_matrixclip(GrContext* context, const SkMatrix& matrix,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000275 const SkClipStack& clipStack,
reed@google.com6f8f2922011-03-04 22:27:10 +0000276 const SkRegion& clipRegion,
277 const SkIPoint& origin) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000278 GrMatrix grmat;
279 SkGr::SkMatrix2GrMatrix(matrix, &grmat);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000280 context->setMatrix(grmat);
reed@google.comac10a2d2010-12-22 21:39:39 +0000281
282 SkGrClipIterator iter;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000283 iter.reset(clipStack);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000284 const SkIRect& skBounds = clipRegion.getBounds();
285 GrRect bounds;
286 bounds.setLTRB(GrIntToScalar(skBounds.fLeft),
287 GrIntToScalar(skBounds.fTop),
288 GrIntToScalar(skBounds.fRight),
289 GrIntToScalar(skBounds.fBottom));
reed@google.com6f8f2922011-03-04 22:27:10 +0000290 GrClip grc(&iter, GrIntToScalar(-origin.x()), GrIntToScalar(-origin.y()),
291 &bounds);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000292 context->setClip(grc);
reed@google.comac10a2d2010-12-22 21:39:39 +0000293}
294
295// call this ever each draw call, to ensure that the context reflects our state,
296// and not the state from some other canvas/device
297void SkGpuDevice::prepareRenderTarget(const SkDraw& draw) {
298 if (fNeedPrepareRenderTarget ||
bsalomon@google.com5782d712011-01-21 21:03:59 +0000299 fContext->getRenderTarget() != fRenderTarget) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000300
301 fContext->setRenderTarget(fRenderTarget);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000302 SkASSERT(draw.fClipStack);
303 convert_matrixclip(fContext, *draw.fMatrix,
reed@google.com6f8f2922011-03-04 22:27:10 +0000304 *draw.fClipStack, *draw.fClip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000305 fNeedPrepareRenderTarget = false;
306 }
307}
308
reed@google.com46799cd2011-02-22 20:56:26 +0000309void SkGpuDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& clip,
310 const SkClipStack& clipStack) {
311 this->INHERITED::setMatrixClip(matrix, clip, clipStack);
reed@google.comac10a2d2010-12-22 21:39:39 +0000312
reed@google.com6f8f2922011-03-04 22:27:10 +0000313 convert_matrixclip(fContext, matrix, clipStack, clip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000314}
315
316void SkGpuDevice::gainFocus(SkCanvas* canvas, const SkMatrix& matrix,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000317 const SkRegion& clip, const SkClipStack& clipStack) {
318
reed@google.comac10a2d2010-12-22 21:39:39 +0000319 fContext->setRenderTarget(fRenderTarget);
320
bsalomon@google.comd302f142011-03-03 13:54:13 +0000321 this->INHERITED::gainFocus(canvas, matrix, clip, clipStack);
reed@google.comac10a2d2010-12-22 21:39:39 +0000322
reed@google.com6f8f2922011-03-04 22:27:10 +0000323 convert_matrixclip(fContext, matrix, clipStack, clip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000324
325 if (fNeedClear) {
326 fContext->eraseColor(0x0);
327 fNeedClear = false;
328 }
329}
330
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000331bool SkGpuDevice::bindDeviceAsTexture(GrPaint* paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000332 if (NULL != fTexture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000333 paint->setTexture(fTexture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000334 return true;
335 }
336 return false;
337}
338
339///////////////////////////////////////////////////////////////////////////////
340
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000341SK_COMPILE_ASSERT(SkShader::kNone_BitmapType == 0, shader_type_mismatch);
342SK_COMPILE_ASSERT(SkShader::kDefault_BitmapType == 1, shader_type_mismatch);
343SK_COMPILE_ASSERT(SkShader::kRadial_BitmapType == 2, shader_type_mismatch);
344SK_COMPILE_ASSERT(SkShader::kSweep_BitmapType == 3, shader_type_mismatch);
345SK_COMPILE_ASSERT(SkShader::kTwoPointRadial_BitmapType == 4,
346 shader_type_mismatch);
347SK_COMPILE_ASSERT(SkShader::kLast_BitmapType == 4, shader_type_mismatch);
reed@google.comac10a2d2010-12-22 21:39:39 +0000348
bsalomon@google.com5782d712011-01-21 21:03:59 +0000349static const GrSamplerState::SampleMode sk_bmp_type_to_sample_mode[] = {
350 (GrSamplerState::SampleMode) -1, // kNone_BitmapType
351 GrSamplerState::kNormal_SampleMode, // kDefault_BitmapType
352 GrSamplerState::kRadial_SampleMode, // kRadial_BitmapType
353 GrSamplerState::kSweep_SampleMode, // kSweep_BitmapType
354 GrSamplerState::kRadial2_SampleMode, // kTwoPointRadial_BitmapType
355};
356
357bool SkGpuDevice::skPaint2GrPaintNoShader(const SkPaint& skPaint,
358 bool justAlpha,
359 GrPaint* grPaint) {
360
361 grPaint->fDither = skPaint.isDither();
362 grPaint->fAntiAlias = skPaint.isAntiAlias();
363
364 SkXfermode::Coeff sm = SkXfermode::kOne_Coeff;
365 SkXfermode::Coeff dm = SkXfermode::kISA_Coeff;
366
367 SkXfermode* mode = skPaint.getXfermode();
368 if (mode) {
369 if (!mode->asCoeff(&sm, &dm)) {
reed@google.com1a2e8d22011-01-21 22:08:29 +0000370 SkDEBUGCODE(SkDebugf("Unsupported xfer mode.\n");)
bsalomon@google.com5782d712011-01-21 21:03:59 +0000371#if 0
372 return false;
373#endif
374 }
375 }
376 grPaint->fSrcBlendCoeff = sk_blend_to_grblend(sm);
377 grPaint->fDstBlendCoeff = sk_blend_to_grblend(dm);
378
379 if (justAlpha) {
380 uint8_t alpha = skPaint.getAlpha();
381 grPaint->fColor = GrColorPackRGBA(alpha, alpha, alpha, alpha);
382 } else {
383 grPaint->fColor = SkGr::SkColor2GrColor(skPaint.getColor());
384 grPaint->setTexture(NULL);
385 }
386 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000387}
388
bsalomon@google.com5782d712011-01-21 21:03:59 +0000389bool SkGpuDevice::skPaint2GrPaintShader(const SkPaint& skPaint,
390 SkAutoCachedTexture* act,
391 const SkMatrix& ctm,
392 GrPaint* grPaint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000393
bsalomon@google.com5782d712011-01-21 21:03:59 +0000394 SkASSERT(NULL != act);
reed@google.comac10a2d2010-12-22 21:39:39 +0000395
bsalomon@google.com5782d712011-01-21 21:03:59 +0000396 SkShader* shader = skPaint.getShader();
reed@google.comac10a2d2010-12-22 21:39:39 +0000397 if (NULL == shader) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000398 return this->skPaint2GrPaintNoShader(skPaint, false, grPaint);
399 grPaint->setTexture(NULL);
400 return true;
401 } else if (!this->skPaint2GrPaintNoShader(skPaint, true, grPaint)) {
402 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000403 }
404
bsalomon@google.com5782d712011-01-21 21:03:59 +0000405 SkPaint noAlphaPaint(skPaint);
406 noAlphaPaint.setAlpha(255);
407 shader->setContext(this->accessBitmap(false), noAlphaPaint, ctm);
reed@google.comac10a2d2010-12-22 21:39:39 +0000408
reed@google.comac10a2d2010-12-22 21:39:39 +0000409 SkBitmap bitmap;
410 SkMatrix matrix;
411 SkShader::TileMode tileModes[2];
412 SkScalar twoPointParams[3];
413 SkShader::BitmapType bmptype = shader->asABitmap(&bitmap, &matrix,
414 tileModes, twoPointParams);
415
bsalomon@google.com5782d712011-01-21 21:03:59 +0000416 GrSamplerState::SampleMode sampleMode = sk_bmp_type_to_sample_mode[bmptype];
417 if (-1 == sampleMode) {
418 SkDebugf("shader->asABitmap() == kNone_BitmapType\n");
419 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000420 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000421 grPaint->fSampler.setSampleMode(sampleMode);
bsalomon@google.com0748f212011-02-01 22:56:16 +0000422 grPaint->fSampler.setFilter(skPaint.isFilterBitmap());
bsalomon@google.com5782d712011-01-21 21:03:59 +0000423 grPaint->fSampler.setWrapX(sk_tile_mode_to_grwrap(tileModes[0]));
424 grPaint->fSampler.setWrapY(sk_tile_mode_to_grwrap(tileModes[1]));
reed@google.comac10a2d2010-12-22 21:39:39 +0000425 if (GrSamplerState::kRadial2_SampleMode == sampleMode) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000426 grPaint->fSampler.setRadial2Params(twoPointParams[0],
427 twoPointParams[1],
428 twoPointParams[2] < 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000429 }
430
bsalomon@google.com5782d712011-01-21 21:03:59 +0000431 GrTexture* texture = act->set(this, bitmap, grPaint->fSampler);
reed@google.comac10a2d2010-12-22 21:39:39 +0000432 if (NULL == texture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000433 SkDebugf("Couldn't convert bitmap to texture.\n");
434 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000435 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000436 grPaint->setTexture(texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000437
438 // since our texture coords will be in local space, we wack the texture
439 // matrix to map them back into 0...1 before we load it
440 SkMatrix localM;
441 if (shader->getLocalMatrix(&localM)) {
442 SkMatrix inverse;
443 if (localM.invert(&inverse)) {
444 matrix.preConcat(inverse);
445 }
446 }
447 if (SkShader::kDefault_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000448 GrScalar sx = GrFixedToScalar(GR_Fixed1 / bitmap.width());
449 GrScalar sy = GrFixedToScalar(GR_Fixed1 / bitmap.height());
reed@google.comac10a2d2010-12-22 21:39:39 +0000450 matrix.postScale(sx, sy);
reed@google.comac10a2d2010-12-22 21:39:39 +0000451 } else if (SkShader::kRadial_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000452 GrScalar s = GrFixedToScalar(GR_Fixed1 / bitmap.width());
reed@google.comac10a2d2010-12-22 21:39:39 +0000453 matrix.postScale(s, s);
454 }
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000455 GrMatrix grMat;
456 SkGr::SkMatrix2GrMatrix(matrix, &grMat);
457 grPaint->fSampler.setMatrix(grMat);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000458
459 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000460}
461
462///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com5782d712011-01-21 21:03:59 +0000463
464class SkPositionSource {
465public:
466 SkPositionSource(const SkPoint* points, int count)
467 : fPoints(points), fCount(count) {}
468
469 int count() const { return fCount; }
470
471 void writeValue(int i, GrPoint* dstPosition) const {
472 SkASSERT(i < fCount);
473 dstPosition->fX = SkScalarToGrScalar(fPoints[i].fX);
474 dstPosition->fY = SkScalarToGrScalar(fPoints[i].fY);
475 }
476private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000477 const SkPoint* fPoints;
bsalomon@google.com19628322011-02-03 21:30:17 +0000478 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000479};
480
481class SkTexCoordSource {
482public:
483 SkTexCoordSource(const SkPoint* coords)
484 : fCoords(coords) {}
485
486 void writeValue(int i, GrPoint* dstCoord) const {
487 dstCoord->fX = SkScalarToGrScalar(fCoords[i].fX);
488 dstCoord->fY = SkScalarToGrScalar(fCoords[i].fY);
489 }
490private:
491 const SkPoint* fCoords;
492};
493
494class SkColorSource {
495public:
496 SkColorSource(const SkColor* colors) : fColors(colors) {}
497
498 void writeValue(int i, GrColor* dstColor) const {
499 *dstColor = SkGr::SkColor2GrColor(fColors[i]);
500 }
501private:
502 const SkColor* fColors;
503};
504
505class SkIndexSource {
506public:
507 SkIndexSource(const uint16_t* indices, int count)
508 : fIndices(indices), fCount(count) {
509 }
510
511 int count() const { return fCount; }
512
513 void writeValue(int i, uint16_t* dstIndex) const {
514 *dstIndex = fIndices[i];
515 }
516
517private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000518 const uint16_t* fIndices;
bsalomon@google.com19628322011-02-03 21:30:17 +0000519 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000520};
521
522///////////////////////////////////////////////////////////////////////////////
523
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000524#if 0 // not currently being used so don't compile,
525
bsalomon@google.com5782d712011-01-21 21:03:59 +0000526// can be used for positions or texture coordinates
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000527
bsalomon@google.com5782d712011-01-21 21:03:59 +0000528class SkRectFanSource {
529public:
530 SkRectFanSource(const SkRect& rect) : fRect(rect) {}
531
532 int count() const { return 4; }
533
534 void writeValue(int i, GrPoint* dstPoint) const {
535 SkASSERT(i < 4);
536 dstPoint->fX = SkScalarToGrScalar((i % 3) ? fRect.fRight :
537 fRect.fLeft);
538 dstPoint->fY = SkScalarToGrScalar((i < 2) ? fRect.fTop :
539 fRect.fBottom);
540 }
541private:
542 const SkRect& fRect;
543};
544
545class SkIRectFanSource {
546public:
547 SkIRectFanSource(const SkIRect& rect) : fRect(rect) {}
548
549 int count() const { return 4; }
550
551 void writeValue(int i, GrPoint* dstPoint) const {
552 SkASSERT(i < 4);
553 dstPoint->fX = (i % 3) ? GrIntToScalar(fRect.fRight) :
554 GrIntToScalar(fRect.fLeft);
555 dstPoint->fY = (i < 2) ? GrIntToScalar(fRect.fTop) :
556 GrIntToScalar(fRect.fBottom);
557 }
558private:
559 const SkIRect& fRect;
560};
561
562class SkMatRectFanSource {
563public:
564 SkMatRectFanSource(const SkRect& rect, const SkMatrix& matrix)
565 : fRect(rect), fMatrix(matrix) {}
566
567 int count() const { return 4; }
568
569 void writeValue(int i, GrPoint* dstPoint) const {
570 SkASSERT(i < 4);
571
572#if SK_SCALAR_IS_GR_SCALAR
573 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
574 (i < 2) ? fRect.fTop : fRect.fBottom,
575 (SkPoint*)dstPoint);
576#else
577 SkPoint dst;
578 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
579 (i < 2) ? fRect.fTop : fRect.fBottom,
580 &dst);
581 dstPoint->fX = SkScalarToGrScalar(dst.fX);
582 dstPoint->fY = SkScalarToGrScalar(dst.fY);
583#endif
584 }
585private:
586 const SkRect& fRect;
587 const SkMatrix& fMatrix;
588};
589
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000590#endif
591
reed@google.comac10a2d2010-12-22 21:39:39 +0000592///////////////////////////////////////////////////////////////////////////////
593
594void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
595 CHECK_SHOULD_DRAW(draw);
596
bsalomon@google.com5782d712011-01-21 21:03:59 +0000597 GrPaint grPaint;
598 SkAutoCachedTexture act;
599 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000600 return;
601 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000602
603 fContext->drawPaint(grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000604}
605
606// must be in SkCanvas::PointMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +0000607static const GrPrimitiveType gPointMode2PrimtiveType[] = {
608 kPoints_PrimitiveType,
609 kLines_PrimitiveType,
610 kLineStrip_PrimitiveType
reed@google.comac10a2d2010-12-22 21:39:39 +0000611};
612
613void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000614 size_t count, const SkPoint pts[], const SkPaint& paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000615 CHECK_SHOULD_DRAW(draw);
616
617 SkScalar width = paint.getStrokeWidth();
618 if (width < 0) {
619 return;
620 }
621
622 // we only handle hairlines here, else we let the SkDraw call our drawPath()
623 if (width > 0) {
624 draw.drawPoints(mode, count, pts, paint, true);
625 return;
626 }
627
bsalomon@google.com5782d712011-01-21 21:03:59 +0000628 GrPaint grPaint;
629 SkAutoCachedTexture act;
630 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000631 return;
632 }
633
reed@google.comac10a2d2010-12-22 21:39:39 +0000634#if SK_SCALAR_IS_GR_SCALAR
bsalomon@google.com5782d712011-01-21 21:03:59 +0000635 fContext->drawVertices(grPaint,
636 gPointMode2PrimtiveType[mode],
637 count,
638 (GrPoint*)pts,
639 NULL,
640 NULL,
641 NULL,
642 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000643#else
bsalomon@google.com5782d712011-01-21 21:03:59 +0000644 fContext->drawCustomVertices(grPaint,
645 gPointMode2PrimtiveType[mode],
646 SkPositionSource(pts, count));
reed@google.comac10a2d2010-12-22 21:39:39 +0000647#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000648}
649
reed@google.comc9aa5872011-04-05 21:05:37 +0000650///////////////////////////////////////////////////////////////////////////////
651
652static void setInsetFan(GrPoint pts[4], const GrRect& r,
653 GrScalar dx, GrScalar dy) {
654 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy);
655}
656
657static GrColor getColorForMesh(const GrPaint& paint) {
658 if (NULL == paint.getTexture()) {
659 return paint.fColor;
660 } else {
661 unsigned a = GrColorUnpackA(paint.fColor);
662 return GrColorPackRGBA(a, a, a, a);
663 }
664}
665
666static const uint16_t gFillAARectIdx1[] = {
667 0, 1, 5, 5, 4, 0,
668 1, 2, 6, 6, 5, 1,
669 2, 3, 7, 7, 6, 2,
670 3, 0, 4, 4, 7, 3,
671 4, 5, 6, 6, 7, 4,
672};
673
674static void fillDevAARect(GrContext* ctx, const GrPaint& paint,
675 const GrRect& rect) {
676 if (rect.isEmpty()) {
677 return;
678 }
679
680 GrAutoMatrix avm(ctx, GrMatrix::I());
681
682 GrPoint verts[8];
683 GrPoint* texs = NULL;
684 GrColor colors[8];
685
686 setInsetFan(&verts[ 0], rect, -0.5f, -0.5f);
687 setInsetFan(&verts[ 4], rect, 0.5f, 0.5f);
688
689 sk_memset32(&colors[ 0], 0, 4);
690 sk_memset32(&colors[ 4], getColorForMesh(paint), 4);
691
692 ctx->drawVertices(paint, kTriangles_PrimitiveType,
693 8, verts, texs, colors,
694 gFillAARectIdx1, SK_ARRAY_COUNT(gFillAARectIdx1));
695}
696
697static const uint16_t gStrokeAARectIdx[] = {
698 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
699 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
700 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
701 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
702
703 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
704 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
705 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
706 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
707
708 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
709 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
710 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
711 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
712};
713
714static void strokeDevAARect(GrContext* ctx, const GrPaint& paint,
715 const GrRect& rect, const SkPoint& strokeSize) {
716 const GrScalar dx = SkScalarToGrScalar(strokeSize.fX);
717 const GrScalar dy = SkScalarToGrScalar(strokeSize.fY);
718 const GrScalar rx = dx * 0.5f;
719 const GrScalar ry = dy * 0.5f;
720
721 GrScalar spare;
722 {
723 GrScalar w = rect.width() - dx;
724 GrScalar h = rect.height() - dy;
725 spare = GrMin(w, h);
726 }
727
728 if (spare <= 0) {
729 GrRect r(rect);
730 r.inset(-rx, -ry);
731 fillDevAARect(ctx, paint, r);
732 return;
733 }
reed@google.com7de5fc22011-04-06 14:28:02 +0000734
reed@google.comc9aa5872011-04-05 21:05:37 +0000735 GrAutoMatrix avm(ctx, GrMatrix::I());
736
737 GrPoint verts[16];
738 GrPoint* texs = NULL;
739 GrColor colors[16];
740
741 setInsetFan(&verts[ 0], rect, -rx - 0.5f, -ry - 0.5f);
742 setInsetFan(&verts[ 4], rect, -rx + 0.5f, -ry + 0.5f);
743 setInsetFan(&verts[ 8], rect, rx - 0.5f, ry - 0.5f);
744 setInsetFan(&verts[12], rect, rx + 0.5f, ry + 0.5f);
745
746 sk_memset32(&colors[ 0], 0, 4);
747 sk_memset32(&colors[ 4], getColorForMesh(paint), 8);
748 sk_memset32(&colors[12], 0, 4);
749
750 ctx->drawVertices(paint, kTriangles_PrimitiveType,
751 16, verts, texs, colors,
752 gStrokeAARectIdx, SK_ARRAY_COUNT(gStrokeAARectIdx));
753}
754
reed@google.com7de5fc22011-04-06 14:28:02 +0000755/*
756 * If the paint has a texture, preconcat the ctx's inverse, since when we
757 * draw verts which are already in device coordinates, we need to "undo" that
758 * before we run our vertex shaders, which expect the coordinates to be local.
759 */
760static void preConcatInverseToTextureMatrix(GrContext* ctx, GrPaint* paint) {
761 if (paint->getTexture()) {
762 GrMatrix inverse;
763 if (ctx->getMatrix().invert(&inverse)) {
764 paint->fSampler.preConcatMatrix(inverse);
765 }
766 }
767}
768
reed@google.comac10a2d2010-12-22 21:39:39 +0000769void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
770 const SkPaint& paint) {
771 CHECK_SHOULD_DRAW(draw);
772
reed@google.com62ab7ad2011-04-05 14:08:25 +0000773 const SkMatrix& matrix = *draw.fMatrix;
774 SkPoint strokeSize;
775 SkDraw::RectType type = SkDraw::ComputeRectType(paint, matrix, &strokeSize);
reed@google.comac10a2d2010-12-22 21:39:39 +0000776
reed@google.com62ab7ad2011-04-05 14:08:25 +0000777 if (SkDraw::kPath_RectType == type) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000778 SkPath path;
779 path.addRect(rect);
780 this->drawPath(draw, path, paint, NULL, true);
reed@google.com62ab7ad2011-04-05 14:08:25 +0000781 } else {
782 GrPaint grPaint;
783 SkAutoCachedTexture act;
784 if (!this->skPaint2GrPaintShader(paint, &act, matrix, &grPaint)) {
785 return;
786 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000787
reed@google.comc9aa5872011-04-05 21:05:37 +0000788 bool doAA = paint.isAntiAlias();
reed@google.combf86c632011-04-06 13:42:34 +0000789
reed@google.comc9aa5872011-04-05 21:05:37 +0000790 if (SkDraw::kHair_RectType == type && doAA) {
791 strokeSize.set(SK_Scalar1, SK_Scalar1);
792 type = SkDraw::kStroke_RectType;
reed@google.com62ab7ad2011-04-05 14:08:25 +0000793 }
reed@google.comc9aa5872011-04-05 21:05:37 +0000794
795 switch (type) {
796 case SkDraw::kHair_RectType:
797 SkASSERT(!doAA);
798 fContext->drawRect(grPaint, Sk2Gr(rect), 0);
799 break;
800 case SkDraw::kFill_RectType:
801 if (doAA) {
802 SkRect devRect;
803 matrix.mapRect(&devRect, rect);
reed@google.com7de5fc22011-04-06 14:28:02 +0000804 preConcatInverseToTextureMatrix(fContext, &grPaint);
reed@google.comc9aa5872011-04-05 21:05:37 +0000805 fillDevAARect(fContext, grPaint, Sk2Gr(devRect));
806 } else {
807 fContext->drawRect(grPaint, Sk2Gr(rect), -1);
808 }
809 break;
810 case SkDraw::kStroke_RectType:
811 if (doAA) {
812 SkRect devRect;
813 matrix.mapRect(&devRect, rect);
reed@google.com7de5fc22011-04-06 14:28:02 +0000814 preConcatInverseToTextureMatrix(fContext, &grPaint);
reed@google.comc9aa5872011-04-05 21:05:37 +0000815 strokeDevAARect(fContext, grPaint, Sk2Gr(devRect), strokeSize);
816 } else {
817 fContext->drawRect(grPaint, Sk2Gr(rect), paint.getStrokeWidth());
818 }
819 break;
820 default:
821 SkASSERT(!"bad value for RectType");
822 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000823 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000824}
825
reed@google.com69302852011-02-16 18:08:07 +0000826#include "SkMaskFilter.h"
827#include "SkBounder.h"
828
reed@google.com69302852011-02-16 18:08:07 +0000829static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
830 SkMaskFilter* filter, const SkMatrix& matrix,
831 const SkRegion& clip, SkBounder* bounder,
832 GrPaint* grp) {
833 SkMask srcM, dstM;
834
835 if (!SkDraw::DrawToMask(path, &clip.getBounds(), filter, &matrix, &srcM,
836 SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
837 return false;
838 }
839
840 SkAutoMaskImage autoSrc(&srcM, false);
841
842 if (!filter->filterMask(&dstM, srcM, matrix, NULL)) {
843 return false;
844 }
845 // this will free-up dstM when we're done (allocated in filterMask())
846 SkAutoMaskImage autoDst(&dstM, false);
847
848 if (clip.quickReject(dstM.fBounds)) {
849 return false;
850 }
851 if (bounder && !bounder->doIRect(dstM.fBounds)) {
852 return false;
853 }
854
855 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
856 // the current clip (and identity matrix) and grpaint settings
857
reed@google.com0c219b62011-02-16 21:31:18 +0000858 GrAutoMatrix avm(context, GrMatrix::I());
reed@google.com69302852011-02-16 18:08:07 +0000859
860 const GrGpu::TextureDesc desc = {
861 0,
862 GrGpu::kNone_AALevel,
863 dstM.fBounds.width(),
864 dstM.fBounds.height(),
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000865 kAlpha_8_GrPixelConfig
reed@google.com69302852011-02-16 18:08:07 +0000866 };
867
868 GrTexture* texture = context->createUncachedTexture(desc, dstM.fImage,
869 dstM.fRowBytes);
870 if (NULL == texture) {
871 return false;
872 }
873
reed@google.com0c219b62011-02-16 21:31:18 +0000874 grp->setTexture(texture);
875 texture->unref();
876 grp->fSampler.setClampNoFilter();
reed@google.com69302852011-02-16 18:08:07 +0000877
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000878 GrRect d;
879 d.setLTRB(GrIntToScalar(dstM.fBounds.fLeft),
reed@google.com0c219b62011-02-16 21:31:18 +0000880 GrIntToScalar(dstM.fBounds.fTop),
881 GrIntToScalar(dstM.fBounds.fRight),
882 GrIntToScalar(dstM.fBounds.fBottom));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000883 GrRect s;
884 s.setLTRB(0, 0, GR_Scalar1, GR_Scalar1);
885 context->drawRectToRect(*grp, d, s);
reed@google.com69302852011-02-16 18:08:07 +0000886 return true;
887}
reed@google.com69302852011-02-16 18:08:07 +0000888
reed@google.com0c219b62011-02-16 21:31:18 +0000889void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
reed@google.comac10a2d2010-12-22 21:39:39 +0000890 const SkPaint& paint, const SkMatrix* prePathMatrix,
891 bool pathIsMutable) {
892 CHECK_SHOULD_DRAW(draw);
893
bsalomon@google.com5782d712011-01-21 21:03:59 +0000894 GrPaint grPaint;
895 SkAutoCachedTexture act;
896 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000897 return;
898 }
899
reed@google.com0c219b62011-02-16 21:31:18 +0000900 // BEGIN lift from SkDraw::drawPath()
901
902 SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
903 bool doFill = true;
904 SkPath tmpPath;
reed@google.comac10a2d2010-12-22 21:39:39 +0000905
906 if (prePathMatrix) {
reed@google.come3445642011-02-16 23:20:39 +0000907 SkPath* result = pathPtr;
reed@google.com0c219b62011-02-16 21:31:18 +0000908
reed@google.come3445642011-02-16 23:20:39 +0000909 if (!pathIsMutable) {
910 result = &tmpPath;
911 pathIsMutable = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000912 }
reed@google.come3445642011-02-16 23:20:39 +0000913 // should I push prePathMatrix on our MV stack temporarily, instead
914 // of applying it here? See SkDraw.cpp
915 pathPtr->transform(*prePathMatrix, result);
916 pathPtr = result;
reed@google.comac10a2d2010-12-22 21:39:39 +0000917 }
reed@google.com0c219b62011-02-16 21:31:18 +0000918 // at this point we're done with prePathMatrix
919 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
reed@google.comac10a2d2010-12-22 21:39:39 +0000920
bsalomon@google.com04de7822011-03-25 18:04:43 +0000921 // This "if" is not part of the SkDraw::drawPath() lift.
922 // When we get a 1.0 wide stroke we hairline stroke it instead of creating
923 // a new stroked-path. This is motivated by canvas2D sites that draw
924 // lines as 1.0 wide stroked paths. We can consider doing an alpha-modulated-
925 // hairline for width < 1.0 when AA is enabled.
926 static const int gMatrixMask = ~(SkMatrix::kIdentity_Mask |
927 SkMatrix::kTranslate_Mask);
928 if (!paint.getPathEffect() &&
929 SkPaint::kStroke_Style == paint.getStyle() &&
930 !(draw.fMatrix->getType() & gMatrixMask) &&
931 SK_Scalar1 == paint.getStrokeWidth()) {
932 doFill = false;
933 }
934
935 if (doFill && (paint.getPathEffect() ||
936 paint.getStyle() != SkPaint::kFill_Style)) {
reed@google.com0c219b62011-02-16 21:31:18 +0000937 doFill = paint.getFillPath(*pathPtr, &tmpPath);
938 pathPtr = &tmpPath;
939 }
940
941 // END lift from SkDraw::drawPath()
942
reed@google.com69302852011-02-16 18:08:07 +0000943 if (paint.getMaskFilter()) {
reed@google.com0c219b62011-02-16 21:31:18 +0000944 // avoid possibly allocating a new path in transform if we can
945 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
946
947 // transform the path into device space
reed@google.come3445642011-02-16 23:20:39 +0000948 pathPtr->transform(*draw.fMatrix, devPathPtr);
reed@google.com0c219b62011-02-16 21:31:18 +0000949
950 drawWithMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
reed@google.com69302852011-02-16 18:08:07 +0000951 *draw.fMatrix, *draw.fClip, draw.fBounder, &grPaint);
952 return;
953 }
reed@google.com69302852011-02-16 18:08:07 +0000954
bsalomon@google.comffca4002011-02-22 20:34:01 +0000955 GrPathFill fill = kHairLine_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000956
reed@google.com0c219b62011-02-16 21:31:18 +0000957 if (doFill) {
958 switch (pathPtr->getFillType()) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000959 case SkPath::kWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000960 fill = kWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000961 break;
962 case SkPath::kEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000963 fill = kEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000964 break;
965 case SkPath::kInverseWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000966 fill = kInverseWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000967 break;
968 case SkPath::kInverseEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000969 fill = kInverseEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000970 break;
971 default:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000972 SkDebugf("Unsupported path fill type\n");
reed@google.comac10a2d2010-12-22 21:39:39 +0000973 return;
974 }
975 }
976
reed@google.com0c219b62011-02-16 21:31:18 +0000977 SkGrPathIter iter(*pathPtr);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000978 fContext->drawPath(grPaint, &iter, fill);
reed@google.comac10a2d2010-12-22 21:39:39 +0000979}
980
reed@google.comac10a2d2010-12-22 21:39:39 +0000981void SkGpuDevice::drawBitmap(const SkDraw& draw,
982 const SkBitmap& bitmap,
983 const SkIRect* srcRectPtr,
984 const SkMatrix& m,
985 const SkPaint& paint) {
986 CHECK_SHOULD_DRAW(draw);
987
988 SkIRect srcRect;
989 if (NULL == srcRectPtr) {
990 srcRect.set(0, 0, bitmap.width(), bitmap.height());
991 } else {
992 srcRect = *srcRectPtr;
993 }
994
bsalomon@google.com5782d712011-01-21 21:03:59 +0000995 GrPaint grPaint;
996 if (!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
997 return;
998 }
999 grPaint.fSampler.setFilter(paint.isFilterBitmap());
1000
reed@google.com02a7e6c2011-01-28 21:21:49 +00001001 const int maxTextureDim = fContext->getMaxTextureDimension();
1002 if (bitmap.getTexture() || (bitmap.width() <= maxTextureDim &&
1003 bitmap.height() <= maxTextureDim)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001004 // take the fast case
bsalomon@google.com5782d712011-01-21 21:03:59 +00001005 this->internalDrawBitmap(draw, bitmap, srcRect, m, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +00001006 return;
1007 }
1008
1009 // undo the translate done by SkCanvas
1010 int DX = SkMax32(0, srcRect.fLeft);
1011 int DY = SkMax32(0, srcRect.fTop);
1012 // compute clip bounds in local coordinates
1013 SkIRect clipRect;
1014 {
1015 SkRect r;
1016 r.set(draw.fClip->getBounds());
1017 SkMatrix matrix, inverse;
1018 matrix.setConcat(*draw.fMatrix, m);
1019 if (!matrix.invert(&inverse)) {
1020 return;
1021 }
1022 inverse.mapRect(&r);
1023 r.roundOut(&clipRect);
1024 // apply the canvas' translate to our local clip
1025 clipRect.offset(DX, DY);
1026 }
1027
reed@google.com02a7e6c2011-01-28 21:21:49 +00001028 int nx = bitmap.width() / maxTextureDim;
1029 int ny = bitmap.height() / maxTextureDim;
reed@google.comac10a2d2010-12-22 21:39:39 +00001030 for (int x = 0; x <= nx; x++) {
1031 for (int y = 0; y <= ny; y++) {
1032 SkIRect tileR;
reed@google.com02a7e6c2011-01-28 21:21:49 +00001033 tileR.set(x * maxTextureDim, y * maxTextureDim,
1034 (x + 1) * maxTextureDim, (y + 1) * maxTextureDim);
reed@google.comac10a2d2010-12-22 21:39:39 +00001035 if (!SkIRect::Intersects(tileR, clipRect)) {
1036 continue;
1037 }
1038
1039 SkIRect srcR = tileR;
1040 if (!srcR.intersect(srcRect)) {
1041 continue;
1042 }
1043
1044 SkBitmap tmpB;
1045 if (bitmap.extractSubset(&tmpB, tileR)) {
1046 // now offset it to make it "local" to our tmp bitmap
1047 srcR.offset(-tileR.fLeft, -tileR.fTop);
1048
1049 SkMatrix tmpM(m);
1050 {
1051 int dx = tileR.fLeft - DX + SkMax32(0, srcR.fLeft);
1052 int dy = tileR.fTop - DY + SkMax32(0, srcR.fTop);
1053 tmpM.preTranslate(SkIntToScalar(dx), SkIntToScalar(dy));
1054 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001055 this->internalDrawBitmap(draw, tmpB, srcR, tmpM, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +00001056 }
1057 }
1058 }
1059}
1060
1061/*
1062 * This is called by drawBitmap(), which has to handle images that may be too
1063 * large to be represented by a single texture.
1064 *
bsalomon@google.com5782d712011-01-21 21:03:59 +00001065 * internalDrawBitmap assumes that the specified bitmap will fit in a texture
1066 * and that non-texture portion of the GrPaint has already been setup.
reed@google.comac10a2d2010-12-22 21:39:39 +00001067 */
1068void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
1069 const SkBitmap& bitmap,
1070 const SkIRect& srcRect,
1071 const SkMatrix& m,
bsalomon@google.com5782d712011-01-21 21:03:59 +00001072 GrPaint* grPaint) {
reed@google.com02a7e6c2011-01-28 21:21:49 +00001073 SkASSERT(bitmap.width() <= fContext->getMaxTextureDimension() &&
1074 bitmap.height() <= fContext->getMaxTextureDimension());
reed@google.comac10a2d2010-12-22 21:39:39 +00001075
1076 SkAutoLockPixels alp(bitmap);
1077 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
1078 return;
1079 }
1080
bsalomon@google.com5782d712011-01-21 21:03:59 +00001081 grPaint->fSampler.setWrapX(GrSamplerState::kClamp_WrapMode);
1082 grPaint->fSampler.setWrapY(GrSamplerState::kClamp_WrapMode);
1083 grPaint->fSampler.setSampleMode(GrSamplerState::kNormal_SampleMode);
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001084 grPaint->fSampler.setMatrix(GrMatrix::I());
reed@google.comac10a2d2010-12-22 21:39:39 +00001085
1086 GrTexture* texture;
bsalomon@google.com5782d712011-01-21 21:03:59 +00001087 SkAutoCachedTexture act(this, bitmap, grPaint->fSampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +00001088 if (NULL == texture) {
1089 return;
1090 }
1091
bsalomon@google.com5782d712011-01-21 21:03:59 +00001092 grPaint->setTexture(texture);
reed@google.com46799cd2011-02-22 20:56:26 +00001093
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +00001094 GrRect dstRect(0, 0, GrIntToScalar(srcRect.width()), GrIntToScalar(srcRect.height()));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001095 GrRect paintRect;
1096 paintRect.setLTRB(GrFixedToScalar((srcRect.fLeft << 16) / bitmap.width()),
1097 GrFixedToScalar((srcRect.fTop << 16) / bitmap.height()),
1098 GrFixedToScalar((srcRect.fRight << 16) / bitmap.width()),
1099 GrFixedToScalar((srcRect.fBottom << 16) / bitmap.height()));
reed@google.comac10a2d2010-12-22 21:39:39 +00001100
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +00001101 GrMatrix grMat;
1102 SkGr::SkMatrix2GrMatrix(m, &grMat);
reed@google.comac10a2d2010-12-22 21:39:39 +00001103
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +00001104 fContext->drawRectToRect(*grPaint, dstRect, paintRect, &grMat);
reed@google.comac10a2d2010-12-22 21:39:39 +00001105}
1106
1107void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
1108 int left, int top, const SkPaint& paint) {
1109 CHECK_SHOULD_DRAW(draw);
1110
1111 SkAutoLockPixels alp(bitmap);
1112 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
1113 return;
1114 }
1115
bsalomon@google.com5782d712011-01-21 21:03:59 +00001116 GrPaint grPaint;
1117 if(!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
1118 return;
1119 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001120
bsalomon@google.com5782d712011-01-21 21:03:59 +00001121 GrAutoMatrix avm(fContext, GrMatrix::I());
1122
1123 GrTexture* texture;
1124 grPaint.fSampler.setClampNoFilter();
1125 SkAutoCachedTexture act(this, bitmap, grPaint.fSampler, &texture);
1126
bsalomon@google.com5782d712011-01-21 21:03:59 +00001127 grPaint.setTexture(texture);
1128
bsalomon@google.com5782d712011-01-21 21:03:59 +00001129 fContext->drawRectToRect(grPaint,
1130 GrRect(GrIntToScalar(left), GrIntToScalar(top),
1131 GrIntToScalar(left + bitmap.width()),
1132 GrIntToScalar(top + bitmap.height())),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001133 GrRect(0, 0, GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001134}
1135
1136void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
1137 int x, int y, const SkPaint& paint) {
1138 CHECK_SHOULD_DRAW(draw);
1139
bsalomon@google.com5782d712011-01-21 21:03:59 +00001140 GrPaint grPaint;
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001141 if (!((SkGpuDevice*)dev)->bindDeviceAsTexture(&grPaint) ||
bsalomon@google.com5782d712011-01-21 21:03:59 +00001142 !this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
1143 return;
reed@google.comac10a2d2010-12-22 21:39:39 +00001144 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001145
1146 SkASSERT(NULL != grPaint.getTexture());
1147
1148 const SkBitmap& bm = dev->accessBitmap(false);
1149 int w = bm.width();
1150 int h = bm.height();
1151
1152 GrAutoMatrix avm(fContext, GrMatrix::I());
1153
1154 grPaint.fSampler.setClampNoFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +00001155
1156 fContext->drawRectToRect(grPaint,
reed@google.com1a2e8d22011-01-21 22:08:29 +00001157 GrRect(GrIntToScalar(x),
1158 GrIntToScalar(y),
1159 GrIntToScalar(x + w),
bsalomon@google.com5782d712011-01-21 21:03:59 +00001160 GrIntToScalar(y + h)),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001161 GrRect(0, 0, GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001162}
1163
1164///////////////////////////////////////////////////////////////////////////////
1165
1166// must be in SkCanvas::VertexMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +00001167static const GrPrimitiveType gVertexMode2PrimitiveType[] = {
1168 kTriangles_PrimitiveType,
1169 kTriangleStrip_PrimitiveType,
1170 kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +00001171};
1172
1173void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
1174 int vertexCount, const SkPoint vertices[],
1175 const SkPoint texs[], const SkColor colors[],
1176 SkXfermode* xmode,
1177 const uint16_t indices[], int indexCount,
1178 const SkPaint& paint) {
1179 CHECK_SHOULD_DRAW(draw);
1180
bsalomon@google.com5782d712011-01-21 21:03:59 +00001181 GrPaint grPaint;
1182 SkAutoCachedTexture act;
1183 // we ignore the shader if texs is null.
1184 if (NULL == texs) {
1185 if (!this->skPaint2GrPaintNoShader(paint, false, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001186 return;
1187 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001188 } else {
reed@google.com1a2e8d22011-01-21 22:08:29 +00001189 if (!this->skPaint2GrPaintShader(paint, &act,
1190 *draw.fMatrix,
bsalomon@google.com5782d712011-01-21 21:03:59 +00001191 &grPaint)) {
1192 return;
1193 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001194 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001195
1196 if (NULL != xmode && NULL != texs && NULL != colors) {
1197 SkXfermode::Mode mode;
1198 if (!SkXfermode::IsMode(xmode, &mode) ||
1199 SkXfermode::kMultiply_Mode != mode) {
1200 SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
1201#if 0
1202 return
1203#endif
1204 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001205 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001206
1207#if SK_SCALAR_IS_GR_SCALAR
1208 // even if GrColor and SkColor byte offsets match we need
1209 // to perform pre-multiply.
1210 if (NULL == colors) {
1211 fContext->drawVertices(grPaint,
1212 gVertexMode2PrimitiveType[vmode],
1213 vertexCount,
1214 (GrPoint*) vertices,
1215 (GrPoint*) texs,
1216 NULL,
1217 indices,
1218 indexCount);
1219 } else
1220#endif
1221 {
1222 SkTexCoordSource texSrc(texs);
1223 SkColorSource colSrc(colors);
1224 SkIndexSource idxSrc(indices, indexCount);
1225
1226 fContext->drawCustomVertices(grPaint,
1227 gVertexMode2PrimitiveType[vmode],
1228 SkPositionSource(vertices, vertexCount),
1229 (NULL == texs) ? NULL : &texSrc,
1230 (NULL == colors) ? NULL : &colSrc,
1231 (NULL == indices) ? NULL : &idxSrc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001232 }
1233}
1234
1235///////////////////////////////////////////////////////////////////////////////
1236
1237static void GlyphCacheAuxProc(void* data) {
1238 delete (GrFontScaler*)data;
1239}
1240
1241static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) {
1242 void* auxData;
1243 GrFontScaler* scaler = NULL;
1244 if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
1245 scaler = (GrFontScaler*)auxData;
1246 }
1247 if (NULL == scaler) {
1248 scaler = new SkGrFontScaler(cache);
1249 cache->setAuxProc(GlyphCacheAuxProc, scaler);
1250 }
1251 return scaler;
1252}
1253
1254static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
1255 SkFixed fx, SkFixed fy,
1256 const SkGlyph& glyph) {
1257 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1258
1259 GrSkDrawProcs* procs = (GrSkDrawProcs*)state.fDraw->fProcs;
1260
1261 if (NULL == procs->fFontScaler) {
1262 procs->fFontScaler = get_gr_font_scaler(state.fCache);
1263 }
reed@google.com39ce0ac2011-04-08 15:42:19 +00001264
1265 /*
1266 * Skia calls us with fx,fy already biased by 1/2. It does this to speed
1267 * up rounding these, so that all of its procs (like us) can just call
1268 * SkFixedFloor and get the "rounded" value.
1269 *
1270 * We take advantage of that for fx, where we pass a rounded value, but
1271 * we want the fractional fy, so we have to unbias it first.
1272 */
reed@google.comac10a2d2010-12-22 21:39:39 +00001273 procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0),
reed@google.com39ce0ac2011-04-08 15:42:19 +00001274 SkIntToFixed(SkFixedFloor(fx)),
1275 fy - SK_FixedHalf,
reed@google.comac10a2d2010-12-22 21:39:39 +00001276 procs->fFontScaler);
1277}
1278
bsalomon@google.com5782d712011-01-21 21:03:59 +00001279SkDrawProcs* SkGpuDevice::initDrawForText(GrTextContext* context) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001280
1281 // deferred allocation
1282 if (NULL == fDrawProcs) {
1283 fDrawProcs = new GrSkDrawProcs;
1284 fDrawProcs->fD1GProc = SkGPU_Draw1Glyph;
1285 fDrawProcs->fContext = fContext;
1286 }
1287
1288 // init our (and GL's) state
1289 fDrawProcs->fTextContext = context;
1290 fDrawProcs->fFontScaler = NULL;
1291 return fDrawProcs;
1292}
1293
1294void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
1295 size_t byteLength, SkScalar x, SkScalar y,
1296 const SkPaint& paint) {
1297 CHECK_SHOULD_DRAW(draw);
1298
1299 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1300 // this guy will just call our drawPath()
1301 draw.drawText((const char*)text, byteLength, x, y, paint);
1302 } else {
1303 SkAutoExtMatrix aem(draw.fExtMatrix);
1304 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001305
1306 GrPaint grPaint;
1307 SkAutoCachedTexture act;
1308
1309 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1310 return;
1311 }
1312 GrTextContext context(fContext, grPaint, aem.extMatrix());
1313 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001314 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
1315 }
1316}
1317
1318void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
1319 size_t byteLength, const SkScalar pos[],
1320 SkScalar constY, int scalarsPerPos,
1321 const SkPaint& paint) {
1322 CHECK_SHOULD_DRAW(draw);
1323
1324 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1325 // this guy will just call our drawPath()
1326 draw.drawPosText((const char*)text, byteLength, pos, constY,
1327 scalarsPerPos, paint);
1328 } else {
1329 SkAutoExtMatrix aem(draw.fExtMatrix);
1330 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001331
1332 GrPaint grPaint;
1333 SkAutoCachedTexture act;
1334 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1335 return;
1336 }
1337
1338 GrTextContext context(fContext, grPaint, aem.extMatrix());
1339 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001340 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
1341 scalarsPerPos, paint);
1342 }
1343}
1344
1345void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
1346 size_t len, const SkPath& path,
1347 const SkMatrix* m, const SkPaint& paint) {
1348 CHECK_SHOULD_DRAW(draw);
1349
1350 SkASSERT(draw.fDevice == this);
1351 draw.drawTextOnPath((const char*)text, len, path, m, paint);
1352}
1353
1354///////////////////////////////////////////////////////////////////////////////
1355
reed@google.comf67e4cf2011-03-15 20:56:58 +00001356bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
1357 if (!paint.isLCDRenderText()) {
1358 // we're cool with the paint as is
1359 return false;
1360 }
1361
1362 if (paint.getShader() ||
1363 paint.getXfermode() || // unless its srcover
1364 paint.getMaskFilter() ||
1365 paint.getRasterizer() ||
1366 paint.getColorFilter() ||
1367 paint.getPathEffect() ||
1368 paint.isFakeBoldText() ||
1369 paint.getStyle() != SkPaint::kFill_Style) {
1370 // turn off lcd
1371 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
1372 flags->fHinting = paint.getHinting();
1373 return true;
1374 }
1375 // we're cool with the paint as is
1376 return false;
1377}
1378
1379///////////////////////////////////////////////////////////////////////////////
1380
reed@google.comac10a2d2010-12-22 21:39:39 +00001381SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
1382 const GrSamplerState& sampler,
1383 GrTexture** texture,
1384 bool forDeviceRenderTarget) {
1385 GrContext* ctx = this->context();
1386 uint32_t p0, p1;
1387 if (forDeviceRenderTarget) {
1388 p0 = p1 = -1;
1389 } else {
1390 p0 = bitmap.getGenerationID();
1391 p1 = bitmap.pixelRefOffset();
1392 }
1393
1394 GrTexture* newTexture = NULL;
1395 GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
1396 GrTextureEntry* entry = ctx->findAndLockTexture(&key, sampler);
1397
1398 if (NULL == entry) {
1399
1400 if (forDeviceRenderTarget) {
1401 const GrGpu::TextureDesc desc = {
1402 GrGpu::kRenderTarget_TextureFlag,
1403 GrGpu::kNone_AALevel,
1404 bitmap.width(),
1405 bitmap.height(),
1406 SkGr::Bitmap2PixelConfig(bitmap)
1407 };
1408 entry = ctx->createAndLockTexture(&key, sampler, desc, NULL, 0);
1409
1410 } else {
1411 entry = sk_gr_create_bitmap_texture(ctx, &key, sampler, bitmap);
1412 }
1413 if (NULL == entry) {
1414 GrPrintf("---- failed to create texture for cache [%d %d]\n",
1415 bitmap.width(), bitmap.height());
1416 }
1417 }
1418
1419 if (NULL != entry) {
1420 newTexture = entry->texture();
reed@google.comac10a2d2010-12-22 21:39:39 +00001421 if (texture) {
1422 *texture = newTexture;
1423 }
1424 // IMPORTANT: We can't allow another SkGpuDevice to get this
1425 // cache entry until this one is destroyed!
1426 if (forDeviceRenderTarget) {
1427 ctx->detachCachedTexture(entry);
1428 }
1429 }
1430 return (TexCache*)entry;
1431}
1432
1433void SkGpuDevice::unlockCachedTexture(TexCache* cache) {
1434 this->context()->unlockTexture((GrTextureEntry*)cache);
1435}
1436
reed@google.com7b201d22011-01-11 18:59:23 +00001437///////////////////////////////////////////////////////////////////////////////
1438
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001439SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context,
1440 GrRenderTarget* rootRenderTarget)
1441 : fContext(context) {
1442
1443 GrAssert(NULL != context);
1444 GrAssert(NULL != rootRenderTarget);
1445
1446 // check this now rather than passing this value to SkGpuDevice cons.
1447 // we want the rt that is bound *now* in the 3D API, not the one
1448 // at the time of newDevice.
1449 if (SkGpuDevice::Current3DApiRenderTarget() == rootRenderTarget) {
1450 fRootRenderTarget = context->createRenderTargetFrom3DApiState();
1451 } else {
1452 fRootRenderTarget = rootRenderTarget;
1453 rootRenderTarget->ref();
1454 }
reed@google.com7b201d22011-01-11 18:59:23 +00001455 context->ref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001456
reed@google.com7b201d22011-01-11 18:59:23 +00001457}
1458
1459SkGpuDeviceFactory::~SkGpuDeviceFactory() {
1460 fContext->unref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001461 fRootRenderTarget->unref();
reed@google.com7b201d22011-01-11 18:59:23 +00001462}
1463
1464SkDevice* SkGpuDeviceFactory::newDevice(SkCanvas*, SkBitmap::Config config,
1465 int width, int height,
1466 bool isOpaque, bool isLayer) {
1467 SkBitmap bm;
1468 bm.setConfig(config, width, height);
1469 bm.setIsOpaque(isOpaque);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001470 return new SkGpuDevice(fContext, bm, isLayer ? NULL : fRootRenderTarget);
reed@google.com7b201d22011-01-11 18:59:23 +00001471}
reed@google.comac10a2d2010-12-22 21:39:39 +00001472