Home | History | Annotate | Download | only in gl
      1 #include "SkGL.h"
      2 #include "SkColorPriv.h"
      3 #include "SkGeometry.h"
      4 #include "SkPaint.h"
      5 #include "SkPath.h"
      6 #include "SkTemplates.h"
      7 #include "SkXfermode.h"
      8 
      9 //#define TRACE_TEXTURE_CREATION
     10 
     11 ///////////////////////////////////////////////////////////////////////////////
     12 
     13 #ifdef SK_GL_HAS_COLOR4UB
     14 static inline void gl_pmcolor(U8CPU r, U8CPU g, U8CPU b, U8CPU a) {
     15     glColor4ub(r, g, b, a);
     16 }
     17 
     18 void SkGL::SetAlpha(U8CPU alpha) {
     19     glColor4ub(alpha, alpha, alpha, alpha);
     20 }
     21 #else
     22 static inline SkFixed byte2fixed(U8CPU value) {
     23     return (value + (value >> 7)) << 8;
     24 }
     25 
     26 static inline void gl_pmcolor(U8CPU r, U8CPU g, U8CPU b, U8CPU a) {
     27     glColor4x(byte2fixed(r), byte2fixed(g), byte2fixed(b), byte2fixed(a));
     28 }
     29 
     30 void SkGL::SetAlpha(U8CPU alpha) {
     31     SkFixed fa = byte2fixed(alpha);
     32     glColor4x(fa, fa, fa, fa);
     33 }
     34 #endif
     35 
     36 void SkGL::SetColor(SkColor c) {
     37     SkPMColor pm = SkPreMultiplyColor(c);
     38     gl_pmcolor(SkGetPackedR32(pm),
     39                SkGetPackedG32(pm),
     40                SkGetPackedB32(pm),
     41                SkGetPackedA32(pm));
     42 }
     43 
     44 static const GLenum gXfermodeCoeff2Blend[] = {
     45     GL_ZERO,
     46     GL_ONE,
     47     GL_SRC_COLOR,
     48     GL_ONE_MINUS_SRC_COLOR,
     49     GL_DST_COLOR,
     50     GL_ONE_MINUS_DST_COLOR,
     51     GL_SRC_ALPHA,
     52     GL_ONE_MINUS_SRC_ALPHA,
     53     GL_DST_ALPHA,
     54     GL_ONE_MINUS_DST_ALPHA,
     55 };
     56 
     57 void SkGL::SetPaint(const SkPaint& paint, bool isPremul, bool justAlpha) {
     58     if (justAlpha) {
     59         SkGL::SetAlpha(paint.getAlpha());
     60     } else {
     61         SkGL::SetColor(paint.getColor());
     62     }
     63 
     64     GLenum sm = GL_ONE;
     65     GLenum dm = GL_ONE_MINUS_SRC_ALPHA;
     66 
     67     SkXfermode* mode = paint.getXfermode();
     68     SkXfermode::Coeff sc, dc;
     69     if (mode && mode->asCoeff(&sc, &dc)) {
     70         sm = gXfermodeCoeff2Blend[sc];
     71         dm = gXfermodeCoeff2Blend[dc];
     72     }
     73 
     74     // hack for text, which is not-premul (afaik)
     75     if (!isPremul) {
     76         if (GL_ONE == sm) {
     77             sm = GL_SRC_ALPHA;
     78         }
     79     }
     80 
     81     glEnable(GL_BLEND);
     82     glBlendFunc(sm, dm);
     83 
     84     if (paint.isDither()) {
     85         glEnable(GL_DITHER);
     86     } else {
     87         glDisable(GL_DITHER);
     88     }
     89 }
     90 
     91 ///////////////////////////////////////////////////////////////////////////////
     92 
     93 void SkGL::DumpError(const char caller[]) {
     94     GLenum err = glGetError();
     95     if (err) {
     96         SkDebugf("---- glGetError(%s) %d\n", caller, err);
     97     }
     98 }
     99 
    100 void SkGL::SetRGBA(uint8_t rgba[], const SkColor src[], int count) {
    101     for (int i = 0; i < count; i++) {
    102         SkPMColor c = SkPreMultiplyColor(*src++);
    103         *rgba++ = SkGetPackedR32(c);
    104         *rgba++ = SkGetPackedG32(c);
    105         *rgba++ = SkGetPackedB32(c);
    106         *rgba++ = SkGetPackedA32(c);
    107     }
    108 }
    109 
    110 ///////////////////////////////////////////////////////////////////////////////
    111 
    112 void SkGL::Scissor(const SkIRect& r, int viewportHeight) {
    113     glScissor(r.fLeft, viewportHeight - r.fBottom, r.width(), r.height());
    114 }
    115 
    116 ///////////////////////////////////////////////////////////////////////////////
    117 
    118 void SkGL::Ortho(float left, float right, float bottom, float top,
    119                  float near, float far) {
    120 
    121     float mat[16];
    122 
    123     sk_bzero(mat, sizeof(mat));
    124 
    125     mat[0] = 2 / (right - left);
    126     mat[5] = 2 / (top - bottom);
    127     mat[10] = 2 / (near - far);
    128     mat[15] = 1;
    129 
    130     mat[12] = (right + left) / (left - right);
    131     mat[13] = (top + bottom) / (bottom - top);
    132     mat[14] = (far + near) / (near - far);
    133 
    134     glMultMatrixf(mat);
    135 }
    136 
    137 ///////////////////////////////////////////////////////////////////////////////
    138 
    139 static bool canBeTexture(const SkBitmap& bm, GLenum* format, GLenum* type) {
    140     switch (bm.config()) {
    141         case SkBitmap::kARGB_8888_Config:
    142             *format = GL_RGBA;
    143             *type = GL_UNSIGNED_BYTE;
    144             break;
    145         case SkBitmap::kRGB_565_Config:
    146             *format = GL_RGB;
    147             *type = GL_UNSIGNED_SHORT_5_6_5;
    148             break;
    149         case SkBitmap::kARGB_4444_Config:
    150             *format = GL_RGBA;
    151             *type = GL_UNSIGNED_SHORT_4_4_4_4;
    152             break;
    153         case SkBitmap::kIndex8_Config:
    154 #ifdef SK_GL_SUPPORT_COMPRESSEDTEXIMAGE2D
    155             *format = GL_PALETTE8_RGBA8_OES;
    156             *type = GL_UNSIGNED_BYTE;   // unused I think
    157 #else
    158             // we promote index to argb32
    159             *format = GL_RGBA;
    160             *type = GL_UNSIGNED_BYTE;
    161 #endif
    162             break;
    163         case SkBitmap::kA8_Config:
    164             *format = GL_ALPHA;
    165             *type = GL_UNSIGNED_BYTE;
    166             break;
    167         default:
    168             return false;
    169     }
    170     return true;
    171 }
    172 
    173 #define SK_GL_SIZE_OF_PALETTE   (256 * sizeof(SkPMColor))
    174 
    175 size_t SkGL::ComputeTextureMemorySize(const SkBitmap& bitmap) {
    176     int shift = 0;
    177     size_t adder = 0;
    178     switch (bitmap.config()) {
    179         case SkBitmap::kARGB_8888_Config:
    180         case SkBitmap::kRGB_565_Config:
    181         case SkBitmap::kARGB_4444_Config:
    182         case SkBitmap::kA8_Config:
    183             // we're good as is
    184             break;
    185         case SkBitmap::kIndex8_Config:
    186 #ifdef SK_GL_SUPPORT_COMPRESSEDTEXIMAGE2D
    187             // account for the colortable
    188             adder = SK_GL_SIZE_OF_PALETTE;
    189 #else
    190             // we promote index to argb32
    191             shift = 2;
    192 #endif
    193             break;
    194         default:
    195             return 0;
    196     }
    197     return (bitmap.getSize() << shift) + adder;
    198 }
    199 
    200 #ifdef SK_GL_SUPPORT_COMPRESSEDTEXIMAGE2D
    201 /*  Fill out buffer with the compressed format GL expects from a colortable
    202     based bitmap. [palette (colortable) + indices].
    203 
    204     At the moment I always take the 8bit version, since that's what my data
    205     is. I could detect that the colortable.count is <= 16, and then repack the
    206     indices as nibbles to save RAM, but it would take more time (i.e. a lot
    207     slower than memcpy), so I'm skipping that for now.
    208 
    209     GL wants a full 256 palette entry, even though my ctable is only as big
    210     as the colortable.count says it is. I presume it is OK to leave any
    211     trailing entries uninitialized, since none of my indices should exceed
    212     ctable->count().
    213 */
    214 static void build_compressed_data(void* buffer, const SkBitmap& bitmap) {
    215     SkASSERT(SkBitmap::kIndex8_Config == bitmap.config());
    216 
    217     SkColorTable* ctable = bitmap.getColorTable();
    218     uint8_t* dst = (uint8_t*)buffer;
    219 
    220     memcpy(dst, ctable->lockColors(), ctable->count() * sizeof(SkPMColor));
    221     ctable->unlockColors(false);
    222 
    223     // always skip a full 256 number of entries, even if we memcpy'd fewer
    224     dst += SK_GL_SIZE_OF_PALETTE;
    225     memcpy(dst, bitmap.getPixels(), bitmap.getSize());
    226 }
    227 #endif
    228 
    229 /*  Return true if the bitmap cannot be supported in its current config as a
    230     texture, and it needs to be promoted to ARGB32.
    231  */
    232 static bool needToPromoteTo32bit(const SkBitmap& bitmap) {
    233     if (bitmap.config() == SkBitmap::kIndex8_Config) {
    234 #ifdef SK_GL_SUPPORT_COMPRESSEDTEXIMAGE2D
    235         const int w = bitmap.width();
    236         const int h = bitmap.height();
    237         if (SkNextPow2(w) == w && SkNextPow2(h) == h) {
    238             // we can handle Indx8 if we're a POW2
    239             return false;
    240         }
    241 #endif
    242         return true;    // must promote to ARGB32
    243     }
    244     return false;
    245 }
    246 
    247 GLuint SkGL::BindNewTexture(const SkBitmap& origBitmap, SkPoint* max) {
    248     SkBitmap tmpBitmap;
    249     const SkBitmap* bitmap = &origBitmap;
    250 
    251     if (needToPromoteTo32bit(origBitmap)) {
    252         origBitmap.copyTo(&tmpBitmap, SkBitmap::kARGB_8888_Config);
    253         // now bitmap points to our temp, which has been promoted to 32bits
    254         bitmap = &tmpBitmap;
    255     }
    256 
    257     GLenum format, type;
    258     if (!canBeTexture(*bitmap, &format, &type)) {
    259         return 0;
    260     }
    261 
    262     SkAutoLockPixels alp(*bitmap);
    263     if (!bitmap->readyToDraw()) {
    264         return 0;
    265     }
    266 
    267     GLuint  textureName;
    268     glGenTextures(1, &textureName);
    269 
    270     glBindTexture(GL_TEXTURE_2D, textureName);
    271 
    272     // express rowbytes as a number of pixels for ow
    273     int ow = bitmap->rowBytesAsPixels();
    274     int oh = bitmap->height();
    275     int nw = SkNextPow2(ow);
    276     int nh = SkNextPow2(oh);
    277 
    278     glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel());
    279 
    280     // check if we need to scale to create power-of-2 dimensions
    281 #ifdef SK_GL_SUPPORT_COMPRESSEDTEXIMAGE2D
    282     if (SkBitmap::kIndex8_Config == bitmap->config()) {
    283         size_t imagesize = bitmap->getSize() + SK_GL_SIZE_OF_PALETTE;
    284         SkAutoMalloc storage(imagesize);
    285 
    286         build_compressed_data(storage.get(), *bitmap);
    287         // we only support POW2 here (GLES 1.0 restriction)
    288         SkASSERT(ow == nw);
    289         SkASSERT(oh == nh);
    290         glCompressedTexImage2D(GL_TEXTURE_2D, 0, format, ow, oh, 0,
    291                                imagesize, storage.get());
    292     } else  // fall through to non-compressed logic
    293 #endif
    294     {
    295         if (ow != nw || oh != nh) {
    296             glTexImage2D(GL_TEXTURE_2D, 0, format, nw, nh, 0,
    297                          format, type, NULL);
    298             glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, ow, oh,
    299                             format, type, bitmap->getPixels());
    300         } else {
    301             // easy case, the bitmap is already pow2
    302             glTexImage2D(GL_TEXTURE_2D, 0, format, ow, oh, 0,
    303                          format, type, bitmap->getPixels());
    304         }
    305     }
    306 
    307 #ifdef TRACE_TEXTURE_CREATION
    308     SkDebugf("--- new texture [%d] size=(%d %d) bpp=%d\n", textureName, ow, oh,
    309              bitmap->bytesPerPixel());
    310 #endif
    311 
    312     if (max) {
    313         max->fX = SkFixedToScalar(bitmap->width() << (16 - SkNextLog2(nw)));
    314         max->fY = SkFixedToScalar(oh << (16 - SkNextLog2(nh)));
    315     }
    316     return textureName;
    317 }
    318 
    319 static const GLenum gTileMode2GLWrap[] = {
    320     GL_CLAMP_TO_EDGE,
    321     GL_REPEAT,
    322 #if GL_VERSION_ES_CM_1_0
    323     GL_REPEAT       // GLES doesn't support MIRROR
    324 #else
    325     GL_MIRRORED_REPEAT
    326 #endif
    327 };
    328 
    329 void SkGL::SetTexParams(bool doFilter,
    330                         SkShader::TileMode tx, SkShader::TileMode ty) {
    331     SkASSERT((unsigned)tx < SK_ARRAY_COUNT(gTileMode2GLWrap));
    332     SkASSERT((unsigned)ty < SK_ARRAY_COUNT(gTileMode2GLWrap));
    333 
    334     GLenum filter = doFilter ? GL_LINEAR : GL_NEAREST;
    335 
    336     SK_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
    337     SK_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
    338     SK_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gTileMode2GLWrap[tx]);
    339     SK_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gTileMode2GLWrap[ty]);
    340 }
    341 
    342 void SkGL::SetTexParamsClamp(bool doFilter) {
    343     GLenum filter = doFilter ? GL_LINEAR : GL_NEAREST;
    344 
    345     SK_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
    346     SK_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
    347     SK_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    348     SK_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    349 }
    350 
    351 ///////////////////////////////////////////////////////////////////////////////
    352 
    353 void SkGL::DrawVertices(int count, GLenum mode,
    354                         const SkGLVertex* SK_RESTRICT vertex,
    355                         const SkGLVertex* SK_RESTRICT texCoords,
    356                         const uint8_t* SK_RESTRICT colorArray,
    357                         const uint16_t* SK_RESTRICT indexArray,
    358                         SkGLClipIter* iter) {
    359     SkASSERT(NULL != vertex);
    360 
    361     if (NULL != texCoords) {
    362         glEnable(GL_TEXTURE_2D);
    363         glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    364         glTexCoordPointer(2, SK_GLType, 0, texCoords);
    365     } else {
    366         glDisable(GL_TEXTURE_2D);
    367         glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    368     }
    369 
    370     if (NULL != colorArray) {
    371         glEnableClientState(GL_COLOR_ARRAY);
    372         glColorPointer(4, GL_UNSIGNED_BYTE, 0, colorArray);
    373         glShadeModel(GL_SMOOTH);
    374     } else {
    375         glDisableClientState(GL_COLOR_ARRAY);
    376         glShadeModel(GL_FLAT);
    377     }
    378 
    379     glVertexPointer(2, SK_GLType, 0, vertex);
    380 
    381     if (NULL != indexArray) {
    382         if (iter) {
    383             while (!iter->done()) {
    384                 iter->scissor();
    385                 glDrawElements(mode, count, GL_UNSIGNED_SHORT, indexArray);
    386                 iter->next();
    387             }
    388         } else {
    389             glDrawElements(mode, count, GL_UNSIGNED_SHORT, indexArray);
    390         }
    391     } else {
    392         if (iter) {
    393             while (!iter->done()) {
    394                 iter->scissor();
    395                 glDrawArrays(mode, 0, count);
    396                 iter->next();
    397             }
    398         } else {
    399             glDrawArrays(mode, 0, count);
    400         }
    401     }
    402 }
    403 
    404 void SkGL::PrepareForFillPath(SkPaint* paint) {
    405     if (paint->getStrokeWidth() <= 0) {
    406         paint->setStrokeWidth(SK_Scalar1);
    407     }
    408 }
    409 
    410 void SkGL::FillPath(const SkPath& path, const SkPaint& paint, bool useTex,
    411                     SkGLClipIter* iter) {
    412     SkPaint p(paint);
    413     SkPath  fillPath;
    414 
    415     SkGL::PrepareForFillPath(&p);
    416     p.getFillPath(path, &fillPath);
    417     SkGL::DrawPath(fillPath, useTex, iter);
    418 }
    419 
    420 // should return max of all contours, rather than the sum (to save temp RAM)
    421 static int worst_case_edge_count(const SkPath& path) {
    422     int edgeCount = 0;
    423 
    424     SkPath::Iter    iter(path, true);
    425     SkPath::Verb    verb;
    426 
    427     while ((verb = iter.next(NULL)) != SkPath::kDone_Verb) {
    428         switch (verb) {
    429             case SkPath::kLine_Verb:
    430                 edgeCount += 1;
    431                 break;
    432             case SkPath::kQuad_Verb:
    433                 edgeCount += 8;
    434                 break;
    435             case SkPath::kCubic_Verb:
    436                 edgeCount += 16;
    437                 break;
    438             default:
    439                 break;
    440         }
    441     }
    442     return edgeCount;
    443 }
    444 
    445 void SkGL::DrawPath(const SkPath& path, bool useTex, SkGLClipIter* clipIter) {
    446     const SkRect& bounds = path.getBounds();
    447     if (bounds.isEmpty()) {
    448         return;
    449     }
    450 
    451     int maxPts = worst_case_edge_count(path);
    452     // add 1 for center of fan, and 1 for closing edge
    453     SkAutoSTMalloc<32, SkGLVertex>  storage(maxPts + 2);
    454     SkGLVertex* base = storage.get();
    455     SkGLVertex* vert = base;
    456     SkGLVertex* texs = useTex ? base : NULL;
    457 
    458     SkPath::Iter    pathIter(path, true);
    459     SkPoint         pts[4];
    460 
    461     bool needEnd = false;
    462 
    463     for (;;) {
    464         switch (pathIter.next(pts)) {
    465             case SkPath::kMove_Verb:
    466                 if (needEnd) {
    467                     SkGL::DrawVertices(vert - base, GL_TRIANGLE_FAN,
    468                                        base, texs, NULL, NULL, clipIter);
    469                     clipIter->safeRewind();
    470                     vert = base;
    471                 }
    472                 needEnd = true;
    473                 // center of the FAN
    474                 vert->setScalars(bounds.centerX(), bounds.centerY());
    475                 vert++;
    476                 // add first edge point
    477                 vert->setPoint(pts[0]);
    478                 vert++;
    479                 break;
    480                 case SkPath::kLine_Verb:
    481                 vert->setPoint(pts[1]);
    482                 vert++;
    483                 break;
    484                 case SkPath::kQuad_Verb: {
    485                     const int n = 8;
    486                     const SkScalar dt = SK_Scalar1 / n;
    487                     SkScalar t = dt;
    488                     for (int i = 1; i < n; i++) {
    489                         SkPoint loc;
    490                         SkEvalQuadAt(pts, t, &loc, NULL);
    491                         t += dt;
    492                         vert->setPoint(loc);
    493                         vert++;
    494                     }
    495                     vert->setPoint(pts[2]);
    496                     vert++;
    497                     break;
    498                 }
    499                 case SkPath::kCubic_Verb: {
    500                     const int n = 16;
    501                     const SkScalar dt = SK_Scalar1 / n;
    502                     SkScalar t = dt;
    503                     for (int i = 1; i < n; i++) {
    504                         SkPoint loc;
    505                         SkEvalCubicAt(pts, t, &loc, NULL, NULL);
    506                         t += dt;
    507                         vert->setPoint(loc);
    508                         vert++;
    509                     }
    510                     vert->setPoint(pts[3]);
    511                     vert++;
    512                     break;
    513                 }
    514                 case SkPath::kClose_Verb:
    515                 break;
    516                 case SkPath::kDone_Verb:
    517                 goto FINISHED;
    518         }
    519     }
    520 FINISHED:
    521     if (needEnd) {
    522         SkGL::DrawVertices(vert - base, GL_TRIANGLE_FAN, base, texs,
    523                            NULL, NULL, clipIter);
    524     }
    525 }
    526 
    527