blob: 2d5634c29f7d14f5d081ba39bec74a95ac4fcc26 [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);
reed@google.com72cf4922011-01-04 19:58:20 +0000517 for (size_t i = 0; i < count; ++i) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000518 v[i].set(SkScalarToGrScalar(pts[i].fX), SkScalarToGrScalar(pts[i].fY));
519 }
reed@google.com72cf4922011-01-04 19:58:20 +0000520 fContext->drawNonIndexed(gPointMode2PrimtiveType[mode], 0, count);
reed@google.comac10a2d2010-12-22 21:39:39 +0000521 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,
reed@google.com1fcd51e2011-01-05 15:50:27 +0000714 0, GrTCast<void**>(&vertex), NULL)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000715 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;
reed@google.com1fcd51e2011-01-05 15:50:27 +0000753 if (!ctx->reserveAndLockGeometry(layout, 4, 0,
754 GrTCast<void**>(&vertex), NULL)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000755 return;
756 }
757
758 vertex[1].setRectFan(0, 0, max.fX, max.fY, 2*sizeof(GrPoint));
759
760 vertex[0].setIRectFan(x, y, x + w, y + h, 2*sizeof(GrPoint));
761
762 sk_gr_set_paint(ctx, paint, true);
763 // should look to use glDrawTexi() has we do for text...
764 ctx->drawNonIndexed(GrGpu::kTriangleFan_PrimitiveType, 0, 4);
765 ctx->releaseReservedGeometry();
766}
767
768void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
769 int left, int top, const SkPaint& paint) {
770 CHECK_SHOULD_DRAW(draw);
771
772 SkAutoLockPixels alp(bitmap);
773 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
774 return;
775 }
776
777 SkPoint max;
778 GrTexture* texture;
779 SkAutoCachedTexture act(this, bitmap, GrSamplerState::ClampNoFilter(),
780 &texture);
781
782 max.set(SkFixedToScalar((texture->contentWidth() << 16) /
783 texture->allocWidth()),
784 SkFixedToScalar((texture->contentHeight() << 16) /
785 texture->allocHeight()));
786 gl_drawSprite(fContext, left, top, bitmap.width(), bitmap.height(), max, paint);
787}
788
789void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
790 int x, int y, const SkPaint& paint) {
791 CHECK_SHOULD_DRAW(draw);
792
793 SkPoint max;
794 if (((SkGpuDevice*)dev)->bindDeviceAsTexture(&max)) {
795 const SkBitmap& bm = dev->accessBitmap(false);
796 int w = bm.width();
797 int h = bm.height();
798 gl_drawSprite(fContext, x, y, w, h, max, paint);
799 }
800}
801
802///////////////////////////////////////////////////////////////////////////////
803
804// must be in SkCanvas::VertexMode order
805static const GrGpu::PrimitiveType gVertexMode2PrimitiveType[] = {
806 GrGpu::kTriangles_PrimitiveType,
807 GrGpu::kTriangleStrip_PrimitiveType,
808 GrGpu::kTriangleFan_PrimitiveType,
809};
810
811void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
812 int vertexCount, const SkPoint vertices[],
813 const SkPoint texs[], const SkColor colors[],
814 SkXfermode* xmode,
815 const uint16_t indices[], int indexCount,
816 const SkPaint& paint) {
817 CHECK_SHOULD_DRAW(draw);
818
819 sk_gr_set_paint(fContext, paint);
820
821 TexCache* cache = NULL;
822
823 bool useTexture = false;
824
825 AutoPaintShader autoShader;
826
827 if (texs) {
828 autoShader.init(this, paint, *draw.fMatrix);
829
830 if (autoShader.failed()) {
831 return;
832 }
833 useTexture = autoShader.useTex();
834 }
835
836 bool releaseVerts = false;
837 GrVertexLayout layout = 0;
838 if (useTexture) {
839 layout |= GrDrawTarget::kSeparateTexCoord_VertexLayoutBit;
840 }
841 if (NULL != colors) {
842 layout |= GrDrawTarget::kColor_VertexLayoutBit;
843 }
844
845 #if SK_SCALAR_IS_GR_SCALAR
846 if (!layout) {
847 fContext->setVertexSourceToArray(vertices, layout);
848 } else
849 #endif
850 {
851 void* verts;
852 releaseVerts = true;
853 if (!fContext->reserveAndLockGeometry(layout, vertexCount, 0,
854 &verts, NULL)) {
855 return;
856 }
857 int texOffset, colorOffset;
858 uint32_t stride = GrDrawTarget::VertexSizeAndOffsets(layout,
859 &texOffset,
860 &colorOffset);
861 for (int i = 0; i < vertexCount; ++i) {
862 GrPoint* p = (GrPoint*)((intptr_t)verts + i * stride);
863 p->set(SkScalarToGrScalar(vertices[i].fX),
864 SkScalarToGrScalar(vertices[i].fY));
865 if (texOffset > 0) {
866 GrPoint* t = (GrPoint*)((intptr_t)p + texOffset);
867 t->set(SkScalarToGrScalar(texs[i].fX),
868 SkScalarToGrScalar(texs[i].fY));
869 }
870 if (colorOffset > 0) {
871 uint32_t* color = (uint32_t*) ((intptr_t)p + colorOffset);
872 *color = SkGr::SkColor2GrColor(colors[i]);
873 }
874 }
875 }
876 if (indices) {
877 fContext->setIndexSourceToArray(indices);
878 fContext->drawIndexed(gVertexMode2PrimitiveType[vmode], 0, 0,
879 vertexCount, indexCount);
880 } else {
881 fContext->drawNonIndexed(gVertexMode2PrimitiveType[vmode],
882 0, vertexCount);
883 }
884 if (cache) {
885 this->unlockCachedTexture(cache);
886 }
887 if (releaseVerts) {
888 fContext->releaseReservedGeometry();
889 }
890}
891
892///////////////////////////////////////////////////////////////////////////////
893
894static void GlyphCacheAuxProc(void* data) {
895 delete (GrFontScaler*)data;
896}
897
898static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) {
899 void* auxData;
900 GrFontScaler* scaler = NULL;
901 if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
902 scaler = (GrFontScaler*)auxData;
903 }
904 if (NULL == scaler) {
905 scaler = new SkGrFontScaler(cache);
906 cache->setAuxProc(GlyphCacheAuxProc, scaler);
907 }
908 return scaler;
909}
910
911static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
912 SkFixed fx, SkFixed fy,
913 const SkGlyph& glyph) {
914 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
915
916 GrSkDrawProcs* procs = (GrSkDrawProcs*)state.fDraw->fProcs;
917
918 if (NULL == procs->fFontScaler) {
919 procs->fFontScaler = get_gr_font_scaler(state.fCache);
920 }
921 procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0),
922 SkIntToFixed(SkFixedFloor(fx)), fy,
923 procs->fFontScaler);
924}
925
926SkDrawProcs* SkGpuDevice::initDrawForText(const SkPaint& paint,
927 GrTextContext* context) {
928
929 // deferred allocation
930 if (NULL == fDrawProcs) {
931 fDrawProcs = new GrSkDrawProcs;
932 fDrawProcs->fD1GProc = SkGPU_Draw1Glyph;
933 fDrawProcs->fContext = fContext;
934 }
935
936 // init our (and GL's) state
937 fDrawProcs->fTextContext = context;
938 fDrawProcs->fFontScaler = NULL;
939 return fDrawProcs;
940}
941
942void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
943 size_t byteLength, SkScalar x, SkScalar y,
944 const SkPaint& paint) {
945 CHECK_SHOULD_DRAW(draw);
946
947 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
948 // this guy will just call our drawPath()
949 draw.drawText((const char*)text, byteLength, x, y, paint);
950 } else {
951 SkAutoExtMatrix aem(draw.fExtMatrix);
952 SkDraw myDraw(draw);
953 sk_gr_set_paint(fContext, paint);
954 GrTextContext context(fContext, aem.extMatrix());
955 myDraw.fProcs = this->initDrawForText(paint, &context);
956 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
957 }
958}
959
960void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
961 size_t byteLength, const SkScalar pos[],
962 SkScalar constY, int scalarsPerPos,
963 const SkPaint& paint) {
964 CHECK_SHOULD_DRAW(draw);
965
966 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
967 // this guy will just call our drawPath()
968 draw.drawPosText((const char*)text, byteLength, pos, constY,
969 scalarsPerPos, paint);
970 } else {
971 SkAutoExtMatrix aem(draw.fExtMatrix);
972 SkDraw myDraw(draw);
973 sk_gr_set_paint(fContext, paint);
974 GrTextContext context(fContext, aem.extMatrix());
975 myDraw.fProcs = this->initDrawForText(paint, &context);
976 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
977 scalarsPerPos, paint);
978 }
979}
980
981void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
982 size_t len, const SkPath& path,
983 const SkMatrix* m, const SkPaint& paint) {
984 CHECK_SHOULD_DRAW(draw);
985
986 SkASSERT(draw.fDevice == this);
987 draw.drawTextOnPath((const char*)text, len, path, m, paint);
988}
989
990///////////////////////////////////////////////////////////////////////////////
991
992SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
993 const GrSamplerState& sampler,
994 GrTexture** texture,
995 bool forDeviceRenderTarget) {
996 GrContext* ctx = this->context();
997 uint32_t p0, p1;
998 if (forDeviceRenderTarget) {
999 p0 = p1 = -1;
1000 } else {
1001 p0 = bitmap.getGenerationID();
1002 p1 = bitmap.pixelRefOffset();
1003 }
1004
1005 GrTexture* newTexture = NULL;
1006 GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
1007 GrTextureEntry* entry = ctx->findAndLockTexture(&key, sampler);
1008
1009 if (NULL == entry) {
1010
1011 if (forDeviceRenderTarget) {
1012 const GrGpu::TextureDesc desc = {
1013 GrGpu::kRenderTarget_TextureFlag,
1014 GrGpu::kNone_AALevel,
1015 bitmap.width(),
1016 bitmap.height(),
1017 SkGr::Bitmap2PixelConfig(bitmap)
1018 };
1019 entry = ctx->createAndLockTexture(&key, sampler, desc, NULL, 0);
1020
1021 } else {
1022 entry = sk_gr_create_bitmap_texture(ctx, &key, sampler, bitmap);
1023 }
1024 if (NULL == entry) {
1025 GrPrintf("---- failed to create texture for cache [%d %d]\n",
1026 bitmap.width(), bitmap.height());
1027 }
1028 }
1029
1030 if (NULL != entry) {
1031 newTexture = entry->texture();
1032 ctx->setTexture(newTexture);
1033 if (texture) {
1034 *texture = newTexture;
1035 }
1036 // IMPORTANT: We can't allow another SkGpuDevice to get this
1037 // cache entry until this one is destroyed!
1038 if (forDeviceRenderTarget) {
1039 ctx->detachCachedTexture(entry);
1040 }
1041 }
1042 return (TexCache*)entry;
1043}
1044
1045void SkGpuDevice::unlockCachedTexture(TexCache* cache) {
1046 this->context()->unlockTexture((GrTextureEntry*)cache);
1047}
1048
1049