Home | History | Annotate | Download | only in gl
      1 #include "SkGLDevice.h"
      2 #include "SkGL.h"
      3 #include "SkDrawProcs.h"
      4 #include "SkRegion.h"
      5 #include "SkThread.h"
      6 
      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:
     14     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 
     26     GLenum texture() const { return fCurrTexture; }
     27 
     28     void flush() {
     29         if (fCurrQuad && fCurrTexture) {
     30             this->drawQuads();
     31         }
     32         fCurrQuad = 0;
     33     }
     34 
     35     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 
     72 SkGLDevice::SkGLDevice(const SkBitmap& bitmap, bool offscreen)
     73         : SkDevice(bitmap), fClipIter(bitmap.height()) {
     74     fDrawProcs = NULL;
     75 }
     76 
     77 SkGLDevice::~SkGLDevice() {
     78     if (fDrawProcs) {
     79         SkDELETE(fDrawProcs);
     80     }
     81 }
     82 
     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 
     92 SkGLDevice::TexOrientation SkGLDevice::bindDeviceAsTexture() {
     93     return kNo_TexOrientation;
     94 }
     95 
     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 
    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
    144 SkGLDevice::AutoPaintShader::AutoPaintShader(SkGLDevice* device,
    145                                              const SkPaint& paint) {
    146     fDevice = device;
    147     fTexCache = device->setupGLPaintShader(paint);
    148 }
    149 
    150 SkGLDevice::AutoPaintShader::~AutoPaintShader() {
    151     if (fTexCache) {
    152         SkGLDevice::UnlockTexCache(fTexCache);
    153     }
    154 }
    155 
    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 
    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 
    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  */
    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 
    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 
    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 
    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
    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 
    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 
    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 
    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 
    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
    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
    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 
    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 
    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 
    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 
    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 
    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