| Index: skia/gl/SkGL.cpp
|
| ===================================================================
|
| --- skia/gl/SkGL.cpp (revision 16859)
|
| +++ skia/gl/SkGL.cpp (working copy)
|
| @@ -1,528 +0,0 @@
|
| -#include "SkGL.h"
|
| -#include "SkColorPriv.h"
|
| -#include "SkGeometry.h"
|
| -#include "SkPaint.h"
|
| -#include "SkPath.h"
|
| -#include "SkTemplates.h"
|
| -#include "SkXfermode.h"
|
| -
|
| -//#define TRACE_TEXTURE_CREATION
|
| -
|
| -///////////////////////////////////////////////////////////////////////////////
|
| -
|
| -#ifdef SK_GL_HAS_COLOR4UB
|
| -static inline void gl_pmcolor(U8CPU r, U8CPU g, U8CPU b, U8CPU a) {
|
| - glColor4ub(r, g, b, a);
|
| -}
|
| -
|
| -void SkGL::SetAlpha(U8CPU alpha) {
|
| - glColor4ub(alpha, alpha, alpha, alpha);
|
| -}
|
| -#else
|
| -static inline SkFixed byte2fixed(U8CPU value) {
|
| - return (value + (value >> 7)) << 8;
|
| -}
|
| -
|
| -static inline void gl_pmcolor(U8CPU r, U8CPU g, U8CPU b, U8CPU a) {
|
| - glColor4x(byte2fixed(r), byte2fixed(g), byte2fixed(b), byte2fixed(a));
|
| -}
|
| -
|
| -void SkGL::SetAlpha(U8CPU alpha) {
|
| - SkFixed fa = byte2fixed(alpha);
|
| - glColor4x(fa, fa, fa, fa);
|
| -}
|
| -#endif
|
| -
|
| -void SkGL::SetColor(SkColor c) {
|
| - SkPMColor pm = SkPreMultiplyColor(c);
|
| - gl_pmcolor(SkGetPackedR32(pm),
|
| - SkGetPackedG32(pm),
|
| - SkGetPackedB32(pm),
|
| - SkGetPackedA32(pm));
|
| -}
|
| -
|
| -static const GLenum gXfermodeCoeff2Blend[] = {
|
| - GL_ZERO,
|
| - GL_ONE,
|
| - GL_SRC_COLOR,
|
| - GL_ONE_MINUS_SRC_COLOR,
|
| - GL_DST_COLOR,
|
| - GL_ONE_MINUS_DST_COLOR,
|
| - GL_SRC_ALPHA,
|
| - GL_ONE_MINUS_SRC_ALPHA,
|
| - GL_DST_ALPHA,
|
| - GL_ONE_MINUS_DST_ALPHA,
|
| -};
|
| -
|
| -void SkGL::SetPaint(const SkPaint& paint, bool isPremul, bool justAlpha) {
|
| - if (justAlpha) {
|
| - SkGL::SetAlpha(paint.getAlpha());
|
| - } else {
|
| - SkGL::SetColor(paint.getColor());
|
| - }
|
| -
|
| - GLenum sm = GL_ONE;
|
| - GLenum dm = GL_ONE_MINUS_SRC_ALPHA;
|
| -
|
| - SkXfermode* mode = paint.getXfermode();
|
| - SkXfermode::Coeff sc, dc;
|
| - if (mode && mode->asCoeff(&sc, &dc)) {
|
| - sm = gXfermodeCoeff2Blend[sc];
|
| - dm = gXfermodeCoeff2Blend[dc];
|
| - }
|
| -
|
| - // hack for text, which is not-premul (afaik)
|
| - if (!isPremul) {
|
| - if (GL_ONE == sm) {
|
| - sm = GL_SRC_ALPHA;
|
| - }
|
| - }
|
| -
|
| - glEnable(GL_BLEND);
|
| - glBlendFunc(sm, dm);
|
| -
|
| - if (paint.isDither()) {
|
| - glEnable(GL_DITHER);
|
| - } else {
|
| - glDisable(GL_DITHER);
|
| - }
|
| -}
|
| -
|
| -///////////////////////////////////////////////////////////////////////////////
|
| -
|
| -void SkGL::DumpError(const char caller[]) {
|
| - GLenum err = glGetError();
|
| - if (err) {
|
| - SkDebugf("---- glGetError(%s) %d\n", caller, err);
|
| - }
|
| -}
|
| -
|
| -void SkGL::SetRGBA(uint8_t rgba[], const SkColor src[], int count) {
|
| - for (int i = 0; i < count; i++) {
|
| - SkPMColor c = SkPreMultiplyColor(*src++);
|
| - *rgba++ = SkGetPackedR32(c);
|
| - *rgba++ = SkGetPackedG32(c);
|
| - *rgba++ = SkGetPackedB32(c);
|
| - *rgba++ = SkGetPackedA32(c);
|
| - }
|
| -}
|
| -
|
| -///////////////////////////////////////////////////////////////////////////////
|
| -
|
| -void SkGL::Scissor(const SkIRect& r, int viewportHeight) {
|
| - glScissor(r.fLeft, viewportHeight - r.fBottom, r.width(), r.height());
|
| -}
|
| -
|
| -///////////////////////////////////////////////////////////////////////////////
|
| -
|
| -void SkGL::Ortho(float left, float right, float bottom, float top,
|
| - float near, float far) {
|
| -
|
| - float mat[16];
|
| -
|
| - bzero(mat, sizeof(mat));
|
| -
|
| - mat[0] = 2 / (right - left);
|
| - mat[5] = 2 / (top - bottom);
|
| - mat[10] = 2 / (near - far);
|
| - mat[15] = 1;
|
| -
|
| - mat[12] = (right + left) / (left - right);
|
| - mat[13] = (top + bottom) / (bottom - top);
|
| - mat[14] = (far + near) / (near - far);
|
| -
|
| - glMultMatrixf(mat);
|
| -}
|
| -
|
| -///////////////////////////////////////////////////////////////////////////////
|
| -
|
| -static bool canBeTexture(const SkBitmap& bm, GLenum* format, GLenum* type) {
|
| - switch (bm.config()) {
|
| - case SkBitmap::kARGB_8888_Config:
|
| - *format = GL_RGBA;
|
| - *type = GL_UNSIGNED_BYTE;
|
| - break;
|
| - case SkBitmap::kRGB_565_Config:
|
| - *format = GL_RGB;
|
| - *type = GL_UNSIGNED_SHORT_5_6_5;
|
| - break;
|
| - case SkBitmap::kARGB_4444_Config:
|
| - *format = GL_RGBA;
|
| - *type = GL_UNSIGNED_SHORT_4_4_4_4;
|
| - break;
|
| - case SkBitmap::kIndex8_Config:
|
| -#ifdef SK_GL_SUPPORT_COMPRESSEDTEXIMAGE2D
|
| - *format = GL_PALETTE8_RGBA8_OES;
|
| - *type = GL_UNSIGNED_BYTE; // unused I think
|
| -#else
|
| - // we promote index to argb32
|
| - *format = GL_RGBA;
|
| - *type = GL_UNSIGNED_BYTE;
|
| -#endif
|
| - break;
|
| - case SkBitmap::kA8_Config:
|
| - *format = GL_ALPHA;
|
| - *type = GL_UNSIGNED_BYTE;
|
| - break;
|
| - default:
|
| - return false;
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -#define SK_GL_SIZE_OF_PALETTE (256 * sizeof(SkPMColor))
|
| -
|
| -size_t SkGL::ComputeTextureMemorySize(const SkBitmap& bitmap) {
|
| - int shift = 0;
|
| - size_t adder = 0;
|
| - switch (bitmap.config()) {
|
| - case SkBitmap::kARGB_8888_Config:
|
| - case SkBitmap::kRGB_565_Config:
|
| - case SkBitmap::kARGB_4444_Config:
|
| - case SkBitmap::kA8_Config:
|
| - // we're good as is
|
| - break;
|
| - case SkBitmap::kIndex8_Config:
|
| -#ifdef SK_GL_SUPPORT_COMPRESSEDTEXIMAGE2D
|
| - // account for the colortable
|
| - adder = SK_GL_SIZE_OF_PALETTE;
|
| -#else
|
| - // we promote index to argb32
|
| - shift = 2;
|
| -#endif
|
| - break;
|
| - default:
|
| - return 0;
|
| - }
|
| - return (bitmap.getSize() << shift) + adder;
|
| -}
|
| -
|
| -#ifdef SK_GL_SUPPORT_COMPRESSEDTEXIMAGE2D
|
| -/* Fill out buffer with the compressed format GL expects from a colortable
|
| - based bitmap. [palette (colortable) + indices].
|
| -
|
| - At the moment I always take the 8bit version, since that's what my data
|
| - is. I could detect that the colortable.count is <= 16, and then repack the
|
| - indices as nibbles to save RAM, but it would take more time (i.e. a lot
|
| - slower than memcpy), so I'm skipping that for now.
|
| -
|
| - GL wants a full 256 palette entry, even though my ctable is only as big
|
| - as the colortable.count says it is. I presume it is OK to leave any
|
| - trailing entries uninitialized, since none of my indices should exceed
|
| - ctable->count().
|
| -*/
|
| -static void build_compressed_data(void* buffer, const SkBitmap& bitmap) {
|
| - SkASSERT(SkBitmap::kIndex8_Config == bitmap.config());
|
| -
|
| - SkColorTable* ctable = bitmap.getColorTable();
|
| - uint8_t* dst = (uint8_t*)buffer;
|
| -
|
| - memcpy(dst, ctable->lockColors(), ctable->count() * sizeof(SkPMColor));
|
| - ctable->unlockColors(false);
|
| -
|
| - // always skip a full 256 number of entries, even if we memcpy'd fewer
|
| - dst += SK_GL_SIZE_OF_PALETTE;
|
| - memcpy(dst, bitmap.getPixels(), bitmap.getSize());
|
| -}
|
| -#endif
|
| -
|
| -/* Return true if the bitmap cannot be supported in its current config as a
|
| - texture, and it needs to be promoted to ARGB32.
|
| - */
|
| -static bool needToPromoteTo32bit(const SkBitmap& bitmap) {
|
| - if (bitmap.config() == SkBitmap::kIndex8_Config) {
|
| -#ifdef SK_GL_SUPPORT_COMPRESSEDTEXIMAGE2D
|
| - const int w = bitmap.width();
|
| - const int h = bitmap.height();
|
| - if (SkNextPow2(w) == w && SkNextPow2(h) == h) {
|
| - // we can handle Indx8 if we're a POW2
|
| - return false;
|
| - }
|
| -#endif
|
| - return true; // must promote to ARGB32
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -GLuint SkGL::BindNewTexture(const SkBitmap& origBitmap, SkPoint* max) {
|
| - SkBitmap tmpBitmap;
|
| - const SkBitmap* bitmap = &origBitmap;
|
| -
|
| - if (needToPromoteTo32bit(origBitmap)) {
|
| - origBitmap.copyTo(&tmpBitmap, SkBitmap::kARGB_8888_Config);
|
| - // now bitmap points to our temp, which has been promoted to 32bits
|
| - bitmap = &tmpBitmap;
|
| - }
|
| -
|
| - GLenum format, type;
|
| - if (!canBeTexture(*bitmap, &format, &type)) {
|
| - return 0;
|
| - }
|
| -
|
| - SkAutoLockPixels alp(*bitmap);
|
| - if (!bitmap->readyToDraw()) {
|
| - return 0;
|
| - }
|
| -
|
| - GLuint textureName;
|
| - glGenTextures(1, &textureName);
|
| -
|
| - glBindTexture(GL_TEXTURE_2D, textureName);
|
| -
|
| - // express rowbytes as a number of pixels for ow
|
| - int ow = bitmap->rowBytesAsPixels();
|
| - int oh = bitmap->height();
|
| - int nw = SkNextPow2(ow);
|
| - int nh = SkNextPow2(oh);
|
| -
|
| - glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel());
|
| -
|
| - // check if we need to scale to create power-of-2 dimensions
|
| -#ifdef SK_GL_SUPPORT_COMPRESSEDTEXIMAGE2D
|
| - if (SkBitmap::kIndex8_Config == bitmap->config()) {
|
| - size_t imagesize = bitmap->getSize() + SK_GL_SIZE_OF_PALETTE;
|
| - SkAutoMalloc storage(imagesize);
|
| -
|
| - build_compressed_data(storage.get(), *bitmap);
|
| - // we only support POW2 here (GLES 1.0 restriction)
|
| - SkASSERT(ow == nw);
|
| - SkASSERT(oh == nh);
|
| - glCompressedTexImage2D(GL_TEXTURE_2D, 0, format, ow, oh, 0,
|
| - imagesize, storage.get());
|
| - } else // fall through to non-compressed logic
|
| -#endif
|
| - {
|
| - if (ow != nw || oh != nh) {
|
| - glTexImage2D(GL_TEXTURE_2D, 0, format, nw, nh, 0,
|
| - format, type, NULL);
|
| - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, ow, oh,
|
| - format, type, bitmap->getPixels());
|
| - } else {
|
| - // easy case, the bitmap is already pow2
|
| - glTexImage2D(GL_TEXTURE_2D, 0, format, ow, oh, 0,
|
| - format, type, bitmap->getPixels());
|
| - }
|
| - }
|
| -
|
| -#ifdef TRACE_TEXTURE_CREATION
|
| - SkDebugf("--- new texture [%d] size=(%d %d) bpp=%d\n", textureName, ow, oh,
|
| - bitmap->bytesPerPixel());
|
| -#endif
|
| -
|
| - if (max) {
|
| - max->fX = SkFixedToScalar(bitmap->width() << (16 - SkNextLog2(nw)));
|
| - max->fY = SkFixedToScalar(oh << (16 - SkNextLog2(nh)));
|
| - }
|
| - return textureName;
|
| -}
|
| -
|
| -static const GLenum gTileMode2GLWrap[] = {
|
| - GL_CLAMP_TO_EDGE,
|
| - GL_REPEAT,
|
| -#if GL_VERSION_ES_CM_1_0
|
| - GL_REPEAT // GLES doesn't support MIRROR
|
| -#else
|
| - GL_MIRRORED_REPEAT
|
| -#endif
|
| -};
|
| -
|
| -void SkGL::SetTexParams(bool doFilter,
|
| - SkShader::TileMode tx, SkShader::TileMode ty) {
|
| - SkASSERT((unsigned)tx < SK_ARRAY_COUNT(gTileMode2GLWrap));
|
| - SkASSERT((unsigned)ty < SK_ARRAY_COUNT(gTileMode2GLWrap));
|
| -
|
| - GLenum filter = doFilter ? GL_LINEAR : GL_NEAREST;
|
| -
|
| - SK_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
|
| - SK_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
|
| - SK_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gTileMode2GLWrap[tx]);
|
| - SK_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gTileMode2GLWrap[ty]);
|
| -}
|
| -
|
| -void SkGL::SetTexParamsClamp(bool doFilter) {
|
| - GLenum filter = doFilter ? GL_LINEAR : GL_NEAREST;
|
| -
|
| - SK_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
|
| - SK_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
|
| - SK_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
| - SK_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
| -}
|
| -
|
| -///////////////////////////////////////////////////////////////////////////////
|
| -
|
| -void SkGL::DrawVertices(int count, GLenum mode,
|
| - const SkGLVertex* SK_RESTRICT vertex,
|
| - const SkGLVertex* SK_RESTRICT texCoords,
|
| - const uint8_t* SK_RESTRICT colorArray,
|
| - const uint16_t* SK_RESTRICT indexArray,
|
| - SkGLClipIter* iter) {
|
| - SkASSERT(NULL != vertex);
|
| -
|
| - if (NULL != texCoords) {
|
| - glEnable(GL_TEXTURE_2D);
|
| - glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
| - glTexCoordPointer(2, SK_GLType, 0, texCoords);
|
| - } else {
|
| - glDisable(GL_TEXTURE_2D);
|
| - glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
| - }
|
| -
|
| - if (NULL != colorArray) {
|
| - glEnableClientState(GL_COLOR_ARRAY);
|
| - glColorPointer(4, GL_UNSIGNED_BYTE, 0, colorArray);
|
| - glShadeModel(GL_SMOOTH);
|
| - } else {
|
| - glDisableClientState(GL_COLOR_ARRAY);
|
| - glShadeModel(GL_FLAT);
|
| - }
|
| -
|
| - glVertexPointer(2, SK_GLType, 0, vertex);
|
| -
|
| - if (NULL != indexArray) {
|
| - if (iter) {
|
| - while (!iter->done()) {
|
| - iter->scissor();
|
| - glDrawElements(mode, count, GL_UNSIGNED_SHORT, indexArray);
|
| - iter->next();
|
| - }
|
| - } else {
|
| - glDrawElements(mode, count, GL_UNSIGNED_SHORT, indexArray);
|
| - }
|
| - } else {
|
| - if (iter) {
|
| - while (!iter->done()) {
|
| - iter->scissor();
|
| - glDrawArrays(mode, 0, count);
|
| - iter->next();
|
| - }
|
| - } else {
|
| - glDrawArrays(mode, 0, count);
|
| - }
|
| - }
|
| -}
|
| -
|
| -void SkGL::PrepareForFillPath(SkPaint* paint) {
|
| - if (paint->getStrokeWidth() <= 0) {
|
| - paint->setStrokeWidth(SK_Scalar1);
|
| - }
|
| -}
|
| -
|
| -void SkGL::FillPath(const SkPath& path, const SkPaint& paint, bool useTex,
|
| - SkGLClipIter* iter) {
|
| - SkPaint p(paint);
|
| - SkPath fillPath;
|
| -
|
| - SkGL::PrepareForFillPath(&p);
|
| - p.getFillPath(path, &fillPath);
|
| - SkGL::DrawPath(fillPath, useTex, iter);
|
| -}
|
| -
|
| -// should return max of all contours, rather than the sum (to save temp RAM)
|
| -static int worst_case_edge_count(const SkPath& path) {
|
| - int edgeCount = 0;
|
| -
|
| - SkPath::Iter iter(path, true);
|
| - SkPath::Verb verb;
|
| -
|
| - while ((verb = iter.next(NULL)) != SkPath::kDone_Verb) {
|
| - switch (verb) {
|
| - case SkPath::kLine_Verb:
|
| - edgeCount += 1;
|
| - break;
|
| - case SkPath::kQuad_Verb:
|
| - edgeCount += 8;
|
| - break;
|
| - case SkPath::kCubic_Verb:
|
| - edgeCount += 16;
|
| - break;
|
| - default:
|
| - break;
|
| - }
|
| - }
|
| - return edgeCount;
|
| -}
|
| -
|
| -void SkGL::DrawPath(const SkPath& path, bool useTex, SkGLClipIter* clipIter) {
|
| - SkRect bounds;
|
| -
|
| - path.computeBounds(&bounds, SkPath::kFast_BoundsType);
|
| - if (bounds.isEmpty()) {
|
| - return;
|
| - }
|
| -
|
| - int maxPts = worst_case_edge_count(path);
|
| - // add 1 for center of fan, and 1 for closing edge
|
| - SkAutoSTMalloc<32, SkGLVertex> storage(maxPts + 2);
|
| - SkGLVertex* base = storage.get();
|
| - SkGLVertex* vert = base;
|
| - SkGLVertex* texs = useTex ? base : NULL;
|
| -
|
| - SkPath::Iter pathIter(path, true);
|
| - SkPoint pts[4];
|
| -
|
| - bool needEnd = false;
|
| -
|
| - for (;;) {
|
| - switch (pathIter.next(pts)) {
|
| - case SkPath::kMove_Verb:
|
| - if (needEnd) {
|
| - SkGL::DrawVertices(vert - base, GL_TRIANGLE_FAN,
|
| - base, texs, NULL, NULL, clipIter);
|
| - clipIter->safeRewind();
|
| - vert = base;
|
| - }
|
| - needEnd = true;
|
| - // center of the FAN
|
| - vert->setScalars(bounds.centerX(), bounds.centerY());
|
| - vert++;
|
| - // add first edge point
|
| - vert->setPoint(pts[0]);
|
| - vert++;
|
| - break;
|
| - case SkPath::kLine_Verb:
|
| - vert->setPoint(pts[1]);
|
| - vert++;
|
| - break;
|
| - case SkPath::kQuad_Verb: {
|
| - const int n = 8;
|
| - const SkScalar dt = SK_Scalar1 / n;
|
| - SkScalar t = dt;
|
| - for (int i = 1; i < n; i++) {
|
| - SkPoint loc;
|
| - SkEvalQuadAt(pts, t, &loc, NULL);
|
| - t += dt;
|
| - vert->setPoint(loc);
|
| - vert++;
|
| - }
|
| - vert->setPoint(pts[2]);
|
| - vert++;
|
| - break;
|
| - }
|
| - case SkPath::kCubic_Verb: {
|
| - const int n = 16;
|
| - const SkScalar dt = SK_Scalar1 / n;
|
| - SkScalar t = dt;
|
| - for (int i = 1; i < n; i++) {
|
| - SkPoint loc;
|
| - SkEvalCubicAt(pts, t, &loc, NULL, NULL);
|
| - t += dt;
|
| - vert->setPoint(loc);
|
| - vert++;
|
| - }
|
| - vert->setPoint(pts[3]);
|
| - vert++;
|
| - break;
|
| - }
|
| - case SkPath::kClose_Verb:
|
| - break;
|
| - case SkPath::kDone_Verb:
|
| - goto FINISHED;
|
| - }
|
| - }
|
| -FINISHED:
|
| - if (needEnd) {
|
| - SkGL::DrawVertices(vert - base, GL_TRIANGLE_FAN, base, texs,
|
| - NULL, NULL, clipIter);
|
| - }
|
| -}
|
| -
|
|
|