blob: f89d4b18a5ae02b4b3afd51d9fd03842dc2242db [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);
bsalomon@google.coma7bf6e22011-04-11 19:20:46 +0000312 // We don't need to set them now because the context may not reflect this device.
313 fNeedPrepareRenderTarget = true;
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) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000326 fContext->clear(0x0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000327 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
bsalomon@google.com398109c2011-04-14 18:40:27 +0000594void SkGpuDevice::clear(SkColor color) {
595 fContext->clear(color);
596}
597
reed@google.comac10a2d2010-12-22 21:39:39 +0000598void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
599 CHECK_SHOULD_DRAW(draw);
600
bsalomon@google.com5782d712011-01-21 21:03:59 +0000601 GrPaint grPaint;
602 SkAutoCachedTexture act;
603 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000604 return;
605 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000606
607 fContext->drawPaint(grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000608}
609
610// must be in SkCanvas::PointMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +0000611static const GrPrimitiveType gPointMode2PrimtiveType[] = {
612 kPoints_PrimitiveType,
613 kLines_PrimitiveType,
614 kLineStrip_PrimitiveType
reed@google.comac10a2d2010-12-22 21:39:39 +0000615};
616
617void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000618 size_t count, const SkPoint pts[], const SkPaint& paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000619 CHECK_SHOULD_DRAW(draw);
620
621 SkScalar width = paint.getStrokeWidth();
622 if (width < 0) {
623 return;
624 }
625
626 // we only handle hairlines here, else we let the SkDraw call our drawPath()
627 if (width > 0) {
628 draw.drawPoints(mode, count, pts, paint, true);
629 return;
630 }
631
bsalomon@google.com5782d712011-01-21 21:03:59 +0000632 GrPaint grPaint;
633 SkAutoCachedTexture act;
634 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000635 return;
636 }
637
reed@google.comac10a2d2010-12-22 21:39:39 +0000638#if SK_SCALAR_IS_GR_SCALAR
bsalomon@google.com5782d712011-01-21 21:03:59 +0000639 fContext->drawVertices(grPaint,
640 gPointMode2PrimtiveType[mode],
641 count,
642 (GrPoint*)pts,
643 NULL,
644 NULL,
645 NULL,
646 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000647#else
bsalomon@google.com5782d712011-01-21 21:03:59 +0000648 fContext->drawCustomVertices(grPaint,
649 gPointMode2PrimtiveType[mode],
650 SkPositionSource(pts, count));
reed@google.comac10a2d2010-12-22 21:39:39 +0000651#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000652}
653
reed@google.comc9aa5872011-04-05 21:05:37 +0000654///////////////////////////////////////////////////////////////////////////////
655
656static void setInsetFan(GrPoint pts[4], const GrRect& r,
657 GrScalar dx, GrScalar dy) {
658 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy);
659}
660
661static GrColor getColorForMesh(const GrPaint& paint) {
662 if (NULL == paint.getTexture()) {
663 return paint.fColor;
664 } else {
665 unsigned a = GrColorUnpackA(paint.fColor);
666 return GrColorPackRGBA(a, a, a, a);
667 }
668}
669
670static const uint16_t gFillAARectIdx1[] = {
671 0, 1, 5, 5, 4, 0,
672 1, 2, 6, 6, 5, 1,
673 2, 3, 7, 7, 6, 2,
674 3, 0, 4, 4, 7, 3,
675 4, 5, 6, 6, 7, 4,
676};
677
678static void fillDevAARect(GrContext* ctx, const GrPaint& paint,
679 const GrRect& rect) {
680 if (rect.isEmpty()) {
681 return;
682 }
683
684 GrAutoMatrix avm(ctx, GrMatrix::I());
685
686 GrPoint verts[8];
687 GrPoint* texs = NULL;
688 GrColor colors[8];
689
690 setInsetFan(&verts[ 0], rect, -0.5f, -0.5f);
691 setInsetFan(&verts[ 4], rect, 0.5f, 0.5f);
692
693 sk_memset32(&colors[ 0], 0, 4);
694 sk_memset32(&colors[ 4], getColorForMesh(paint), 4);
695
696 ctx->drawVertices(paint, kTriangles_PrimitiveType,
697 8, verts, texs, colors,
698 gFillAARectIdx1, SK_ARRAY_COUNT(gFillAARectIdx1));
699}
700
701static const uint16_t gStrokeAARectIdx[] = {
702 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
703 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
704 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
705 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
706
707 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
708 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
709 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
710 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
711
712 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
713 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
714 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
715 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
716};
717
718static void strokeDevAARect(GrContext* ctx, const GrPaint& paint,
719 const GrRect& rect, const SkPoint& strokeSize) {
720 const GrScalar dx = SkScalarToGrScalar(strokeSize.fX);
721 const GrScalar dy = SkScalarToGrScalar(strokeSize.fY);
722 const GrScalar rx = dx * 0.5f;
723 const GrScalar ry = dy * 0.5f;
724
725 GrScalar spare;
726 {
727 GrScalar w = rect.width() - dx;
728 GrScalar h = rect.height() - dy;
729 spare = GrMin(w, h);
730 }
731
732 if (spare <= 0) {
733 GrRect r(rect);
734 r.inset(-rx, -ry);
735 fillDevAARect(ctx, paint, r);
736 return;
737 }
reed@google.com7de5fc22011-04-06 14:28:02 +0000738
reed@google.comc9aa5872011-04-05 21:05:37 +0000739 GrAutoMatrix avm(ctx, GrMatrix::I());
740
741 GrPoint verts[16];
742 GrPoint* texs = NULL;
743 GrColor colors[16];
744
745 setInsetFan(&verts[ 0], rect, -rx - 0.5f, -ry - 0.5f);
746 setInsetFan(&verts[ 4], rect, -rx + 0.5f, -ry + 0.5f);
747 setInsetFan(&verts[ 8], rect, rx - 0.5f, ry - 0.5f);
748 setInsetFan(&verts[12], rect, rx + 0.5f, ry + 0.5f);
749
750 sk_memset32(&colors[ 0], 0, 4);
751 sk_memset32(&colors[ 4], getColorForMesh(paint), 8);
752 sk_memset32(&colors[12], 0, 4);
753
754 ctx->drawVertices(paint, kTriangles_PrimitiveType,
755 16, verts, texs, colors,
756 gStrokeAARectIdx, SK_ARRAY_COUNT(gStrokeAARectIdx));
757}
758
reed@google.com7de5fc22011-04-06 14:28:02 +0000759/*
760 * If the paint has a texture, preconcat the ctx's inverse, since when we
761 * draw verts which are already in device coordinates, we need to "undo" that
762 * before we run our vertex shaders, which expect the coordinates to be local.
763 */
764static void preConcatInverseToTextureMatrix(GrContext* ctx, GrPaint* paint) {
765 if (paint->getTexture()) {
766 GrMatrix inverse;
767 if (ctx->getMatrix().invert(&inverse)) {
768 paint->fSampler.preConcatMatrix(inverse);
769 }
770 }
771}
772
reed@google.comac10a2d2010-12-22 21:39:39 +0000773void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
774 const SkPaint& paint) {
775 CHECK_SHOULD_DRAW(draw);
776
reed@google.com62ab7ad2011-04-05 14:08:25 +0000777 const SkMatrix& matrix = *draw.fMatrix;
778 SkPoint strokeSize;
779 SkDraw::RectType type = SkDraw::ComputeRectType(paint, matrix, &strokeSize);
reed@google.comac10a2d2010-12-22 21:39:39 +0000780
reed@google.com62ab7ad2011-04-05 14:08:25 +0000781 if (SkDraw::kPath_RectType == type) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000782 SkPath path;
783 path.addRect(rect);
784 this->drawPath(draw, path, paint, NULL, true);
reed@google.com62ab7ad2011-04-05 14:08:25 +0000785 } else {
786 GrPaint grPaint;
787 SkAutoCachedTexture act;
788 if (!this->skPaint2GrPaintShader(paint, &act, matrix, &grPaint)) {
789 return;
790 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000791
reed@google.comc9aa5872011-04-05 21:05:37 +0000792 bool doAA = paint.isAntiAlias();
reed@google.combf86c632011-04-06 13:42:34 +0000793
reed@google.comc9aa5872011-04-05 21:05:37 +0000794 if (SkDraw::kHair_RectType == type && doAA) {
795 strokeSize.set(SK_Scalar1, SK_Scalar1);
796 type = SkDraw::kStroke_RectType;
reed@google.com62ab7ad2011-04-05 14:08:25 +0000797 }
reed@google.comc9aa5872011-04-05 21:05:37 +0000798
799 switch (type) {
800 case SkDraw::kHair_RectType:
801 SkASSERT(!doAA);
802 fContext->drawRect(grPaint, Sk2Gr(rect), 0);
803 break;
804 case SkDraw::kFill_RectType:
805 if (doAA) {
806 SkRect devRect;
807 matrix.mapRect(&devRect, rect);
reed@google.com7de5fc22011-04-06 14:28:02 +0000808 preConcatInverseToTextureMatrix(fContext, &grPaint);
reed@google.comc9aa5872011-04-05 21:05:37 +0000809 fillDevAARect(fContext, grPaint, Sk2Gr(devRect));
810 } else {
811 fContext->drawRect(grPaint, Sk2Gr(rect), -1);
812 }
813 break;
814 case SkDraw::kStroke_RectType:
815 if (doAA) {
816 SkRect devRect;
817 matrix.mapRect(&devRect, rect);
reed@google.com7de5fc22011-04-06 14:28:02 +0000818 preConcatInverseToTextureMatrix(fContext, &grPaint);
reed@google.comc9aa5872011-04-05 21:05:37 +0000819 strokeDevAARect(fContext, grPaint, Sk2Gr(devRect), strokeSize);
820 } else {
821 fContext->drawRect(grPaint, Sk2Gr(rect), paint.getStrokeWidth());
822 }
823 break;
824 default:
825 SkASSERT(!"bad value for RectType");
826 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000827 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000828}
829
reed@google.com69302852011-02-16 18:08:07 +0000830#include "SkMaskFilter.h"
831#include "SkBounder.h"
832
reed@google.com69302852011-02-16 18:08:07 +0000833static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
834 SkMaskFilter* filter, const SkMatrix& matrix,
835 const SkRegion& clip, SkBounder* bounder,
836 GrPaint* grp) {
837 SkMask srcM, dstM;
838
839 if (!SkDraw::DrawToMask(path, &clip.getBounds(), filter, &matrix, &srcM,
840 SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
841 return false;
842 }
843
844 SkAutoMaskImage autoSrc(&srcM, false);
845
846 if (!filter->filterMask(&dstM, srcM, matrix, NULL)) {
847 return false;
848 }
849 // this will free-up dstM when we're done (allocated in filterMask())
850 SkAutoMaskImage autoDst(&dstM, false);
851
852 if (clip.quickReject(dstM.fBounds)) {
853 return false;
854 }
855 if (bounder && !bounder->doIRect(dstM.fBounds)) {
856 return false;
857 }
858
859 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
860 // the current clip (and identity matrix) and grpaint settings
861
reed@google.com0c219b62011-02-16 21:31:18 +0000862 GrAutoMatrix avm(context, GrMatrix::I());
reed@google.com69302852011-02-16 18:08:07 +0000863
864 const GrGpu::TextureDesc desc = {
865 0,
866 GrGpu::kNone_AALevel,
867 dstM.fBounds.width(),
868 dstM.fBounds.height(),
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000869 kAlpha_8_GrPixelConfig
reed@google.com69302852011-02-16 18:08:07 +0000870 };
871
872 GrTexture* texture = context->createUncachedTexture(desc, dstM.fImage,
873 dstM.fRowBytes);
874 if (NULL == texture) {
875 return false;
876 }
877
reed@google.com0c219b62011-02-16 21:31:18 +0000878 grp->setTexture(texture);
879 texture->unref();
880 grp->fSampler.setClampNoFilter();
reed@google.com69302852011-02-16 18:08:07 +0000881
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000882 GrRect d;
883 d.setLTRB(GrIntToScalar(dstM.fBounds.fLeft),
reed@google.com0c219b62011-02-16 21:31:18 +0000884 GrIntToScalar(dstM.fBounds.fTop),
885 GrIntToScalar(dstM.fBounds.fRight),
886 GrIntToScalar(dstM.fBounds.fBottom));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000887 GrRect s;
888 s.setLTRB(0, 0, GR_Scalar1, GR_Scalar1);
889 context->drawRectToRect(*grp, d, s);
reed@google.com69302852011-02-16 18:08:07 +0000890 return true;
891}
reed@google.com69302852011-02-16 18:08:07 +0000892
reed@google.com0c219b62011-02-16 21:31:18 +0000893void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
reed@google.comac10a2d2010-12-22 21:39:39 +0000894 const SkPaint& paint, const SkMatrix* prePathMatrix,
895 bool pathIsMutable) {
896 CHECK_SHOULD_DRAW(draw);
897
bsalomon@google.com5782d712011-01-21 21:03:59 +0000898 GrPaint grPaint;
899 SkAutoCachedTexture act;
900 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000901 return;
902 }
903
reed@google.com0c219b62011-02-16 21:31:18 +0000904 // BEGIN lift from SkDraw::drawPath()
905
906 SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
907 bool doFill = true;
908 SkPath tmpPath;
reed@google.comac10a2d2010-12-22 21:39:39 +0000909
910 if (prePathMatrix) {
reed@google.come3445642011-02-16 23:20:39 +0000911 SkPath* result = pathPtr;
reed@google.com0c219b62011-02-16 21:31:18 +0000912
reed@google.come3445642011-02-16 23:20:39 +0000913 if (!pathIsMutable) {
914 result = &tmpPath;
915 pathIsMutable = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000916 }
reed@google.come3445642011-02-16 23:20:39 +0000917 // should I push prePathMatrix on our MV stack temporarily, instead
918 // of applying it here? See SkDraw.cpp
919 pathPtr->transform(*prePathMatrix, result);
920 pathPtr = result;
reed@google.comac10a2d2010-12-22 21:39:39 +0000921 }
reed@google.com0c219b62011-02-16 21:31:18 +0000922 // at this point we're done with prePathMatrix
923 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
reed@google.comac10a2d2010-12-22 21:39:39 +0000924
bsalomon@google.com04de7822011-03-25 18:04:43 +0000925 // This "if" is not part of the SkDraw::drawPath() lift.
926 // When we get a 1.0 wide stroke we hairline stroke it instead of creating
927 // a new stroked-path. This is motivated by canvas2D sites that draw
928 // lines as 1.0 wide stroked paths. We can consider doing an alpha-modulated-
929 // hairline for width < 1.0 when AA is enabled.
930 static const int gMatrixMask = ~(SkMatrix::kIdentity_Mask |
931 SkMatrix::kTranslate_Mask);
932 if (!paint.getPathEffect() &&
933 SkPaint::kStroke_Style == paint.getStyle() &&
934 !(draw.fMatrix->getType() & gMatrixMask) &&
935 SK_Scalar1 == paint.getStrokeWidth()) {
936 doFill = false;
937 }
938
939 if (doFill && (paint.getPathEffect() ||
940 paint.getStyle() != SkPaint::kFill_Style)) {
reed@google.com0c219b62011-02-16 21:31:18 +0000941 doFill = paint.getFillPath(*pathPtr, &tmpPath);
942 pathPtr = &tmpPath;
943 }
944
945 // END lift from SkDraw::drawPath()
946
reed@google.com69302852011-02-16 18:08:07 +0000947 if (paint.getMaskFilter()) {
reed@google.com0c219b62011-02-16 21:31:18 +0000948 // avoid possibly allocating a new path in transform if we can
949 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
950
951 // transform the path into device space
reed@google.come3445642011-02-16 23:20:39 +0000952 pathPtr->transform(*draw.fMatrix, devPathPtr);
reed@google.com0c219b62011-02-16 21:31:18 +0000953
954 drawWithMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
reed@google.com69302852011-02-16 18:08:07 +0000955 *draw.fMatrix, *draw.fClip, draw.fBounder, &grPaint);
956 return;
957 }
reed@google.com69302852011-02-16 18:08:07 +0000958
bsalomon@google.comffca4002011-02-22 20:34:01 +0000959 GrPathFill fill = kHairLine_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000960
reed@google.com0c219b62011-02-16 21:31:18 +0000961 if (doFill) {
962 switch (pathPtr->getFillType()) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000963 case SkPath::kWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000964 fill = kWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000965 break;
966 case SkPath::kEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000967 fill = kEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000968 break;
969 case SkPath::kInverseWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000970 fill = kInverseWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000971 break;
972 case SkPath::kInverseEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000973 fill = kInverseEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000974 break;
975 default:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000976 SkDebugf("Unsupported path fill type\n");
reed@google.comac10a2d2010-12-22 21:39:39 +0000977 return;
978 }
979 }
980
reed@google.com0c219b62011-02-16 21:31:18 +0000981 SkGrPathIter iter(*pathPtr);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000982 fContext->drawPath(grPaint, &iter, fill);
reed@google.comac10a2d2010-12-22 21:39:39 +0000983}
984
reed@google.comac10a2d2010-12-22 21:39:39 +0000985void SkGpuDevice::drawBitmap(const SkDraw& draw,
986 const SkBitmap& bitmap,
987 const SkIRect* srcRectPtr,
988 const SkMatrix& m,
989 const SkPaint& paint) {
990 CHECK_SHOULD_DRAW(draw);
991
992 SkIRect srcRect;
993 if (NULL == srcRectPtr) {
994 srcRect.set(0, 0, bitmap.width(), bitmap.height());
995 } else {
996 srcRect = *srcRectPtr;
997 }
998
bsalomon@google.com5782d712011-01-21 21:03:59 +0000999 GrPaint grPaint;
1000 if (!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
1001 return;
1002 }
1003 grPaint.fSampler.setFilter(paint.isFilterBitmap());
1004
reed@google.com02a7e6c2011-01-28 21:21:49 +00001005 const int maxTextureDim = fContext->getMaxTextureDimension();
1006 if (bitmap.getTexture() || (bitmap.width() <= maxTextureDim &&
1007 bitmap.height() <= maxTextureDim)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001008 // take the fast case
bsalomon@google.com5782d712011-01-21 21:03:59 +00001009 this->internalDrawBitmap(draw, bitmap, srcRect, m, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +00001010 return;
1011 }
1012
1013 // undo the translate done by SkCanvas
1014 int DX = SkMax32(0, srcRect.fLeft);
1015 int DY = SkMax32(0, srcRect.fTop);
1016 // compute clip bounds in local coordinates
1017 SkIRect clipRect;
1018 {
1019 SkRect r;
1020 r.set(draw.fClip->getBounds());
1021 SkMatrix matrix, inverse;
1022 matrix.setConcat(*draw.fMatrix, m);
1023 if (!matrix.invert(&inverse)) {
1024 return;
1025 }
1026 inverse.mapRect(&r);
1027 r.roundOut(&clipRect);
1028 // apply the canvas' translate to our local clip
1029 clipRect.offset(DX, DY);
1030 }
1031
reed@google.com02a7e6c2011-01-28 21:21:49 +00001032 int nx = bitmap.width() / maxTextureDim;
1033 int ny = bitmap.height() / maxTextureDim;
reed@google.comac10a2d2010-12-22 21:39:39 +00001034 for (int x = 0; x <= nx; x++) {
1035 for (int y = 0; y <= ny; y++) {
1036 SkIRect tileR;
reed@google.com02a7e6c2011-01-28 21:21:49 +00001037 tileR.set(x * maxTextureDim, y * maxTextureDim,
1038 (x + 1) * maxTextureDim, (y + 1) * maxTextureDim);
reed@google.comac10a2d2010-12-22 21:39:39 +00001039 if (!SkIRect::Intersects(tileR, clipRect)) {
1040 continue;
1041 }
1042
1043 SkIRect srcR = tileR;
1044 if (!srcR.intersect(srcRect)) {
1045 continue;
1046 }
1047
1048 SkBitmap tmpB;
1049 if (bitmap.extractSubset(&tmpB, tileR)) {
1050 // now offset it to make it "local" to our tmp bitmap
1051 srcR.offset(-tileR.fLeft, -tileR.fTop);
1052
1053 SkMatrix tmpM(m);
1054 {
1055 int dx = tileR.fLeft - DX + SkMax32(0, srcR.fLeft);
1056 int dy = tileR.fTop - DY + SkMax32(0, srcR.fTop);
1057 tmpM.preTranslate(SkIntToScalar(dx), SkIntToScalar(dy));
1058 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001059 this->internalDrawBitmap(draw, tmpB, srcR, tmpM, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +00001060 }
1061 }
1062 }
1063}
1064
1065/*
1066 * This is called by drawBitmap(), which has to handle images that may be too
1067 * large to be represented by a single texture.
1068 *
bsalomon@google.com5782d712011-01-21 21:03:59 +00001069 * internalDrawBitmap assumes that the specified bitmap will fit in a texture
1070 * and that non-texture portion of the GrPaint has already been setup.
reed@google.comac10a2d2010-12-22 21:39:39 +00001071 */
1072void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
1073 const SkBitmap& bitmap,
1074 const SkIRect& srcRect,
1075 const SkMatrix& m,
bsalomon@google.com5782d712011-01-21 21:03:59 +00001076 GrPaint* grPaint) {
reed@google.com02a7e6c2011-01-28 21:21:49 +00001077 SkASSERT(bitmap.width() <= fContext->getMaxTextureDimension() &&
1078 bitmap.height() <= fContext->getMaxTextureDimension());
reed@google.comac10a2d2010-12-22 21:39:39 +00001079
1080 SkAutoLockPixels alp(bitmap);
1081 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
1082 return;
1083 }
1084
bsalomon@google.com5782d712011-01-21 21:03:59 +00001085 grPaint->fSampler.setWrapX(GrSamplerState::kClamp_WrapMode);
1086 grPaint->fSampler.setWrapY(GrSamplerState::kClamp_WrapMode);
1087 grPaint->fSampler.setSampleMode(GrSamplerState::kNormal_SampleMode);
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001088 grPaint->fSampler.setMatrix(GrMatrix::I());
reed@google.comac10a2d2010-12-22 21:39:39 +00001089
1090 GrTexture* texture;
bsalomon@google.com5782d712011-01-21 21:03:59 +00001091 SkAutoCachedTexture act(this, bitmap, grPaint->fSampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +00001092 if (NULL == texture) {
1093 return;
1094 }
1095
bsalomon@google.com5782d712011-01-21 21:03:59 +00001096 grPaint->setTexture(texture);
reed@google.com46799cd2011-02-22 20:56:26 +00001097
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +00001098 GrRect dstRect(0, 0, GrIntToScalar(srcRect.width()), GrIntToScalar(srcRect.height()));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001099 GrRect paintRect;
1100 paintRect.setLTRB(GrFixedToScalar((srcRect.fLeft << 16) / bitmap.width()),
1101 GrFixedToScalar((srcRect.fTop << 16) / bitmap.height()),
1102 GrFixedToScalar((srcRect.fRight << 16) / bitmap.width()),
1103 GrFixedToScalar((srcRect.fBottom << 16) / bitmap.height()));
reed@google.comac10a2d2010-12-22 21:39:39 +00001104
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +00001105 GrMatrix grMat;
1106 SkGr::SkMatrix2GrMatrix(m, &grMat);
reed@google.comac10a2d2010-12-22 21:39:39 +00001107
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +00001108 fContext->drawRectToRect(*grPaint, dstRect, paintRect, &grMat);
reed@google.comac10a2d2010-12-22 21:39:39 +00001109}
1110
1111void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
1112 int left, int top, const SkPaint& paint) {
1113 CHECK_SHOULD_DRAW(draw);
1114
1115 SkAutoLockPixels alp(bitmap);
1116 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
1117 return;
1118 }
1119
bsalomon@google.com5782d712011-01-21 21:03:59 +00001120 GrPaint grPaint;
1121 if(!this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
1122 return;
1123 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001124
bsalomon@google.com5782d712011-01-21 21:03:59 +00001125 GrAutoMatrix avm(fContext, GrMatrix::I());
1126
1127 GrTexture* texture;
1128 grPaint.fSampler.setClampNoFilter();
1129 SkAutoCachedTexture act(this, bitmap, grPaint.fSampler, &texture);
1130
bsalomon@google.com5782d712011-01-21 21:03:59 +00001131 grPaint.setTexture(texture);
1132
bsalomon@google.com5782d712011-01-21 21:03:59 +00001133 fContext->drawRectToRect(grPaint,
1134 GrRect(GrIntToScalar(left), GrIntToScalar(top),
1135 GrIntToScalar(left + bitmap.width()),
1136 GrIntToScalar(top + bitmap.height())),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001137 GrRect(0, 0, GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001138}
1139
1140void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
1141 int x, int y, const SkPaint& paint) {
1142 CHECK_SHOULD_DRAW(draw);
1143
bsalomon@google.com5782d712011-01-21 21:03:59 +00001144 GrPaint grPaint;
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001145 if (!((SkGpuDevice*)dev)->bindDeviceAsTexture(&grPaint) ||
bsalomon@google.com5782d712011-01-21 21:03:59 +00001146 !this->skPaint2GrPaintNoShader(paint, true, &grPaint)) {
1147 return;
reed@google.comac10a2d2010-12-22 21:39:39 +00001148 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001149
1150 SkASSERT(NULL != grPaint.getTexture());
1151
1152 const SkBitmap& bm = dev->accessBitmap(false);
1153 int w = bm.width();
1154 int h = bm.height();
1155
1156 GrAutoMatrix avm(fContext, GrMatrix::I());
1157
1158 grPaint.fSampler.setClampNoFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +00001159
1160 fContext->drawRectToRect(grPaint,
reed@google.com1a2e8d22011-01-21 22:08:29 +00001161 GrRect(GrIntToScalar(x),
1162 GrIntToScalar(y),
1163 GrIntToScalar(x + w),
bsalomon@google.com5782d712011-01-21 21:03:59 +00001164 GrIntToScalar(y + h)),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001165 GrRect(0, 0, GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001166}
1167
1168///////////////////////////////////////////////////////////////////////////////
1169
1170// must be in SkCanvas::VertexMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +00001171static const GrPrimitiveType gVertexMode2PrimitiveType[] = {
1172 kTriangles_PrimitiveType,
1173 kTriangleStrip_PrimitiveType,
1174 kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +00001175};
1176
1177void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
1178 int vertexCount, const SkPoint vertices[],
1179 const SkPoint texs[], const SkColor colors[],
1180 SkXfermode* xmode,
1181 const uint16_t indices[], int indexCount,
1182 const SkPaint& paint) {
1183 CHECK_SHOULD_DRAW(draw);
1184
bsalomon@google.com5782d712011-01-21 21:03:59 +00001185 GrPaint grPaint;
1186 SkAutoCachedTexture act;
1187 // we ignore the shader if texs is null.
1188 if (NULL == texs) {
1189 if (!this->skPaint2GrPaintNoShader(paint, false, &grPaint)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001190 return;
1191 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001192 } else {
reed@google.com1a2e8d22011-01-21 22:08:29 +00001193 if (!this->skPaint2GrPaintShader(paint, &act,
1194 *draw.fMatrix,
bsalomon@google.com5782d712011-01-21 21:03:59 +00001195 &grPaint)) {
1196 return;
1197 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001198 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001199
1200 if (NULL != xmode && NULL != texs && NULL != colors) {
1201 SkXfermode::Mode mode;
1202 if (!SkXfermode::IsMode(xmode, &mode) ||
1203 SkXfermode::kMultiply_Mode != mode) {
1204 SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
1205#if 0
1206 return
1207#endif
1208 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001209 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001210
1211#if SK_SCALAR_IS_GR_SCALAR
1212 // even if GrColor and SkColor byte offsets match we need
1213 // to perform pre-multiply.
1214 if (NULL == colors) {
1215 fContext->drawVertices(grPaint,
1216 gVertexMode2PrimitiveType[vmode],
1217 vertexCount,
1218 (GrPoint*) vertices,
1219 (GrPoint*) texs,
1220 NULL,
1221 indices,
1222 indexCount);
1223 } else
1224#endif
1225 {
1226 SkTexCoordSource texSrc(texs);
1227 SkColorSource colSrc(colors);
1228 SkIndexSource idxSrc(indices, indexCount);
1229
1230 fContext->drawCustomVertices(grPaint,
1231 gVertexMode2PrimitiveType[vmode],
1232 SkPositionSource(vertices, vertexCount),
1233 (NULL == texs) ? NULL : &texSrc,
1234 (NULL == colors) ? NULL : &colSrc,
1235 (NULL == indices) ? NULL : &idxSrc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001236 }
1237}
1238
1239///////////////////////////////////////////////////////////////////////////////
1240
1241static void GlyphCacheAuxProc(void* data) {
1242 delete (GrFontScaler*)data;
1243}
1244
1245static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) {
1246 void* auxData;
1247 GrFontScaler* scaler = NULL;
1248 if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
1249 scaler = (GrFontScaler*)auxData;
1250 }
1251 if (NULL == scaler) {
1252 scaler = new SkGrFontScaler(cache);
1253 cache->setAuxProc(GlyphCacheAuxProc, scaler);
1254 }
1255 return scaler;
1256}
1257
1258static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
1259 SkFixed fx, SkFixed fy,
1260 const SkGlyph& glyph) {
1261 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1262
1263 GrSkDrawProcs* procs = (GrSkDrawProcs*)state.fDraw->fProcs;
1264
1265 if (NULL == procs->fFontScaler) {
1266 procs->fFontScaler = get_gr_font_scaler(state.fCache);
1267 }
reed@google.com39ce0ac2011-04-08 15:42:19 +00001268
1269 /*
1270 * Skia calls us with fx,fy already biased by 1/2. It does this to speed
1271 * up rounding these, so that all of its procs (like us) can just call
1272 * SkFixedFloor and get the "rounded" value.
1273 *
1274 * We take advantage of that for fx, where we pass a rounded value, but
1275 * we want the fractional fy, so we have to unbias it first.
1276 */
reed@google.comac10a2d2010-12-22 21:39:39 +00001277 procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0),
reed@google.com39ce0ac2011-04-08 15:42:19 +00001278 SkIntToFixed(SkFixedFloor(fx)),
1279 fy - SK_FixedHalf,
reed@google.comac10a2d2010-12-22 21:39:39 +00001280 procs->fFontScaler);
1281}
1282
bsalomon@google.com5782d712011-01-21 21:03:59 +00001283SkDrawProcs* SkGpuDevice::initDrawForText(GrTextContext* context) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001284
1285 // deferred allocation
1286 if (NULL == fDrawProcs) {
1287 fDrawProcs = new GrSkDrawProcs;
1288 fDrawProcs->fD1GProc = SkGPU_Draw1Glyph;
1289 fDrawProcs->fContext = fContext;
1290 }
1291
1292 // init our (and GL's) state
1293 fDrawProcs->fTextContext = context;
1294 fDrawProcs->fFontScaler = NULL;
1295 return fDrawProcs;
1296}
1297
1298void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
1299 size_t byteLength, SkScalar x, SkScalar y,
1300 const SkPaint& paint) {
1301 CHECK_SHOULD_DRAW(draw);
1302
1303 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1304 // this guy will just call our drawPath()
1305 draw.drawText((const char*)text, byteLength, x, y, paint);
1306 } else {
1307 SkAutoExtMatrix aem(draw.fExtMatrix);
1308 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001309
1310 GrPaint grPaint;
1311 SkAutoCachedTexture act;
1312
1313 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1314 return;
1315 }
1316 GrTextContext context(fContext, grPaint, aem.extMatrix());
1317 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001318 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
1319 }
1320}
1321
1322void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
1323 size_t byteLength, const SkScalar pos[],
1324 SkScalar constY, int scalarsPerPos,
1325 const SkPaint& paint) {
1326 CHECK_SHOULD_DRAW(draw);
1327
1328 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1329 // this guy will just call our drawPath()
1330 draw.drawPosText((const char*)text, byteLength, pos, constY,
1331 scalarsPerPos, paint);
1332 } else {
1333 SkAutoExtMatrix aem(draw.fExtMatrix);
1334 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001335
1336 GrPaint grPaint;
1337 SkAutoCachedTexture act;
1338 if (!this->skPaint2GrPaintShader(paint, &act, *draw.fMatrix, &grPaint)) {
1339 return;
1340 }
1341
1342 GrTextContext context(fContext, grPaint, aem.extMatrix());
1343 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001344 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
1345 scalarsPerPos, paint);
1346 }
1347}
1348
1349void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
1350 size_t len, const SkPath& path,
1351 const SkMatrix* m, const SkPaint& paint) {
1352 CHECK_SHOULD_DRAW(draw);
1353
1354 SkASSERT(draw.fDevice == this);
1355 draw.drawTextOnPath((const char*)text, len, path, m, paint);
1356}
1357
1358///////////////////////////////////////////////////////////////////////////////
1359
reed@google.comf67e4cf2011-03-15 20:56:58 +00001360bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
1361 if (!paint.isLCDRenderText()) {
1362 // we're cool with the paint as is
1363 return false;
1364 }
1365
1366 if (paint.getShader() ||
1367 paint.getXfermode() || // unless its srcover
1368 paint.getMaskFilter() ||
1369 paint.getRasterizer() ||
1370 paint.getColorFilter() ||
1371 paint.getPathEffect() ||
1372 paint.isFakeBoldText() ||
1373 paint.getStyle() != SkPaint::kFill_Style) {
1374 // turn off lcd
1375 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
1376 flags->fHinting = paint.getHinting();
1377 return true;
1378 }
1379 // we're cool with the paint as is
1380 return false;
1381}
1382
1383///////////////////////////////////////////////////////////////////////////////
1384
reed@google.comac10a2d2010-12-22 21:39:39 +00001385SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
1386 const GrSamplerState& sampler,
1387 GrTexture** texture,
1388 bool forDeviceRenderTarget) {
1389 GrContext* ctx = this->context();
1390 uint32_t p0, p1;
1391 if (forDeviceRenderTarget) {
1392 p0 = p1 = -1;
1393 } else {
1394 p0 = bitmap.getGenerationID();
1395 p1 = bitmap.pixelRefOffset();
1396 }
1397
1398 GrTexture* newTexture = NULL;
1399 GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
1400 GrTextureEntry* entry = ctx->findAndLockTexture(&key, sampler);
1401
1402 if (NULL == entry) {
1403
1404 if (forDeviceRenderTarget) {
1405 const GrGpu::TextureDesc desc = {
1406 GrGpu::kRenderTarget_TextureFlag,
1407 GrGpu::kNone_AALevel,
1408 bitmap.width(),
1409 bitmap.height(),
1410 SkGr::Bitmap2PixelConfig(bitmap)
1411 };
1412 entry = ctx->createAndLockTexture(&key, sampler, desc, NULL, 0);
1413
1414 } else {
1415 entry = sk_gr_create_bitmap_texture(ctx, &key, sampler, bitmap);
1416 }
1417 if (NULL == entry) {
1418 GrPrintf("---- failed to create texture for cache [%d %d]\n",
1419 bitmap.width(), bitmap.height());
1420 }
1421 }
1422
1423 if (NULL != entry) {
1424 newTexture = entry->texture();
reed@google.comac10a2d2010-12-22 21:39:39 +00001425 if (texture) {
1426 *texture = newTexture;
1427 }
1428 // IMPORTANT: We can't allow another SkGpuDevice to get this
1429 // cache entry until this one is destroyed!
1430 if (forDeviceRenderTarget) {
1431 ctx->detachCachedTexture(entry);
1432 }
1433 }
1434 return (TexCache*)entry;
1435}
1436
1437void SkGpuDevice::unlockCachedTexture(TexCache* cache) {
1438 this->context()->unlockTexture((GrTextureEntry*)cache);
1439}
1440
reed@google.com7b201d22011-01-11 18:59:23 +00001441///////////////////////////////////////////////////////////////////////////////
1442
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001443SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context,
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001444 GrRenderTarget* rootRenderTarget) {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001445 GrAssert(NULL != context);
1446 GrAssert(NULL != rootRenderTarget);
1447
1448 // check this now rather than passing this value to SkGpuDevice cons.
1449 // we want the rt that is bound *now* in the 3D API, not the one
1450 // at the time of newDevice.
1451 if (SkGpuDevice::Current3DApiRenderTarget() == rootRenderTarget) {
1452 fRootRenderTarget = context->createRenderTargetFrom3DApiState();
1453 } else {
1454 fRootRenderTarget = rootRenderTarget;
1455 rootRenderTarget->ref();
1456 }
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001457
1458 fContext = context;
reed@google.com7b201d22011-01-11 18:59:23 +00001459 context->ref();
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001460
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001461 fRootTexture = NULL;
1462}
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001463
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001464SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context, GrTexture* rootRenderTargetTexture) {
1465 GrAssert(NULL != context);
1466 GrAssert(NULL != rootRenderTargetTexture);
1467 GrAssert(NULL != rootRenderTargetTexture->asRenderTarget());
1468
1469 fRootTexture = rootRenderTargetTexture;
1470 rootRenderTargetTexture->ref();
1471
1472 fRootRenderTarget = rootRenderTargetTexture->asRenderTarget();
1473 fRootRenderTarget->ref();
1474
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001475 fContext = context;
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001476 context->ref();
reed@google.com7b201d22011-01-11 18:59:23 +00001477}
1478
1479SkGpuDeviceFactory::~SkGpuDeviceFactory() {
1480 fContext->unref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001481 fRootRenderTarget->unref();
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001482 GrSafeUnref(fRootTexture);
reed@google.com7b201d22011-01-11 18:59:23 +00001483}
1484
1485SkDevice* SkGpuDeviceFactory::newDevice(SkCanvas*, SkBitmap::Config config,
1486 int width, int height,
1487 bool isOpaque, bool isLayer) {
1488 SkBitmap bm;
1489 bm.setConfig(config, width, height);
1490 bm.setIsOpaque(isOpaque);
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001491 return new SkGpuDevice(fContext, bm, isLayer ? NULL : fRootRenderTarget);
reed@google.com7b201d22011-01-11 18:59:23 +00001492}