1 #include "SkGLDevice.h"
2 #include "SkGL.h"
3 #include "SkDrawProcs.h"
4 #include "SkRegion.h"
5 #include "SkThread.h"
6
TRACE_DRAW(const char func[],SkGLDevice * device,const SkDraw & draw)7 static void TRACE_DRAW(const char func[], SkGLDevice* device,
8 const SkDraw& draw) {
9 // SkDebugf("--- <%s> %p %p\n", func, canvas, draw.fDevice);
10 }
11
12 struct SkGLDrawProcs : public SkDrawProcs {
13 public:
initSkGLDrawProcs14 void init(const SkRegion* clip, int height) {
15 fCurrQuad = 0;
16 fCurrTexture = 0;
17 fClip = clip;
18 fViewportHeight = height;
19
20 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
21 glTexCoordPointer(2, SK_TextGLType, 0, fTexs);
22 glDisableClientState(GL_COLOR_ARRAY);
23 glVertexPointer(2, SK_TextGLType, 0, fVerts);
24 }
25
textureSkGLDrawProcs26 GLenum texture() const { return fCurrTexture; }
27
flushSkGLDrawProcs28 void flush() {
29 if (fCurrQuad && fCurrTexture) {
30 this->drawQuads();
31 }
32 fCurrQuad = 0;
33 }
34
addQuadSkGLDrawProcs35 void addQuad(GLuint texture, int x, int y, const SkGlyph& glyph,
36 SkFixed left, SkFixed right, SkFixed bottom) {
37 SkASSERT((size_t)fCurrQuad <= SK_ARRAY_COUNT(fVerts));
38
39 if (fCurrTexture != texture || fCurrQuad == SK_ARRAY_COUNT(fVerts)) {
40 if (fCurrQuad && fCurrTexture) {
41 this->drawQuads();
42 }
43 fCurrQuad = 0;
44 fCurrTexture = texture;
45 }
46
47 fVerts[fCurrQuad].setIRectFan(x, y,
48 x + glyph.fWidth, y + glyph.fHeight);
49 fTexs[fCurrQuad].setXRectFan(left, 0, right, bottom);
50 fCurrQuad += 4;
51 }
52
53 void drawQuads();
54
55 private:
56 enum {
57 MAX_QUADS = 32
58 };
59
60 SkGLTextVertex fVerts[MAX_QUADS * 4];
61 SkGLTextVertex fTexs[MAX_QUADS * 4];
62
63 // these are initialized in setupForText
64 GLuint fCurrTexture;
65 int fCurrQuad;
66 int fViewportHeight;
67 const SkRegion* fClip;
68 };
69
70 ///////////////////////////////////////////////////////////////////////////////
71
SkGLDevice(const SkBitmap & bitmap,bool offscreen)72 SkGLDevice::SkGLDevice(const SkBitmap& bitmap, bool offscreen)
73 : SkDevice(bitmap), fClipIter(bitmap.height()) {
74 fDrawProcs = NULL;
75 }
76
~SkGLDevice()77 SkGLDevice::~SkGLDevice() {
78 if (fDrawProcs) {
79 SkDELETE(fDrawProcs);
80 }
81 }
82
setMatrixClip(const SkMatrix & matrix,const SkRegion & clip)83 void SkGLDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& clip) {
84 this->INHERITED::setMatrixClip(matrix, clip);
85
86 fGLMatrix.set(matrix);
87 fMatrix = matrix;
88 fClip = clip;
89 fDirty = true;
90 }
91
bindDeviceAsTexture()92 SkGLDevice::TexOrientation SkGLDevice::bindDeviceAsTexture() {
93 return kNo_TexOrientation;
94 }
95
gainFocus(SkCanvas * canvas)96 void SkGLDevice::gainFocus(SkCanvas* canvas) {
97 this->INHERITED::gainFocus(canvas);
98
99 const int w = this->width();
100 const int h = this->height();
101 glViewport(0, 0, w, h);
102 glMatrixMode(GL_PROJECTION);
103 glLoadIdentity();
104 SkGL::Ortho(0, w, h, 0, -1, 1);
105 glMatrixMode(GL_MODELVIEW);
106 fDirty = true;
107 }
108
updateMatrixClip()109 SkGLClipIter* SkGLDevice::updateMatrixClip() {
110 bool useIter = false;
111
112 // first handle the clip
113 if (fDirty || !fClip.isRect()) {
114 fClipIter.reset(fClip);
115 useIter = true;
116 } else if (fDirty) {
117 // no iter means caller is not respecting complex clips :(
118 SkGL::Scissor(fClip.getBounds(), this->height());
119 }
120 // else we're just a rect, and we've already call scissor
121
122 // now handle the matrix
123 if (fDirty) {
124 MAKE_GL(glLoadMatrix)(fGLMatrix.fMat);
125 #if 0
126 SkDebugf("--- gldevice update matrix %p %p\n", this, fFBO);
127 for (int y = 0; y < 4; y++) {
128 SkDebugf(" [ ");
129 for (int x = 0; x < 4; x++) {
130 SkDebugf("%g ", fGLMatrix.fMat[y*4 + x]);
131 }
132 SkDebugf("]\n");
133 }
134 #endif
135 fDirty = false;
136 }
137
138 return useIter ? &fClipIter : NULL;
139 }
140
141 ///////////////////////////////////////////////////////////////////////////////
142
143 // must be in the same order as SkXfermode::Coeff in SkXfermode.h
AutoPaintShader(SkGLDevice * device,const SkPaint & paint)144 SkGLDevice::AutoPaintShader::AutoPaintShader(SkGLDevice* device,
145 const SkPaint& paint) {
146 fDevice = device;
147 fTexCache = device->setupGLPaintShader(paint);
148 }
149
~AutoPaintShader()150 SkGLDevice::AutoPaintShader::~AutoPaintShader() {
151 if (fTexCache) {
152 SkGLDevice::UnlockTexCache(fTexCache);
153 }
154 }
155
setupGLPaintShader(const SkPaint & paint)156 SkGLDevice::TexCache* SkGLDevice::setupGLPaintShader(const SkPaint& paint) {
157 SkGL::SetPaint(paint);
158
159 SkShader* shader = paint.getShader();
160 if (NULL == shader) {
161 return NULL;
162 }
163
164 if (!shader->setContext(this->accessBitmap(false), paint, this->matrix())) {
165 return NULL;
166 }
167
168 SkBitmap bitmap;
169 SkMatrix matrix;
170 SkShader::TileMode tileModes[2];
171 if (!shader->asABitmap(&bitmap, &matrix, tileModes)) {
172 SkGL_unimpl("shader->asABitmap() == false");
173 return NULL;
174 }
175
176 bitmap.lockPixels();
177 if (!bitmap.readyToDraw()) {
178 return NULL;
179 }
180
181 // see if we've already cached the bitmap from the shader
182 SkPoint max;
183 GLuint name;
184 TexCache* cache = SkGLDevice::LockTexCache(bitmap, &name, &max);
185 // the lock has already called glBindTexture for us
186 SkGL::SetTexParams(paint.isFilterBitmap(), tileModes[0], tileModes[1]);
187
188 // since our texture coords will be in local space, we wack the texture
189 // matrix to map them back into 0...1 before we load it
190 SkMatrix localM;
191 if (shader->getLocalMatrix(&localM)) {
192 SkMatrix inverse;
193 if (localM.invert(&inverse)) {
194 matrix.preConcat(inverse);
195 }
196 }
197
198 matrix.postScale(max.fX / bitmap.width(), max.fY / bitmap.height());
199 glMatrixMode(GL_TEXTURE);
200 SkGL::LoadMatrix(matrix);
201 glMatrixMode(GL_MODELVIEW);
202
203 // since we're going to use a shader/texture, we don't want the color,
204 // just its alpha
205 SkGL::SetAlpha(paint.getAlpha());
206 // report that we have setup the texture
207 return cache;
208 }
209
210 ///////////////////////////////////////////////////////////////////////////////
211 ///////////////////////////////////////////////////////////////////////////////
212
drawPaint(const SkDraw & draw,const SkPaint & paint)213 void SkGLDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
214 TRACE_DRAW("coreDrawPaint", this, draw);
215
216 AutoPaintShader shader(this, paint);
217 SkGLVertex vertex[4];
218 const SkGLVertex* texs = shader.useTex() ? vertex : NULL;
219
220 // set vert to be big enough to fill the space, but not super-huge, to we
221 // don't overflow fixed-point implementations
222 {
223 SkRect r;
224 r.set(this->clip().getBounds());
225 SkMatrix inverse;
226 if (draw.fMatrix->invert(&inverse)) {
227 inverse.mapRect(&r);
228 }
229 vertex->setRectFan(r);
230 }
231
232 SkGL::DrawVertices(4, GL_TRIANGLE_FAN, vertex, texs, NULL, NULL,
233 this->updateMatrixClip());
234 }
235
236 // must be in SkCanvas::PointMode order
237 static const GLenum gPointMode2GL[] = {
238 GL_POINTS,
239 GL_LINES,
240 GL_LINE_STRIP
241 };
242
drawPoints(const SkDraw & draw,SkCanvas::PointMode mode,size_t count,const SkPoint pts[],const SkPaint & paint)243 void SkGLDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
244 size_t count, const SkPoint pts[], const SkPaint& paint) {
245 TRACE_DRAW("coreDrawPoints", this, draw);
246
247 SkScalar width = paint.getStrokeWidth();
248 if (width < 0) {
249 return;
250 }
251
252 /* We should really only use drawverts for hairlines, since gl and skia
253 treat the thickness differently...
254 */
255
256 AutoPaintShader shader(this, paint);
257
258 if (width <= 0) {
259 width = SK_Scalar1;
260 }
261
262 if (SkCanvas::kPoints_PointMode == mode) {
263 glPointSize(SkScalarToFloat(width));
264 } else {
265 glLineWidth(SkScalarToFloat(width));
266 }
267
268 const SkGLVertex* verts;
269
270 #if GLSCALAR_IS_SCALAR
271 verts = (const SkGLVertex*)pts;
272 #else
273 SkAutoSTMalloc<32, SkGLVertex> storage(count);
274 SkGLVertex* v = storage.get();
275
276 v->setPoints(pts, count);
277 verts = v;
278 #endif
279
280 const SkGLVertex* texs = shader.useTex() ? verts : NULL;
281
282 SkGL::DrawVertices(count, gPointMode2GL[mode], verts, texs, NULL, NULL,
283 this->updateMatrixClip());
284 }
285
286 /* create a triangle strip that strokes the specified triangle. There are 8
287 unique vertices, but we repreat the last 2 to close up. Alternatively we
288 could use an indices array, and then only send 8 verts, but not sure that
289 would be faster.
290 */
setStrokeRectStrip(SkGLVertex verts[10],const SkRect & rect,SkScalar width)291 static void setStrokeRectStrip(SkGLVertex verts[10], const SkRect& rect,
292 SkScalar width) {
293 const SkScalar rad = SkScalarHalf(width);
294
295 verts[0].setScalars(rect.fLeft + rad, rect.fTop + rad);
296 verts[1].setScalars(rect.fLeft - rad, rect.fTop - rad);
297 verts[2].setScalars(rect.fRight - rad, rect.fTop + rad);
298 verts[3].setScalars(rect.fRight + rad, rect.fTop - rad);
299 verts[4].setScalars(rect.fRight - rad, rect.fBottom - rad);
300 verts[5].setScalars(rect.fRight + rad, rect.fBottom + rad);
301 verts[6].setScalars(rect.fLeft + rad, rect.fBottom - rad);
302 verts[7].setScalars(rect.fLeft - rad, rect.fBottom + rad);
303 verts[8] = verts[0];
304 verts[9] = verts[1];
305 }
306
drawRect(const SkDraw & draw,const SkRect & rect,const SkPaint & paint)307 void SkGLDevice::drawRect(const SkDraw& draw, const SkRect& rect,
308 const SkPaint& paint) {
309 TRACE_DRAW("coreDrawRect", this, draw);
310
311 bool doStroke = paint.getStyle() == SkPaint::kStroke_Style;
312
313 if (doStroke) {
314 if (paint.getStrokeJoin() != SkPaint::kMiter_Join) {
315 SkGL_unimpl("non-miter stroke rect");
316 return;
317 }
318 } else if (paint.getStrokeJoin() != SkPaint::kMiter_Join) {
319 SkPath path;
320 path.addRect(rect);
321 this->drawPath(draw, path, paint);
322 return;
323 }
324
325 AutoPaintShader shader(this, paint);
326 SkScalar width = paint.getStrokeWidth();
327 SkGLVertex vertex[10]; // max needed for all cases
328 int vertCount;
329 GLenum vertMode;
330
331 if (doStroke) {
332 if (width > 0) {
333 vertCount = 10;
334 vertMode = GL_TRIANGLE_STRIP;
335 setStrokeRectStrip(vertex, rect, width);
336 } else { // hairline
337 vertCount = 5;
338 vertMode = GL_LINE_STRIP;
339 vertex[0].setScalars(rect.fLeft, rect.fTop);
340 vertex[1].setScalars(rect.fRight, rect.fTop);
341 vertex[2].setScalars(rect.fRight, rect.fBottom);
342 vertex[3].setScalars(rect.fLeft, rect.fBottom);
343 vertex[4].setScalars(rect.fLeft, rect.fTop);
344 glLineWidth(1);
345 }
346 } else {
347 vertCount = 4;
348 vertMode = GL_TRIANGLE_FAN;
349 vertex->setRectFan(rect);
350 }
351
352 const SkGLVertex* texs = shader.useTex() ? vertex : NULL;
353 SkGL::DrawVertices(vertCount, vertMode, vertex, texs, NULL, NULL,
354 this->updateMatrixClip());
355 }
356
drawPath(const SkDraw & draw,const SkPath & path,const SkPaint & paint)357 void SkGLDevice::drawPath(const SkDraw& draw, const SkPath& path,
358 const SkPaint& paint) {
359 TRACE_DRAW("coreDrawPath", this, draw);
360 if (paint.getStyle() == SkPaint::kStroke_Style) {
361 SkGL_unimpl("stroke path");
362 return;
363 }
364
365 AutoPaintShader shader(this, paint);
366
367 SkGL::FillPath(path, paint, shader.useTex(), this->updateMatrixClip());
368 }
369
drawBitmap(const SkDraw & draw,const SkBitmap & bitmap,const SkMatrix & m,const SkPaint & paint)370 void SkGLDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
371 const SkMatrix& m, const SkPaint& paint) {
372 TRACE_DRAW("coreDrawBitmap", this, draw);
373
374 SkAutoLockPixels alp(bitmap);
375 if (!bitmap.readyToDraw()) {
376 return;
377 }
378
379 SkGLClipIter* iter = this->updateMatrixClip();
380
381 SkPoint max;
382 GLenum name;
383 SkAutoLockTexCache(bitmap, &name, &max);
384 // the lock has already called glBindTexture for us
385 SkGL::SetTexParamsClamp(paint.isFilterBitmap());
386
387 glMatrixMode(GL_TEXTURE);
388 glLoadIdentity();
389 glMatrixMode(GL_MODELVIEW);
390 glPushMatrix();
391 SkGL::MultMatrix(m);
392
393 SkGLVertex pts[4], tex[4];
394
395 pts->setIRectFan(0, 0, bitmap.width(), bitmap.height());
396 tex->setRectFan(0, 0, max.fX, max.fY);
397
398 // now draw the mesh
399 SkGL::SetPaintAlpha(paint);
400 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
401
402 SkGL::DrawVertices(4, GL_TRIANGLE_FAN, pts, tex, NULL, NULL, iter);
403
404 glPopMatrix();
405 }
406
407 // move this guy into SkGL, so we can call it from SkGLDevice
gl_drawSprite(int x,int y,int w,int h,const SkPoint & max,const SkPaint & paint,SkGLClipIter * iter)408 static void gl_drawSprite(int x, int y, int w, int h, const SkPoint& max,
409 const SkPaint& paint, SkGLClipIter* iter) {
410 SkGL::SetTexParamsClamp(false);
411
412 glMatrixMode(GL_TEXTURE);
413 glLoadIdentity();
414 glMatrixMode(GL_MODELVIEW);
415 glPushMatrix();
416 glLoadIdentity();
417
418 SkGLVertex pts[4], tex[4];
419
420 // if h < 0, then the texture is bottom-to-top, but since our projection
421 // matrix always inverts Y, we have to re-invert our texture coord here
422 if (h < 0) {
423 h = -h;
424 tex->setRectFan(0, max.fY, max.fX, 0);
425 } else {
426 tex->setRectFan(0, 0, max.fX, max.fY);
427 }
428 pts->setIRectFan(x, y, x + w, y + h);
429
430 SkGL::SetPaintAlpha(paint);
431 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
432
433 // should look to use glDrawTexi() has we do for text...
434 SkGL::DrawVertices(4, GL_TRIANGLE_FAN, pts, tex, NULL, NULL, iter);
435
436 glPopMatrix();
437 }
438
drawSprite(const SkDraw & draw,const SkBitmap & bitmap,int left,int top,const SkPaint & paint)439 void SkGLDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
440 int left, int top, const SkPaint& paint) {
441 TRACE_DRAW("coreDrawSprite", this, draw);
442
443 SkAutoLockPixels alp(bitmap);
444 if (!bitmap.readyToDraw()) {
445 return;
446 }
447
448 SkGLClipIter* iter = this->updateMatrixClip();
449
450 SkPoint max;
451 GLuint name;
452 SkAutoLockTexCache(bitmap, &name, &max);
453
454 gl_drawSprite(left, top, bitmap.width(), bitmap.height(), max, paint, iter);
455 }
456
drawDevice(const SkDraw & draw,SkDevice * dev,int x,int y,const SkPaint & paint)457 void SkGLDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
458 int x, int y, const SkPaint& paint) {
459 TRACE_DRAW("coreDrawDevice", this, draw);
460
461 SkGLDevice::TexOrientation to = ((SkGLDevice*)dev)->bindDeviceAsTexture();
462 if (SkGLDevice::kNo_TexOrientation != to) {
463 SkGLClipIter* iter = this->updateMatrixClip();
464
465 const SkBitmap& bm = dev->accessBitmap(false);
466 int w = bm.width();
467 int h = bm.height();
468 SkPoint max;
469
470 max.set(SkFixedToScalar(w << (16 - SkNextLog2(bm.rowBytesAsPixels()))),
471 SkFixedToScalar(h << (16 - SkNextLog2(h))));
472
473 if (SkGLDevice::kBottomToTop_TexOrientation == to) {
474 h = -h;
475 }
476 gl_drawSprite(x, y, w, h, max, paint, iter);
477 }
478 }
479
480 ///////////////////////////////////////////////////////////////////////////////
481
482 static const GLenum gVertexModeToGL[] = {
483 GL_TRIANGLES, // kTriangles_VertexMode,
484 GL_TRIANGLE_STRIP, // kTriangleStrip_VertexMode,
485 GL_TRIANGLE_FAN // kTriangleFan_VertexMode
486 };
487
488 #include "SkShader.h"
489
drawVertices(const SkDraw & draw,SkCanvas::VertexMode vmode,int vertexCount,const SkPoint vertices[],const SkPoint texs[],const SkColor colors[],SkXfermode * xmode,const uint16_t indices[],int indexCount,const SkPaint & paint)490 void SkGLDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
491 int vertexCount, const SkPoint vertices[],
492 const SkPoint texs[], const SkColor colors[],
493 SkXfermode* xmode,
494 const uint16_t indices[], int indexCount,
495 const SkPaint& paint) {
496
497 if (false) {
498 SkRect bounds;
499 SkIRect ibounds;
500
501 bounds.set(vertices, vertexCount);
502 bounds.round(&ibounds);
503
504 SkDebugf("---- drawverts: %d pts, texs=%d colors=%d indices=%d bounds [%d %d]\n",
505 vertexCount, texs!=0, colors!=0, indexCount, ibounds.width(), ibounds.height());
506 }
507
508 SkGLClipIter* iter = this->updateMatrixClip();
509
510 SkGL::SetPaint(paint);
511
512 const SkGLVertex* glVerts;
513 const SkGLVertex* glTexs = NULL;
514
515 #if GLSCALAR_IS_SCALAR
516 glVerts = (const SkGLVertex*)vertices;
517 #else
518 SkAutoSTMalloc<32, SkGLVertex> storage(vertexCount);
519 storage.get()->setPoints(vertices, vertexCount);
520 glVerts = storage.get();
521 #endif
522
523 uint8_t* colorArray = NULL;
524 if (colors) {
525 colorArray = (uint8_t*)sk_malloc_throw(vertexCount*4);
526 SkGL::SetRGBA(colorArray, colors, vertexCount);
527 }
528 SkAutoFree afca(colorArray);
529
530 SkGLVertex* texArray = NULL;
531 TexCache* cache = NULL;
532
533 if (texs && paint.getShader()) {
534 SkShader* shader = paint.getShader();
535
536 // if (!shader->setContext(this->accessBitmap(), paint, *draw.fMatrix)) {
537 if (!shader->setContext(*draw.fBitmap, paint, *draw.fMatrix)) {
538 goto DONE;
539 }
540
541 SkBitmap bitmap;
542 SkMatrix matrix;
543 SkShader::TileMode tileModes[2];
544 if (shader->asABitmap(&bitmap, &matrix, tileModes)) {
545 SkPoint max;
546 GLuint name;
547 cache = SkGLDevice::LockTexCache(bitmap, &name, &max);
548 if (NULL == cache) {
549 return;
550 }
551
552 matrix.postScale(max.fX / bitmap.width(), max.fY / bitmap.height());
553 glMatrixMode(GL_TEXTURE);
554 SkGL::LoadMatrix(matrix);
555 glMatrixMode(GL_MODELVIEW);
556
557 #if GLSCALAR_IS_SCALAR
558 glTexs = (const SkGLVertex*)texs;
559 #else
560 texArray = (SkGLVertex*)sk_malloc_throw(vertexCount * sizeof(SkGLVertex));
561 texArray->setPoints(texs, vertexCount);
562 glTexs = texArray;
563 #endif
564
565 SkGL::SetPaintAlpha(paint);
566 SkGL::SetTexParams(paint.isFilterBitmap(),
567 tileModes[0], tileModes[1]);
568 }
569 }
570 DONE:
571 SkAutoFree aftex(texArray);
572
573 SkGL::DrawVertices(indices ? indexCount : vertexCount,
574 gVertexModeToGL[vmode],
575 glVerts, glTexs, colorArray, indices, iter);
576
577 if (cache) {
578 SkGLDevice::UnlockTexCache(cache);
579 }
580 }
581
582 ///////////////////////////////////////////////////////////////////////////////
583
584 #include "SkGlyphCache.h"
585 #include "SkGLTextCache.h"
586
GlyphCacheAuxProc(void * data)587 void SkGLDevice::GlyphCacheAuxProc(void* data) {
588 SkDebugf("-------------- delete text texture cache\n");
589 SkDELETE((SkGLTextCache*)data);
590 }
591
592 #ifdef SK_SCALAR_IS_FIXED
593 #define SkDiv16ToScalar(numer, denom) (SkIntToFixed(numer) / (denom))
594 #else
595 #define SkDiv16ToScalar(numer, denom) SkScalarDiv(numer, denom)
596 #endif
597
598 // stolen from SkDraw.cpp - D1G_NoBounder_RectClip
SkGL_Draw1Glyph(const SkDraw1Glyph & state,const SkGlyph & glyph,int x,int y)599 static void SkGL_Draw1Glyph(const SkDraw1Glyph& state, const SkGlyph& glyph,
600 int x, int y) {
601 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
602
603 SkGLDrawProcs* procs = (SkGLDrawProcs*)state.fDraw->fProcs;
604
605 x += glyph.fLeft;
606 y += glyph.fTop;
607
608 // check if we're clipped out (nothing to draw)
609 SkIRect bounds;
610 bounds.set(x, y, x + glyph.fWidth, y + glyph.fHeight);
611 if (!SkIRect::Intersects(state.fClip->getBounds(), bounds)) {
612 return;
613 }
614
615 // now dig up our texture cache
616
617 SkGlyphCache* gcache = state.fCache;
618 void* auxData;
619 SkGLTextCache* textCache = NULL;
620
621 if (gcache->getAuxProcData(SkGLDevice::GlyphCacheAuxProc, &auxData)) {
622 textCache = (SkGLTextCache*)auxData;
623 }
624 if (NULL == textCache) {
625 // need to create one
626 textCache = SkNEW(SkGLTextCache);
627 gcache->setAuxProc(SkGLDevice::GlyphCacheAuxProc, textCache);
628 }
629
630 int offset;
631 SkGLTextCache::Strike* strike = textCache->findGlyph(glyph, &offset);
632 if (NULL == strike) {
633 // make sure the glyph has an image
634 uint8_t* aa = (uint8_t*)glyph.fImage;
635 if (NULL == aa) {
636 aa = (uint8_t*)gcache->findImage(glyph);
637 if (NULL == aa) {
638 return; // can't rasterize glyph
639 }
640 }
641 strike = textCache->addGlyphAndBind(glyph, aa, &offset);
642 if (NULL == strike) {
643 SkGL_unimpl("addGlyphAndBind failed, too big");
644 // too big to cache, need to draw as is...
645 return;
646 }
647 }
648
649 const int shiftW = strike->widthShift();
650 const int shiftH = strike->heightShift();
651
652 SkFixed left = offset << (16 - shiftW);
653 SkFixed right = (offset + glyph.fWidth) << (16 - shiftW);
654 SkFixed bottom = glyph.fHeight << (16 - shiftH);
655
656 procs->addQuad(strike->texture(), x, y, glyph, left, right, bottom);
657 }
658
659 #if 1
660 // matches the orientation used in SkGL::setRectFan. Too bad we can't rely on
661 // QUADS in android's GL
662 static const uint8_t gQuadIndices[] = {
663 0, 1, 2, 0, 2, 3,
664 4, 5, 6, 4, 6, 7,
665 8, 9, 10, 8, 10, 11,
666 12, 13, 14, 12, 14, 15,
667 16, 17, 18, 16, 18, 19,
668 20, 21, 22, 20, 22, 23,
669 24, 25, 26, 24, 26, 27,
670 28, 29, 30, 28, 30, 31,
671 32, 33, 34, 32, 34, 35,
672 36, 37, 38, 36, 38, 39,
673 40, 41, 42, 40, 42, 43,
674 44, 45, 46, 44, 46, 47,
675 48, 49, 50, 48, 50, 51,
676 52, 53, 54, 52, 54, 55,
677 56, 57, 58, 56, 58, 59,
678 60, 61, 62, 60, 62, 63,
679 64, 65, 66, 64, 66, 67,
680 68, 69, 70, 68, 70, 71,
681 72, 73, 74, 72, 74, 75,
682 76, 77, 78, 76, 78, 79,
683 80, 81, 82, 80, 82, 83,
684 84, 85, 86, 84, 86, 87,
685 88, 89, 90, 88, 90, 91,
686 92, 93, 94, 92, 94, 95,
687 96, 97, 98, 96, 98, 99,
688 100, 101, 102, 100, 102, 103,
689 104, 105, 106, 104, 106, 107,
690 108, 109, 110, 108, 110, 111,
691 112, 113, 114, 112, 114, 115,
692 116, 117, 118, 116, 118, 119,
693 120, 121, 122, 120, 122, 123,
694 124, 125, 126, 124, 126, 127
695 };
696 #else
generateQuadIndices(int n)697 static void generateQuadIndices(int n) {
698 int index = 0;
699 for (int i = 0; i < n; i++) {
700 SkDebugf(" %3d, %3d, %3d, %3d, %3d, %3d,\n",
701 index, index + 1, index + 2, index, index + 2, index + 3);
702 index += 4;
703 }
704 }
705 #endif
706
drawQuads()707 void SkGLDrawProcs::drawQuads() {
708 SkASSERT(SK_ARRAY_COUNT(gQuadIndices) == MAX_QUADS * 6);
709
710 glBindTexture(GL_TEXTURE_2D, fCurrTexture);
711
712 #if 0
713 static bool gOnce;
714 if (!gOnce) {
715 generateQuadIndices(MAX_QUADS);
716 gOnce = true;
717 }
718 #endif
719
720 // convert from quad vertex count to triangle vertex count
721 // 6/4 * n == n + (n >> 1) since n is always a multiple of 4
722 SkASSERT((fCurrQuad & 3) == 0);
723 int count = fCurrQuad + (fCurrQuad >> 1);
724
725 if (fClip->isComplex()) {
726 SkGLClipIter iter(fViewportHeight);
727 iter.reset(*fClip);
728 while (!iter.done()) {
729 iter.scissor();
730 glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_BYTE, gQuadIndices);
731 iter.next();
732 }
733 } else {
734 glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_BYTE, gQuadIndices);
735 }
736 }
737
setupForText(SkDraw * draw,const SkPaint & paint)738 void SkGLDevice::setupForText(SkDraw* draw, const SkPaint& paint) {
739 // we handle complex clips in the SkDraw common code, so we don't check
740 // for it here
741 this->updateMatrixClip();
742
743 SkGL::SetPaint(paint, false);
744
745 glMatrixMode(GL_TEXTURE);
746 glLoadIdentity();
747
748 glMatrixMode(GL_MODELVIEW);
749 glPushMatrix();
750 glLoadIdentity();
751
752 // deferred allocation
753 if (NULL == fDrawProcs) {
754 fDrawProcs = SkNEW(SkGLDrawProcs);
755 fDrawProcs->fD1GProc = SkGL_Draw1Glyph;
756 }
757
758 // init our (and GL's) state
759 fDrawProcs->init(draw->fClip, this->height());
760 // assign to the caller's SkDraw
761 draw->fProcs = fDrawProcs;
762
763 glEnable(GL_TEXTURE_2D);
764 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
765 glShadeModel(GL_FLAT);
766 }
767
drawText(const SkDraw & draw,const void * text,size_t byteLength,SkScalar x,SkScalar y,const SkPaint & paint)768 void SkGLDevice::drawText(const SkDraw& draw, const void* text,
769 size_t byteLength, SkScalar x, SkScalar y,
770 const SkPaint& paint) {
771 /* Currently, perspective text is draw via paths, invoked directly by
772 SkDraw. This can't work for us, since the bitmap that our draw points
773 to has no pixels, so we just abort if we're in perspective.
774
775 Better fix would be to...
776 - have a callback inside draw to handle path drawing
777 - option to have draw call the font cache, which we could patch (?)
778 */
779 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
780 SkGL_unimpl("drawText in perspective");
781 return;
782 }
783
784 SkDraw myDraw(draw);
785 this->setupForText(&myDraw, paint);
786 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
787 fDrawProcs->flush();
788 glPopMatrix(); // GL_MODELVIEW
789 }
790
drawPosText(const SkDraw & draw,const void * text,size_t byteLength,const SkScalar pos[],SkScalar constY,int scalarsPerPos,const SkPaint & paint)791 void SkGLDevice::drawPosText(const SkDraw& draw, const void* text,
792 size_t byteLength, const SkScalar pos[],
793 SkScalar constY, int scalarsPerPos,
794 const SkPaint& paint) {
795 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
796 SkGL_unimpl("drawPosText in perspective");
797 return;
798 }
799
800 SkDraw myDraw(draw);
801 this->setupForText(&myDraw, paint);
802 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
803 scalarsPerPos, paint);
804 fDrawProcs->flush();
805 glPopMatrix(); // GL_MODELVIEW
806 }
807
drawTextOnPath(const SkDraw & draw,const void * text,size_t byteLength,const SkPath & path,const SkMatrix * m,const SkPaint & paint)808 void SkGLDevice::drawTextOnPath(const SkDraw& draw, const void* text,
809 size_t byteLength, const SkPath& path,
810 const SkMatrix* m, const SkPaint& paint) {
811 SkGL_unimpl("drawTextOnPath");
812 }
813
814