blob: 832fc6ea7516b6832603b64a305f0d89b3c5153f [file] [log] [blame]
reed@google.comac10a2d2010-12-22 21:39:39 +00001/*
2 Copyright 2010 Google Inc.
3
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
21#include "SkGpuCanvas.h"
22#include "SkGpuDevice.h"
23#include "SkGrTexturePixelRef.h"
24
25#include "SkDrawProcs.h"
26#include "SkGlyphCache.h"
27
28#define CACHE_LAYER_TEXTURES 1
29
30#if 0
31 extern bool (*gShouldDrawProc)();
32 #define CHECK_SHOULD_DRAW(draw) \
33 do { \
34 if (gShouldDrawProc && !gShouldDrawProc()) return; \
35 this->prepareRenderTarget(draw); \
36 } while (0)
37#else
38 #define CHECK_SHOULD_DRAW(draw) this->prepareRenderTarget(draw)
39#endif
40
41class SkAutoExtMatrix {
42public:
43 SkAutoExtMatrix(const SkMatrix* extMatrix) {
44 if (extMatrix) {
45 SkGr::SkMatrix2GrMatrix(*extMatrix, &fMatrix);
46 fExtMatrix = &fMatrix;
47 } else {
48 fExtMatrix = NULL;
49 }
50 }
51 const GrMatrix* extMatrix() const { return fExtMatrix; }
52
53private:
54 GrMatrix fMatrix;
55 GrMatrix* fExtMatrix; // NULL or &fMatrix
56};
57
58///////////////////////////////////////////////////////////////////////////////
59
60SkGpuDevice::SkAutoCachedTexture::
61 SkAutoCachedTexture(SkGpuDevice* device,
62 const SkBitmap& bitmap,
63 const GrSamplerState& sampler,
64 GrTexture** texture) {
65 GrAssert(texture);
66 fTex = NULL;
67 *texture = this->set(device, bitmap, sampler);
68}
69
70SkGpuDevice::SkAutoCachedTexture::SkAutoCachedTexture() {
71 fTex = NULL;
72}
73
74GrTexture* SkGpuDevice::SkAutoCachedTexture::set(SkGpuDevice* device,
75 const SkBitmap& bitmap,
76 const GrSamplerState& sampler) {
77 if (fTex) {
78 fDevice->unlockCachedTexture(fTex);
79 }
80 fDevice = device;
81 GrTexture* texture = (GrTexture*)bitmap.getTexture();
82 if (texture) {
83 // return the native texture
84 fTex = NULL;
85 device->context()->setTexture(texture);
86 } 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
112SkGpuDevice::SkGpuDevice(SkGpuCanvas* canvas, const SkBitmap& bitmap, bool isLayer)
113 : SkDevice(canvas, bitmap, false) {
114
115 fNeedPrepareRenderTarget = false;
116 fDrawProcs = NULL;
117
118 fContext = canvas->context();
119
120 fCache = NULL;
121 fTexture = NULL;
122 fRenderTarget = NULL;
123 fNeedClear = false;
124
125 if (isLayer) {
126 SkBitmap::Config c = bitmap.config();
127 if (c != SkBitmap::kRGB_565_Config) {
128 c = SkBitmap::kARGB_8888_Config;
129 }
130 SkBitmap bm;
131 bm.setConfig(c, this->width(), this->height());
132
133#if CACHE_LAYER_TEXTURES
134
135 fCache = this->lockCachedTexture(bm, GrSamplerState::ClampNoFilter(),
136 &fTexture, true);
137 if (fCache) {
138 SkASSERT(NULL != fTexture);
139 SkASSERT(fTexture->isRenderTarget());
140 }
141#else
142 const GrGpu::TextureDesc desc = {
143 GrGpu::kRenderTarget_TextureFlag,
144 GrGpu::kNone_AALevel,
145 this->width(),
146 this->height(),
147 SkGr::Bitmap2PixelConfig(bm)
148 };
149
150 fTexture = fContext->createUncachedTexture(desc, NULL, 0);
151#endif
152 if (NULL != fTexture) {
153 fRenderTarget = fTexture->asRenderTarget();
154
155 GrAssert(NULL != fRenderTarget);
156
157 // we defer the actual clear until our gainFocus()
158 fNeedClear = true;
159
160 // wrap the bitmap with a pixelref to expose our texture
161 SkGrTexturePixelRef* pr = new SkGrTexturePixelRef(fTexture);
162 this->setPixelRef(pr, 0)->unref();
163 } else {
164 GrPrintf("--- failed to create gpu-offscreen [%d %d]\n",
165 this->width(), this->height());
166 }
167 }
168
169 if (NULL == fRenderTarget) {
170 GrAssert(NULL == fCache);
171 GrAssert(NULL == fTexture);
172
173 fRenderTarget = fContext->currentRenderTarget();
174 fRenderTarget->ref();
175 fContext->setDefaultRenderTargetSize(this->width(), this->height());
176 }
177}
178
179SkGpuDevice::~SkGpuDevice() {
180 if (fDrawProcs) {
181 delete fDrawProcs;
182 }
183
184 if (fCache) {
185 GrAssert(NULL != fTexture);
186 GrAssert(fRenderTarget == fTexture->asRenderTarget());
187 // IMPORTANT: reattach the rendertarget/tex back to the cache.
188 fContext->reattachAndUnlockCachedTexture((GrTextureEntry*)fCache);
189 } else if (NULL != fTexture) {
190 GrAssert(!CACHE_LAYER_TEXTURES);
191 GrAssert(fRenderTarget == fTexture->asRenderTarget());
192 fTexture->unref();
193 } else if (NULL != fRenderTarget) {
194 fRenderTarget->unref();
195 }
196}
197
198void SkGpuDevice::bindDeviceToTargetHandle(intptr_t handle) {
199 if (fCache) {
200 GrAssert(NULL != fTexture);
201 GrAssert(fRenderTarget == fTexture->asRenderTarget());
202 // IMPORTANT: reattach the rendertarget/tex back to the cache.
203 fContext->reattachAndUnlockCachedTexture((GrTextureEntry*)fCache);
204 } else if (NULL != fTexture) {
205 GrAssert(!CACHE_LAYER_TEXTURES);
206 fTexture->unref();
207 } else if (NULL != fRenderTarget) {
208 fRenderTarget->unref();
209 }
210
211 fCache = NULL;
212 fTexture = NULL;
213 fRenderTarget = fContext->createPlatformRenderTarget(handle,
214 this->width(),
215 this->height());
216}
217
218intptr_t SkGpuDevice::getLayerTextureHandle() const {
219 if (fTexture) {
220 return fTexture->getTextureHandle();
221 } else {
222 return 0;
223 }
224}
225///////////////////////////////////////////////////////////////////////////////
226
227void SkGpuDevice::makeRenderTargetCurrent() {
228 fContext->setRenderTarget(fRenderTarget);
229 fContext->flush(true);
230 fNeedPrepareRenderTarget = true;
231}
232
233///////////////////////////////////////////////////////////////////////////////
234
235bool SkGpuDevice::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
236 SkIRect bounds;
237 bounds.set(0, 0, this->width(), this->height());
238 if (!bounds.intersect(srcRect)) {
239 return false;
240 }
241
242 const int w = bounds.width();
243 const int h = bounds.height();
244 SkBitmap tmp;
245 // note we explicitly specify our rowBytes to be snug (no gap between rows)
246 tmp.setConfig(SkBitmap::kARGB_8888_Config, w, h, w * 4);
247 if (!tmp.allocPixels()) {
248 return false;
249 }
250
251 SkAutoLockPixels alp(tmp);
252 fContext->setRenderTarget(fRenderTarget);
253 // we aren't setting the clip or matrix, so mark as dirty
254 // we don't need to set them for this call and don't have them anyway
255 fNeedPrepareRenderTarget = true;
256
257 if (!fContext->readPixels(bounds.fLeft, bounds.fTop,
258 bounds.width(), bounds.height(),
259 GrTexture::kRGBA_8888_PixelConfig,
260 tmp.getPixels())) {
261 return false;
262 }
263
264 tmp.swap(*bitmap);
265 return true;
266}
267
268void SkGpuDevice::writePixels(const SkBitmap& bitmap, int x, int y) {
269 SkAutoLockPixels alp(bitmap);
270 if (!bitmap.readyToDraw()) {
271 return;
272 }
273 GrTexture::PixelConfig config = SkGr::BitmapConfig2PixelConfig(bitmap.config(),
274 bitmap.isOpaque());
275 fContext->setRenderTarget(fRenderTarget);
276 // we aren't setting the clip or matrix, so mark as dirty
277 // we don't need to set them for this call and don't have them anyway
278 fNeedPrepareRenderTarget = true;
279
280 fContext->writePixels(x, y, bitmap.width(), bitmap.height(),
281 config, bitmap.getPixels(), bitmap.rowBytes());
282}
283
284///////////////////////////////////////////////////////////////////////////////
285
286static void convert_matrixclip(GrContext* context, const SkMatrix& matrix,
287 const SkRegion& clip) {
288 GrMatrix grmat;
289 SkGr::SkMatrix2GrMatrix(matrix, &grmat);
290 context->setViewMatrix(grmat);
291
292 SkGrClipIterator iter;
293 iter.reset(clip);
294 GrClip grc(&iter);
295 if (context->getClip() == grc) {
296 } else {
297 context->setClip(grc);
298 }
299}
300
301// call this ever each draw call, to ensure that the context reflects our state,
302// and not the state from some other canvas/device
303void SkGpuDevice::prepareRenderTarget(const SkDraw& draw) {
304 if (fNeedPrepareRenderTarget ||
305 fContext->currentRenderTarget() != fRenderTarget) {
306
307 fContext->setRenderTarget(fRenderTarget);
308 convert_matrixclip(fContext, *draw.fMatrix, *draw.fClip);
309 fNeedPrepareRenderTarget = false;
310 }
311}
312
313void SkGpuDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& clip) {
314 this->INHERITED::setMatrixClip(matrix, clip);
315
316 convert_matrixclip(fContext, matrix, clip);
317}
318
319void SkGpuDevice::gainFocus(SkCanvas* canvas, const SkMatrix& matrix,
320 const SkRegion& clip) {
321 fContext->setRenderTarget(fRenderTarget);
322
323 this->INHERITED::gainFocus(canvas, matrix, clip);
324
325 convert_matrixclip(fContext, matrix, clip);
326
327 if (fNeedClear) {
328 fContext->eraseColor(0x0);
329 fNeedClear = false;
330 }
331}
332
333bool SkGpuDevice::bindDeviceAsTexture(SkPoint* max) {
334 if (NULL != fTexture) {
335 fContext->setTexture(fTexture);
336 if (NULL != max) {
337 max->set(SkFixedToScalar((width() << 16) /
338 fTexture->allocWidth()),
339 SkFixedToScalar((height() << 16) /
340 fTexture->allocHeight()));
341 }
342 return true;
343 }
344 return false;
345}
346
347///////////////////////////////////////////////////////////////////////////////
348
349// must be in the same order as SkXfermode::Coeff in SkXfermode.h
350
351SkGpuDevice::AutoPaintShader::AutoPaintShader() {
352 fSuccess = false;
353 fTexture = NULL;
354}
355
356SkGpuDevice::AutoPaintShader::AutoPaintShader(SkGpuDevice* device,
357 const SkPaint& paint,
358 const SkMatrix& matrix) {
359 fSuccess = false;
360 fTexture = NULL;
361 this->init(device, paint, matrix);
362}
363
364void SkGpuDevice::AutoPaintShader::init(SkGpuDevice* device,
365 const SkPaint& paint,
366 const SkMatrix& ctm) {
367 fSuccess = true;
368 GrContext* ctx = device->context();
369 sk_gr_set_paint(ctx, paint); // should we pass true for justAlpha if we have a shader/texture?
370
371 SkShader* shader = paint.getShader();
372 if (NULL == shader) {
373 return;
374 }
375
376 if (!shader->setContext(device->accessBitmap(false), paint, ctm)) {
377 fSuccess = false;
378 return;
379 }
380
381 GrSamplerState::SampleMode sampleMode;
382 SkBitmap bitmap;
383 SkMatrix matrix;
384 SkShader::TileMode tileModes[2];
385 SkScalar twoPointParams[3];
386 SkShader::BitmapType bmptype = shader->asABitmap(&bitmap, &matrix,
387 tileModes, twoPointParams);
388
389 switch (bmptype) {
390 case SkShader::kNone_BitmapType:
391 SkDebugf("shader->asABitmap() == kNone_BitmapType");
392 return;
393 case SkShader::kDefault_BitmapType:
394 sampleMode = GrSamplerState::kNormal_SampleMode;
395 break;
396 case SkShader::kRadial_BitmapType:
397 sampleMode = GrSamplerState::kRadial_SampleMode;
398 break;
399 case SkShader::kSweep_BitmapType:
400 sampleMode = GrSamplerState::kSweep_SampleMode;
401 break;
402 case SkShader::kTwoPointRadial_BitmapType:
403 sampleMode = GrSamplerState::kRadial2_SampleMode;
404 break;
405 default:
406 SkASSERT("Unexpected return from asABitmap");
407 return;
408 }
409
410 bitmap.lockPixels();
411 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
412 return;
413 }
414
415 // see if we've already cached the bitmap from the shader
416 GrSamplerState samplerState(sk_tile_mode_to_grwrap(tileModes[0]),
417 sk_tile_mode_to_grwrap(tileModes[1]),
418 sampleMode,
419 paint.isFilterBitmap());
420
421 if (GrSamplerState::kRadial2_SampleMode == sampleMode) {
422 samplerState.setRadial2Params(twoPointParams[0],
423 twoPointParams[1],
424 twoPointParams[2] < 0);
425 }
426
427 GrTexture* texture = fCachedTexture.set(device, bitmap, samplerState);
428 if (NULL == texture) {
429 return;
430 }
431
432 // the lock has already called setTexture for us
433 ctx->setSamplerState(samplerState);
434
435 // since our texture coords will be in local space, we wack the texture
436 // matrix to map them back into 0...1 before we load it
437 SkMatrix localM;
438 if (shader->getLocalMatrix(&localM)) {
439 SkMatrix inverse;
440 if (localM.invert(&inverse)) {
441 matrix.preConcat(inverse);
442 }
443 }
444 if (SkShader::kDefault_BitmapType == bmptype) {
445 GrScalar sx = (GR_Scalar1 * texture->contentWidth()) /
446 (bitmap.width() * texture->allocWidth());
447 GrScalar sy = (GR_Scalar1 * texture->contentHeight()) /
448 (bitmap.height() * texture->allocHeight());
449 matrix.postScale(sx, sy);
450
451 } else if (SkShader::kRadial_BitmapType == bmptype) {
452 GrScalar s = (GR_Scalar1 * texture->contentWidth()) /
453 (bitmap.width() * texture->allocWidth());
454 matrix.postScale(s, s);
455 }
456 GrMatrix grmat;
457 SkGr::SkMatrix2GrMatrix(matrix, &grmat);
458 ctx->setTextureMatrix(grmat);
459
460 // since we're going to use a shader/texture, we don't want the color,
461 // just its alpha
462 ctx->setAlpha(paint.getAlpha());
463 // report that we have setup the texture
464 fSuccess = true;
465 fTexture = texture;
466}
467
468///////////////////////////////////////////////////////////////////////////////
469///////////////////////////////////////////////////////////////////////////////
470
471void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
472 CHECK_SHOULD_DRAW(draw);
473
474 AutoPaintShader shader(this, paint, *draw.fMatrix);
475 if (shader.failed()) {
476 return;
477 }
478 fContext->drawFull(shader.useTex());
479}
480
481// must be in SkCanvas::PointMode order
482static const GrGpu::PrimitiveType gPointMode2PrimtiveType[] = {
483 GrGpu::kPoints_PrimitiveType,
484 GrGpu::kLines_PrimitiveType,
485 GrGpu::kLineStrip_PrimitiveType
486};
487
488void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
489 size_t count, const SkPoint pts[], const SkPaint& paint) {
490 CHECK_SHOULD_DRAW(draw);
491
492 SkScalar width = paint.getStrokeWidth();
493 if (width < 0) {
494 return;
495 }
496
497 // we only handle hairlines here, else we let the SkDraw call our drawPath()
498 if (width > 0) {
499 draw.drawPoints(mode, count, pts, paint, true);
500 return;
501 }
502
503 AutoPaintShader shader(this, paint, *draw.fMatrix);
504 if (shader.failed()) {
505 return;
506 }
507
508 GrVertexLayout layout = shader.useTex() ?
509 GrDrawTarget::kPositionAsTexCoord_VertexLayoutBit :
510 0;
511#if SK_SCALAR_IS_GR_SCALAR
512 fContext->setVertexSourceToArray(pts, layout);
513 fContext->drawNonIndexed(gPointMode2PrimtiveType[mode], 0, count);
514#else
515 GrPoint* v;
516 fContext->reserveAndLockGeometry(layout, count, 0, (void**)&v, NULL);
517 for (int i = 0; i < count; ++i) {
518 v[i].set(SkScalarToGrScalar(pts[i].fX), SkScalarToGrScalar(pts[i].fY));
519 }
520 fContext->drawNonIndexed(gPointMode2PrimtiveType[mode], layout, 0, count);
521 fContext->releaseReservedGeometry();
522#endif
523
524}
525
526void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
527 const SkPaint& paint) {
528 CHECK_SHOULD_DRAW(draw);
529
530 bool doStroke = paint.getStyle() == SkPaint::kStroke_Style;
531 SkScalar width = paint.getStrokeWidth();
532
533 /*
534 We have special code for hairline strokes, miter-strokes, and fills.
535 Anything else we just call our path code. (i.e. non-miter thick stroke)
536 */
537 if (doStroke && width > 0 && paint.getStrokeJoin() != SkPaint::kMiter_Join) {
538 SkPath path;
539 path.addRect(rect);
540 this->drawPath(draw, path, paint, NULL, true);
541 return;
542 }
543
544 AutoPaintShader shader(this, paint, *draw.fMatrix);
545 if (shader.failed()) {
546 return;
547 }
548
549 fContext->drawRect(Sk2Gr(rect), shader.useTex(), doStroke ? width : -1);
550}
551
552void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& path,
553 const SkPaint& paint, const SkMatrix* prePathMatrix,
554 bool pathIsMutable) {
555 CHECK_SHOULD_DRAW(draw);
556
557 AutoPaintShader shader(this, paint, *draw.fMatrix);
558 if (shader.failed()) {
559 return;
560 }
561
562 const SkPath* pathPtr = &path;
563 SkPath tmpPath;
564
565 if (prePathMatrix) {
566 if (pathIsMutable) {
567 const_cast<SkPath*>(pathPtr)->transform(*prePathMatrix);
568 } else {
569 path.transform(*prePathMatrix, &tmpPath);
570 pathPtr = &tmpPath;
571 }
572 }
573
574 SkPath fillPath;
575 GrContext::PathFills fill = GrContext::kHairLine_PathFill;
576
577 if (paint.getFillPath(*pathPtr, &fillPath)) {
578 switch (fillPath.getFillType()) {
579 case SkPath::kWinding_FillType:
580 fill = GrContext::kWinding_PathFill;
581 break;
582 case SkPath::kEvenOdd_FillType:
583 fill = GrContext::kEvenOdd_PathFill;
584 break;
585 case SkPath::kInverseWinding_FillType:
586 fill = GrContext::kInverseWinding_PathFill;
587 break;
588 case SkPath::kInverseEvenOdd_FillType:
589 fill = GrContext::kInverseEvenOdd_PathFill;
590 break;
591 default:
592 SkDebugf("Unsupported path fill type");
593 return;
594 }
595 }
596
597 SkGrPathIter iter(fillPath);
598 fContext->drawPath(&iter, fill, shader.useTex());
599}
600
601/*
602 * This value must not exceed the GPU's texture dimension limit, but it can
603 * be smaller, if that helps avoid very large single textures hurting the
604 * cache.
605 */
606#define MAX_TEXTURE_DIM 512
607
608void SkGpuDevice::drawBitmap(const SkDraw& draw,
609 const SkBitmap& bitmap,
610 const SkIRect* srcRectPtr,
611 const SkMatrix& m,
612 const SkPaint& paint) {
613 CHECK_SHOULD_DRAW(draw);
614
615 SkIRect srcRect;
616 if (NULL == srcRectPtr) {
617 srcRect.set(0, 0, bitmap.width(), bitmap.height());
618 } else {
619 srcRect = *srcRectPtr;
620 }
621
622 if (bitmap.getTexture() || (bitmap.width() <= MAX_TEXTURE_DIM &&
623 bitmap.height() <= MAX_TEXTURE_DIM)) {
624 // take the fast case
625 this->internalDrawBitmap(draw, bitmap, srcRect, m, paint);
626 return;
627 }
628
629 // undo the translate done by SkCanvas
630 int DX = SkMax32(0, srcRect.fLeft);
631 int DY = SkMax32(0, srcRect.fTop);
632 // compute clip bounds in local coordinates
633 SkIRect clipRect;
634 {
635 SkRect r;
636 r.set(draw.fClip->getBounds());
637 SkMatrix matrix, inverse;
638 matrix.setConcat(*draw.fMatrix, m);
639 if (!matrix.invert(&inverse)) {
640 return;
641 }
642 inverse.mapRect(&r);
643 r.roundOut(&clipRect);
644 // apply the canvas' translate to our local clip
645 clipRect.offset(DX, DY);
646 }
647
648 int nx = bitmap.width() / MAX_TEXTURE_DIM;
649 int ny = bitmap.height() / MAX_TEXTURE_DIM;
650 for (int x = 0; x <= nx; x++) {
651 for (int y = 0; y <= ny; y++) {
652 SkIRect tileR;
653 tileR.set(x * MAX_TEXTURE_DIM, y * MAX_TEXTURE_DIM,
654 (x + 1) * MAX_TEXTURE_DIM, (y + 1) * MAX_TEXTURE_DIM);
655 if (!SkIRect::Intersects(tileR, clipRect)) {
656 continue;
657 }
658
659 SkIRect srcR = tileR;
660 if (!srcR.intersect(srcRect)) {
661 continue;
662 }
663
664 SkBitmap tmpB;
665 if (bitmap.extractSubset(&tmpB, tileR)) {
666 // now offset it to make it "local" to our tmp bitmap
667 srcR.offset(-tileR.fLeft, -tileR.fTop);
668
669 SkMatrix tmpM(m);
670 {
671 int dx = tileR.fLeft - DX + SkMax32(0, srcR.fLeft);
672 int dy = tileR.fTop - DY + SkMax32(0, srcR.fTop);
673 tmpM.preTranslate(SkIntToScalar(dx), SkIntToScalar(dy));
674 }
675 this->internalDrawBitmap(draw, tmpB, srcR, tmpM, paint);
676 }
677 }
678 }
679}
680
681/*
682 * This is called by drawBitmap(), which has to handle images that may be too
683 * large to be represented by a single texture.
684 *
685 * internalDrawBitmap assumes that the specified bitmap will fit in a texture.
686 */
687void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
688 const SkBitmap& bitmap,
689 const SkIRect& srcRect,
690 const SkMatrix& m,
691 const SkPaint& paint) {
692 SkASSERT(bitmap.width() <= MAX_TEXTURE_DIM &&
693 bitmap.height() <= MAX_TEXTURE_DIM);
694
695 SkAutoLockPixels alp(bitmap);
696 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
697 return;
698 }
699
700 GrSamplerState sampler(paint.isFilterBitmap()); // defaults to clamp
701 // the lock has already called setTexture for us
702 fContext->setSamplerState(sampler);
703
704 GrTexture* texture;
705 SkAutoCachedTexture act(this, bitmap, sampler, &texture);
706 if (NULL == texture) {
707 return;
708 }
709
710 GrVertexLayout layout = GrDrawTarget::kSeparateTexCoord_VertexLayoutBit;
711
712 GrPoint* vertex;
713 if (!fContext->reserveAndLockGeometry(layout, 4,
714 0, (void**)&vertex, NULL)) {
715 return;
716 }
717
718 {
719 GrMatrix grmat;
720 SkGr::SkMatrix2GrMatrix(m, &grmat);
721 vertex[0].setIRectFan(0, 0, srcRect.width(), srcRect.height(),
722 2*sizeof(GrPoint));
723 grmat.mapPointsWithStride(vertex, 2*sizeof(GrPoint), 4);
724 }
725
726 SkScalar left = SkFixedToScalar((srcRect.fLeft << 16) /
727 texture->allocWidth());
728 SkScalar right = SkFixedToScalar((srcRect.fRight << 16) /
729 texture->allocWidth());
730 SkScalar top = SkFixedToScalar((srcRect.fTop << 16) /
731 texture->allocHeight());
732 SkScalar bottom = SkFixedToScalar((srcRect.fBottom << 16) /
733 texture->allocHeight());
734 vertex[1].setRectFan(left, top, right, bottom, 2*sizeof(GrPoint));
735
736 fContext->setTextureMatrix(GrMatrix::I());
737 // now draw the mesh
738 sk_gr_set_paint(fContext, paint, true);
739 fContext->drawNonIndexed(GrGpu::kTriangleFan_PrimitiveType, 0, 4);
740 fContext->releaseReservedGeometry();
741}
742
743static void gl_drawSprite(GrContext* ctx,
744 int x, int y, int w, int h, const SkPoint& max,
745 const SkPaint& paint) {
746 GrAutoViewMatrix avm(ctx, GrMatrix::I());
747
748 ctx->setSamplerState(GrSamplerState::ClampNoFilter());
749 ctx->setTextureMatrix(GrMatrix::I());
750
751 GrPoint* vertex;
752 GrVertexLayout layout = GrGpu::kSeparateTexCoord_VertexLayoutBit;
753 if (!ctx->reserveAndLockGeometry(layout, 4, 0, (void**)&vertex, NULL)) {
754 return;
755 }
756
757 vertex[1].setRectFan(0, 0, max.fX, max.fY, 2*sizeof(GrPoint));
758
759 vertex[0].setIRectFan(x, y, x + w, y + h, 2*sizeof(GrPoint));
760
761 sk_gr_set_paint(ctx, paint, true);
762 // should look to use glDrawTexi() has we do for text...
763 ctx->drawNonIndexed(GrGpu::kTriangleFan_PrimitiveType, 0, 4);
764 ctx->releaseReservedGeometry();
765}
766
767void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
768 int left, int top, const SkPaint& paint) {
769 CHECK_SHOULD_DRAW(draw);
770
771 SkAutoLockPixels alp(bitmap);
772 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
773 return;
774 }
775
776 SkPoint max;
777 GrTexture* texture;
778 SkAutoCachedTexture act(this, bitmap, GrSamplerState::ClampNoFilter(),
779 &texture);
780
781 max.set(SkFixedToScalar((texture->contentWidth() << 16) /
782 texture->allocWidth()),
783 SkFixedToScalar((texture->contentHeight() << 16) /
784 texture->allocHeight()));
785 gl_drawSprite(fContext, left, top, bitmap.width(), bitmap.height(), max, paint);
786}
787
788void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
789 int x, int y, const SkPaint& paint) {
790 CHECK_SHOULD_DRAW(draw);
791
792 SkPoint max;
793 if (((SkGpuDevice*)dev)->bindDeviceAsTexture(&max)) {
794 const SkBitmap& bm = dev->accessBitmap(false);
795 int w = bm.width();
796 int h = bm.height();
797 gl_drawSprite(fContext, x, y, w, h, max, paint);
798 }
799}
800
801///////////////////////////////////////////////////////////////////////////////
802
803// must be in SkCanvas::VertexMode order
804static const GrGpu::PrimitiveType gVertexMode2PrimitiveType[] = {
805 GrGpu::kTriangles_PrimitiveType,
806 GrGpu::kTriangleStrip_PrimitiveType,
807 GrGpu::kTriangleFan_PrimitiveType,
808};
809
810void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
811 int vertexCount, const SkPoint vertices[],
812 const SkPoint texs[], const SkColor colors[],
813 SkXfermode* xmode,
814 const uint16_t indices[], int indexCount,
815 const SkPaint& paint) {
816 CHECK_SHOULD_DRAW(draw);
817
818 sk_gr_set_paint(fContext, paint);
819
820 TexCache* cache = NULL;
821
822 bool useTexture = false;
823
824 AutoPaintShader autoShader;
825
826 if (texs) {
827 autoShader.init(this, paint, *draw.fMatrix);
828
829 if (autoShader.failed()) {
830 return;
831 }
832 useTexture = autoShader.useTex();
833 }
834
835 bool releaseVerts = false;
836 GrVertexLayout layout = 0;
837 if (useTexture) {
838 layout |= GrDrawTarget::kSeparateTexCoord_VertexLayoutBit;
839 }
840 if (NULL != colors) {
841 layout |= GrDrawTarget::kColor_VertexLayoutBit;
842 }
843
844 #if SK_SCALAR_IS_GR_SCALAR
845 if (!layout) {
846 fContext->setVertexSourceToArray(vertices, layout);
847 } else
848 #endif
849 {
850 void* verts;
851 releaseVerts = true;
852 if (!fContext->reserveAndLockGeometry(layout, vertexCount, 0,
853 &verts, NULL)) {
854 return;
855 }
856 int texOffset, colorOffset;
857 uint32_t stride = GrDrawTarget::VertexSizeAndOffsets(layout,
858 &texOffset,
859 &colorOffset);
860 for (int i = 0; i < vertexCount; ++i) {
861 GrPoint* p = (GrPoint*)((intptr_t)verts + i * stride);
862 p->set(SkScalarToGrScalar(vertices[i].fX),
863 SkScalarToGrScalar(vertices[i].fY));
864 if (texOffset > 0) {
865 GrPoint* t = (GrPoint*)((intptr_t)p + texOffset);
866 t->set(SkScalarToGrScalar(texs[i].fX),
867 SkScalarToGrScalar(texs[i].fY));
868 }
869 if (colorOffset > 0) {
870 uint32_t* color = (uint32_t*) ((intptr_t)p + colorOffset);
871 *color = SkGr::SkColor2GrColor(colors[i]);
872 }
873 }
874 }
875 if (indices) {
876 fContext->setIndexSourceToArray(indices);
877 fContext->drawIndexed(gVertexMode2PrimitiveType[vmode], 0, 0,
878 vertexCount, indexCount);
879 } else {
880 fContext->drawNonIndexed(gVertexMode2PrimitiveType[vmode],
881 0, vertexCount);
882 }
883 if (cache) {
884 this->unlockCachedTexture(cache);
885 }
886 if (releaseVerts) {
887 fContext->releaseReservedGeometry();
888 }
889}
890
891///////////////////////////////////////////////////////////////////////////////
892
893static void GlyphCacheAuxProc(void* data) {
894 delete (GrFontScaler*)data;
895}
896
897static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) {
898 void* auxData;
899 GrFontScaler* scaler = NULL;
900 if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
901 scaler = (GrFontScaler*)auxData;
902 }
903 if (NULL == scaler) {
904 scaler = new SkGrFontScaler(cache);
905 cache->setAuxProc(GlyphCacheAuxProc, scaler);
906 }
907 return scaler;
908}
909
910static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
911 SkFixed fx, SkFixed fy,
912 const SkGlyph& glyph) {
913 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
914
915 GrSkDrawProcs* procs = (GrSkDrawProcs*)state.fDraw->fProcs;
916
917 if (NULL == procs->fFontScaler) {
918 procs->fFontScaler = get_gr_font_scaler(state.fCache);
919 }
920 procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0),
921 SkIntToFixed(SkFixedFloor(fx)), fy,
922 procs->fFontScaler);
923}
924
925SkDrawProcs* SkGpuDevice::initDrawForText(const SkPaint& paint,
926 GrTextContext* context) {
927
928 // deferred allocation
929 if (NULL == fDrawProcs) {
930 fDrawProcs = new GrSkDrawProcs;
931 fDrawProcs->fD1GProc = SkGPU_Draw1Glyph;
932 fDrawProcs->fContext = fContext;
933 }
934
935 // init our (and GL's) state
936 fDrawProcs->fTextContext = context;
937 fDrawProcs->fFontScaler = NULL;
938 return fDrawProcs;
939}
940
941void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
942 size_t byteLength, SkScalar x, SkScalar y,
943 const SkPaint& paint) {
944 CHECK_SHOULD_DRAW(draw);
945
946 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
947 // this guy will just call our drawPath()
948 draw.drawText((const char*)text, byteLength, x, y, paint);
949 } else {
950 SkAutoExtMatrix aem(draw.fExtMatrix);
951 SkDraw myDraw(draw);
952 sk_gr_set_paint(fContext, paint);
953 GrTextContext context(fContext, aem.extMatrix());
954 myDraw.fProcs = this->initDrawForText(paint, &context);
955 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
956 }
957}
958
959void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
960 size_t byteLength, const SkScalar pos[],
961 SkScalar constY, int scalarsPerPos,
962 const SkPaint& paint) {
963 CHECK_SHOULD_DRAW(draw);
964
965 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
966 // this guy will just call our drawPath()
967 draw.drawPosText((const char*)text, byteLength, pos, constY,
968 scalarsPerPos, paint);
969 } else {
970 SkAutoExtMatrix aem(draw.fExtMatrix);
971 SkDraw myDraw(draw);
972 sk_gr_set_paint(fContext, paint);
973 GrTextContext context(fContext, aem.extMatrix());
974 myDraw.fProcs = this->initDrawForText(paint, &context);
975 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
976 scalarsPerPos, paint);
977 }
978}
979
980void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
981 size_t len, const SkPath& path,
982 const SkMatrix* m, const SkPaint& paint) {
983 CHECK_SHOULD_DRAW(draw);
984
985 SkASSERT(draw.fDevice == this);
986 draw.drawTextOnPath((const char*)text, len, path, m, paint);
987}
988
989///////////////////////////////////////////////////////////////////////////////
990
991SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
992 const GrSamplerState& sampler,
993 GrTexture** texture,
994 bool forDeviceRenderTarget) {
995 GrContext* ctx = this->context();
996 uint32_t p0, p1;
997 if (forDeviceRenderTarget) {
998 p0 = p1 = -1;
999 } else {
1000 p0 = bitmap.getGenerationID();
1001 p1 = bitmap.pixelRefOffset();
1002 }
1003
1004 GrTexture* newTexture = NULL;
1005 GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
1006 GrTextureEntry* entry = ctx->findAndLockTexture(&key, sampler);
1007
1008 if (NULL == entry) {
1009
1010 if (forDeviceRenderTarget) {
1011 const GrGpu::TextureDesc desc = {
1012 GrGpu::kRenderTarget_TextureFlag,
1013 GrGpu::kNone_AALevel,
1014 bitmap.width(),
1015 bitmap.height(),
1016 SkGr::Bitmap2PixelConfig(bitmap)
1017 };
1018 entry = ctx->createAndLockTexture(&key, sampler, desc, NULL, 0);
1019
1020 } else {
1021 entry = sk_gr_create_bitmap_texture(ctx, &key, sampler, bitmap);
1022 }
1023 if (NULL == entry) {
1024 GrPrintf("---- failed to create texture for cache [%d %d]\n",
1025 bitmap.width(), bitmap.height());
1026 }
1027 }
1028
1029 if (NULL != entry) {
1030 newTexture = entry->texture();
1031 ctx->setTexture(newTexture);
1032 if (texture) {
1033 *texture = newTexture;
1034 }
1035 // IMPORTANT: We can't allow another SkGpuDevice to get this
1036 // cache entry until this one is destroyed!
1037 if (forDeviceRenderTarget) {
1038 ctx->detachCachedTexture(entry);
1039 }
1040 }
1041 return (TexCache*)entry;
1042}
1043
1044void SkGpuDevice::unlockCachedTexture(TexCache* cache) {
1045 this->context()->unlockTexture((GrTextureEntry*)cache);
1046}
1047
1048