Delete 'obsolete' directory, most of whose contents have been there more than a year.

git-svn-id: http://skia.googlecode.com/svn/trunk@3416 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
tomhudson@google.com 2012-03-16 17:16:25 +00:00
parent 022a3e1f3e
commit f97ef2f98e
16 changed files with 0 additions and 3372 deletions

View File

@ -1,533 +0,0 @@
/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#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];
sk_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.getSafeSize()); // Just copy what we need.
}
#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) {
const SkRect& bounds = path.getBounds();
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);
}
}

View File

@ -1,314 +0,0 @@
/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkGL_DEFINED
#define SkGL_DEFINED
#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_SDL)
#include <OpenGL/gl.h>
#include <OpenGL/glext.h>
#include <AGL/agl.h>
// use FBOs for devices
#define SK_GL_DEVICE_FBO
#elif defined(ANDROID)
#include <GLES/gl.h>
#include <EGL/egl.h>
#include <GLES/glext.h>
#endif
#include "SkColor.h"
#include "SkMatrix.h"
#include "SkShader.h"
class SkPaint;
class SkPath;
class SkGLClipIter;
//#define TRACE_TEXTURE_CREATE
static void SkGL_unimpl(const char str[]) {
SkDebugf("SkGL unimplemented: %s\n", str);
}
///////////////////////////////////////////////////////////////////////////////
#if GL_OES_compressed_paletted_texture
#define SK_GL_SUPPORT_COMPRESSEDTEXIMAGE2D
#endif
#if GL_OES_fixed_point && defined(SK_SCALAR_IS_FIXED)
#define SK_GLType GL_FIXED
#else
#define SK_GLType GL_FLOAT
#endif
#if SK_GLType == GL_FIXED
typedef SkFixed SkGLScalar;
#define SkIntToGL(n) SkIntToFixed(n)
#define SkScalarToGL(x) SkScalarToFixed(x)
#define SK_GLScalar1 SK_Fixed1
#define SkGLScalarMul(a, b) SkFixedMul(a, b)
#define MAKE_GL(name) name ## x
#ifdef SK_SCALAR_IS_FIXED
#define GLSCALAR_IS_SCALAR 1
#define SkPerspToGL(x) SkFractToFixed(x)
#else
#define GLSCALAR_IS_SCALAR 0
#define SkPerspToGL(x) SkFractToFloat(x)
#endif
#else
typedef float SkGLScalar;
#define SkIntToGL(n) (n)
#define SkScalarToGL(x) SkScalarToFloat(x)
#define SK_GLScalar1 (1.f)
#define SkGLScalarMul(a, b) ((a) * (b))
#define MAKE_GL(name) name ## f
#ifdef SK_SCALAR_IS_FLOAT
#define GLSCALAR_IS_SCALAR 1
#define SkPerspToGL(x) (x)
#else
#define GLSCALAR_IS_SCALAR 0
#define SkPerspToGL(x) SkFractToFloat(x)
#endif
#endif
#if GL_OES_fixed_point
typedef SkFixed SkGLTextScalar;
#define SK_TextGLType GL_FIXED
#define SkIntToTextGL(n) SkIntToFixed(n)
#define SkFixedToTextGL(x) (x)
#define SK_glTexParameteri(target, pname, param) \
glTexParameterx(target, pname, param)
#else
typedef float SkGLTextScalar;
#define SK_TextGLType SK_GLType
#define SK_GL_HAS_COLOR4UB
#define SkIntToTextGL(n) SkIntToGL(n)
#define SkFixedToTextGL(x) SkFixedToFloat(x)
#define SK_glTexParameteri(target, pname, param) \
glTexParameteri(target, pname, param)
#endif
///////////////////////////////////////////////////////////////////////////////
// text has its own vertex class, since it may want to be in fixed point (given)
// that it starts with all integers) even when the default vertices are floats
struct SkGLTextVertex {
SkGLTextScalar fX;
SkGLTextScalar fY;
void setI(int x, int y) {
fX = SkIntToTextGL(x);
fY = SkIntToTextGL(y);
}
void setX(SkFixed x, SkFixed y) {
fX = SkFixedToTextGL(x);
fY = SkFixedToTextGL(y);
}
// counter-clockwise fan
void setIRectFan(int l, int t, int r, int b) {
SkGLTextVertex* SK_RESTRICT v = this;
v[0].setI(l, t);
v[1].setI(l, b);
v[2].setI(r, b);
v[3].setI(r, t);
}
// counter-clockwise fan
void setXRectFan(SkFixed l, SkFixed t, SkFixed r, SkFixed b) {
SkGLTextVertex* SK_RESTRICT v = this;
v[0].setX(l, t);
v[1].setX(l, b);
v[2].setX(r, b);
v[3].setX(r, t);
}
};
struct SkGLVertex {
SkGLScalar fX;
SkGLScalar fY;
void setGL(SkGLScalar x, SkGLScalar y) {
fX = x;
fY = y;
}
void setScalars(SkScalar x, SkScalar y) {
fX = SkScalarToGL(x);
fY = SkScalarToGL(y);
}
void setPoint(const SkPoint& pt) {
fX = SkScalarToGL(pt.fX);
fY = SkScalarToGL(pt.fY);
}
void setPoints(const SkPoint* SK_RESTRICT pts, int count) {
const SkScalar* SK_RESTRICT src = (const SkScalar*)pts;
SkGLScalar* SK_RESTRICT dst = (SkGLScalar*)this;
for (int i = 0; i < count; i++) {
*dst++ = SkScalarToGL(*src++);
*dst++ = SkScalarToGL(*src++);
}
}
// counter-clockwise fan
void setRectFan(SkScalar l, SkScalar t, SkScalar r, SkScalar b) {
SkGLVertex* v = this;
v[0].setScalars(l, t);
v[1].setScalars(l, b);
v[2].setScalars(r, b);
v[3].setScalars(r, t);
}
// counter-clockwise fan
void setIRectFan(int l, int t, int r, int b) {
SkGLVertex* v = this;
v[0].setGL(SkIntToGL(l), SkIntToGL(t));
v[1].setGL(SkIntToGL(l), SkIntToGL(b));
v[2].setGL(SkIntToGL(r), SkIntToGL(b));
v[3].setGL(SkIntToGL(r), SkIntToGL(t));
}
// counter-clockwise fan
void setRectFan(const SkRect& r) {
this->setRectFan(r.fLeft, r.fTop, r.fRight, r.fBottom);
}
// counter-clockwise fan
void setIRectFan(const SkIRect& r) {
this->setIRectFan(r.fLeft, r.fTop, r.fRight, r.fBottom);
}
};
struct SkGLMatrix {
SkGLScalar fMat[16];
void reset() {
sk_bzero(fMat, sizeof(fMat));
fMat[0] = fMat[5] = fMat[10] = fMat[15] = SK_GLScalar1;
}
void set(const SkMatrix& m) {
sk_bzero(fMat, sizeof(fMat));
fMat[0] = SkScalarToGL(m[SkMatrix::kMScaleX]);
fMat[4] = SkScalarToGL(m[SkMatrix::kMSkewX]);
fMat[12] = SkScalarToGL(m[SkMatrix::kMTransX]);
fMat[1] = SkScalarToGL(m[SkMatrix::kMSkewY]);
fMat[5] = SkScalarToGL(m[SkMatrix::kMScaleY]);
fMat[13] = SkScalarToGL(m[SkMatrix::kMTransY]);
fMat[3] = SkPerspToGL(m[SkMatrix::kMPersp0]);
fMat[7] = SkPerspToGL(m[SkMatrix::kMPersp1]);
fMat[15] = SkPerspToGL(m[SkMatrix::kMPersp2]);
fMat[10] = SK_GLScalar1; // z-scale
}
};
class SkGL {
public:
static void SetColor(SkColor c);
static void SetAlpha(U8CPU alpha);
static void SetPaint(const SkPaint&, bool isPremul = true,
bool justAlpha = false);
static void SetPaintAlpha(const SkPaint& paint, bool isPremul = true) {
SetPaint(paint, isPremul, true);
}
static void SetRGBA(uint8_t rgba[], const SkColor src[], int count);
static void DumpError(const char caller[]);
static void Ortho(float left, float right, float bottom, float top,
float near, float far);
static inline void Translate(SkScalar dx, SkScalar dy) {
MAKE_GL(glTranslate)(SkScalarToGL(dx), SkScalarToGL(dy), 0);
}
static inline void Scale(SkScalar sx, SkScalar sy) {
MAKE_GL(glScale)(SkScalarToGL(sx), SkScalarToGL(sy), SK_GLScalar1);
}
static inline void Rotate(SkScalar angle) {
MAKE_GL(glRotate)(SkScalarToGL(angle), 0, 0, SK_GLScalar1);
}
static inline void MultMatrix(const SkMatrix& m) {
SkGLMatrix glm;
glm.set(m);
MAKE_GL(glMultMatrix)(glm.fMat);
}
static inline void LoadMatrix(const SkMatrix& m) {
SkGLMatrix glm;
glm.set(m);
MAKE_GL(glLoadMatrix)(glm.fMat);
}
static void Scissor(const SkIRect&, int viewportHeight);
// return the byte size for the associated texture memory. This doesn't
// always == bitmap.getSize(), since on a given port we may have to change
// the format when the bitmap's pixels are copied over to GL
static size_t ComputeTextureMemorySize(const SkBitmap&);
// return 0 on failure
static GLuint BindNewTexture(const SkBitmap&, SkPoint* dimension);
static void SetTexParams(bool filter,
SkShader::TileMode tx, SkShader::TileMode ty);
static void SetTexParamsClamp(bool filter);
static void 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*);
static void PrepareForFillPath(SkPaint* paint);
static void FillPath(const SkPath& path, const SkPaint& paint, bool useTex,
SkGLClipIter*);
static void DrawPath(const SkPath& path, bool useTex, SkGLClipIter*);
};
#include "SkRegion.h"
class SkGLClipIter : public SkRegion::Iterator {
public:
SkGLClipIter(int viewportHeight) : fViewportHeight(viewportHeight) {}
// call rewind only if this is non-null
void safeRewind() {
if (this) {
this->rewind();
}
}
void scissor() {
SkASSERT(!this->done());
SkGL::Scissor(this->rect(), fViewportHeight);
}
private:
const int fViewportHeight;
};
#endif

View File

@ -1,43 +0,0 @@
/*
* Copyright 2010 The Android Open Source Project
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkGLCanvas.h"
#include "SkGLDevice.h"
SkGLCanvas::SkGLCanvas() : SkCanvas(SkNEW(SkGLDeviceFactory)) {}
// static
size_t SkGLCanvas::GetTextureCacheMaxCount() {
return SkGLDevice::GetTextureCacheMaxCount();
}
// static
void SkGLCanvas::SetTextureCacheMaxCount(size_t count) {
SkGLDevice::SetTextureCacheMaxCount(count);
}
// static
size_t SkGLCanvas::GetTextureCacheMaxSize() {
return SkGLDevice::GetTextureCacheMaxSize();
}
// static
void SkGLCanvas::SetTextureCacheMaxSize(size_t size) {
SkGLDevice::SetTextureCacheMaxSize(size);
}
// static
void SkGLCanvas::DeleteAllTextures() {
SkGLDevice::DeleteAllTextures();
}
// static
void SkGLCanvas::AbandonAllTextures() {
SkGLDevice::AbandonAllTextures();
}

View File

@ -1,32 +0,0 @@
/*
* Copyright 2010 The Android Open Source Project
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkGLCanvas_DEFINED
#define SkGLCanvas_DEFINED
#include "SkCanvas.h"
// Deprecated. You should now use SkGLDevice and SkGLDeviceFactory with
// SkCanvas.
class SkGLCanvas : public SkCanvas {
public:
SkGLCanvas();
static size_t GetTextureCacheMaxCount();
static void SetTextureCacheMaxCount(size_t count);
static size_t GetTextureCacheMaxSize();
static void SetTextureCacheMaxSize(size_t size);
static void DeleteAllTextures();
static void AbandonAllTextures();
};
#endif

View File

@ -1,960 +0,0 @@
/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkGLDevice.h"
#include "SkGL.h"
#include "SkDrawProcs.h"
#include "SkRegion.h"
#include "SkThread.h"
#ifdef SK_GL_DEVICE_FBO
#define USE_FBO_DEVICE
#include "SkGLDevice_FBO.h"
#else
#define USE_SWLAYER_DEVICE
#include "SkGLDevice_SWLayer.h"
#endif
// maximum number of entries in our texture cache (before purging)
#define kTexCountMax_Default 256
// maximum number of bytes used (by gl) for the texture cache (before purging)
#define kTexSizeMax_Default (4 * 1024 * 1024)
static void TRACE_DRAW(const char func[], SkGLDevice* device,
const SkDraw& draw) {
// SkDebugf("--- <%s> %p %p\n", func, canvas, draw.fDevice);
}
struct SkGLDrawProcs : public SkDrawProcs {
public:
void init(const SkRegion* clip, int height) {
fCurrQuad = 0;
fCurrTexture = 0;
fClip = clip;
fViewportHeight = height;
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, SK_TextGLType, 0, fTexs);
glDisableClientState(GL_COLOR_ARRAY);
glVertexPointer(2, SK_TextGLType, 0, fVerts);
}
GLenum texture() const { return fCurrTexture; }
void flush() {
if (fCurrQuad && fCurrTexture) {
this->drawQuads();
}
fCurrQuad = 0;
}
void addQuad(GLuint texture, int x, int y, const SkGlyph& glyph,
SkFixed left, SkFixed right, SkFixed bottom) {
SkASSERT((size_t)fCurrQuad <= SK_ARRAY_COUNT(fVerts));
if (fCurrTexture != texture || fCurrQuad == SK_ARRAY_COUNT(fVerts)) {
if (fCurrQuad && fCurrTexture) {
this->drawQuads();
}
fCurrQuad = 0;
fCurrTexture = texture;
}
fVerts[fCurrQuad].setIRectFan(x, y,
x + glyph.fWidth, y + glyph.fHeight);
fTexs[fCurrQuad].setXRectFan(left, 0, right, bottom);
fCurrQuad += 4;
}
void drawQuads();
private:
enum {
MAX_QUADS = 32
};
SkGLTextVertex fVerts[MAX_QUADS * 4];
SkGLTextVertex fTexs[MAX_QUADS * 4];
// these are initialized in setupForText
GLuint fCurrTexture;
int fCurrQuad;
int fViewportHeight;
const SkRegion* fClip;
};
///////////////////////////////////////////////////////////////////////////////
SkDevice* SkGLDeviceFactory::newDevice(SkBitmap::Config config, int width,
int height, bool isOpaque,
bool isForLayer) {
SkBitmap bitmap;
bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
bitmap.setIsOpaque(isOpaque);
#ifdef USE_FBO_DEVICE
return SkNEW_ARGS(SkGLDevice_FBO, (bitmap, isForLayer));
#elif defined(USE_SWLAYER_DEVICE)
if (isForLayer) {
bitmap.allocPixels();
if (!bitmap.isOpaque()) {
bitmap.eraseColor(0);
}
return SkNEW_ARGS(SkGLDevice_SWLayer, (bitmap));
} else {
return SkNEW_ARGS(SkGLDevice, (bitmap, isForLayer));
}
#else
return SkNEW_ARGS(SkGLDevice, (bitmap, isForLayer));
#endif
}
SkGLDevice::SkGLDevice(const SkBitmap& bitmap, bool offscreen)
: SkDevice(bitmap), fClipIter(bitmap.height()) {
glEnable(GL_TEXTURE_2D);
glEnable(GL_SCISSOR_TEST);
glEnableClientState(GL_VERTEX_ARRAY);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
fDrawProcs = NULL;
}
SkGLDevice::~SkGLDevice() {
if (fDrawProcs) {
SkDELETE(fDrawProcs);
}
}
void SkGLDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& clip) {
this->INHERITED::setMatrixClip(matrix, clip);
fGLMatrix.set(matrix);
fMatrix = matrix;
fClip = clip;
fDirty = true;
}
SkGLDevice::TexOrientation SkGLDevice::bindDeviceAsTexture() {
return kNo_TexOrientation;
}
void SkGLDevice::gainFocus(SkCanvas* canvas) {
this->INHERITED::gainFocus(canvas);
const int w = this->width();
const int h = this->height();
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
SkGL::Ortho(0, w, h, 0, -1, 1);
glMatrixMode(GL_MODELVIEW);
fDirty = true;
}
SkGLClipIter* SkGLDevice::updateMatrixClip() {
bool useIter = false;
// first handle the clip
if (fDirty || !fClip.isRect()) {
fClipIter.reset(fClip);
useIter = true;
} else if (fDirty) {
// no iter means caller is not respecting complex clips :(
SkGL::Scissor(fClip.getBounds(), this->height());
}
// else we're just a rect, and we've already call scissor
// now handle the matrix
if (fDirty) {
MAKE_GL(glLoadMatrix)(fGLMatrix.fMat);
#if 0
SkDebugf("--- gldevice update matrix %p %p\n", this, fFBO);
for (int y = 0; y < 4; y++) {
SkDebugf(" [ ");
for (int x = 0; x < 4; x++) {
SkDebugf("%g ", fGLMatrix.fMat[y*4 + x]);
}
SkDebugf("]\n");
}
#endif
fDirty = false;
}
return useIter ? &fClipIter : NULL;
}
///////////////////////////////////////////////////////////////////////////////
// must be in the same order as SkXfermode::Coeff in SkXfermode.h
SkGLDevice::AutoPaintShader::AutoPaintShader(SkGLDevice* device,
const SkPaint& paint) {
fDevice = device;
fTexCache = device->setupGLPaintShader(paint);
}
SkGLDevice::AutoPaintShader::~AutoPaintShader() {
if (fTexCache) {
SkGLDevice::UnlockTexCache(fTexCache);
}
}
SkGLDevice::TexCache* SkGLDevice::setupGLPaintShader(const SkPaint& paint) {
SkGL::SetPaint(paint);
SkShader* shader = paint.getShader();
if (NULL == shader) {
return NULL;
}
if (!shader->setContext(this->accessBitmap(false), paint, this->matrix())) {
return NULL;
}
SkBitmap bitmap;
SkMatrix matrix;
SkShader::TileMode tileModes[2];
if (!shader->asABitmap(&bitmap, &matrix, tileModes)) {
SkGL_unimpl("shader->asABitmap() == false");
return NULL;
}
bitmap.lockPixels();
if (!bitmap.readyToDraw()) {
return NULL;
}
// see if we've already cached the bitmap from the shader
SkPoint max;
GLuint name;
TexCache* cache = SkGLDevice::LockTexCache(bitmap, &name, &max);
// the lock has already called glBindTexture for us
SkGL::SetTexParams(paint.isFilterBitmap(), tileModes[0], tileModes[1]);
// since our texture coords will be in local space, we wack the texture
// matrix to map them back into 0...1 before we load it
SkMatrix localM;
if (shader->getLocalMatrix(&localM)) {
SkMatrix inverse;
if (localM.invert(&inverse)) {
matrix.preConcat(inverse);
}
}
matrix.postScale(max.fX / bitmap.width(), max.fY / bitmap.height());
glMatrixMode(GL_TEXTURE);
SkGL::LoadMatrix(matrix);
glMatrixMode(GL_MODELVIEW);
// since we're going to use a shader/texture, we don't want the color,
// just its alpha
SkGL::SetAlpha(paint.getAlpha());
// report that we have setup the texture
return cache;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void SkGLDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
TRACE_DRAW("coreDrawPaint", this, draw);
AutoPaintShader shader(this, paint);
SkGLVertex vertex[4];
const SkGLVertex* texs = shader.useTex() ? vertex : NULL;
// set vert to be big enough to fill the space, but not super-huge, to we
// don't overflow fixed-point implementations
{
SkRect r;
r.set(this->clip().getBounds());
SkMatrix inverse;
if (draw.fMatrix->invert(&inverse)) {
inverse.mapRect(&r);
}
vertex->setRectFan(r);
}
SkGL::DrawVertices(4, GL_TRIANGLE_FAN, vertex, texs, NULL, NULL,
this->updateMatrixClip());
}
// must be in SkCanvas::PointMode order
static const GLenum gPointMode2GL[] = {
GL_POINTS,
GL_LINES,
GL_LINE_STRIP
};
void SkGLDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
size_t count, const SkPoint pts[], const SkPaint& paint) {
TRACE_DRAW("coreDrawPoints", this, draw);
SkScalar width = paint.getStrokeWidth();
if (width < 0) {
return;
}
/* We should really only use drawverts for hairlines, since gl and skia
treat the thickness differently...
*/
AutoPaintShader shader(this, paint);
if (width <= 0) {
width = SK_Scalar1;
}
if (SkCanvas::kPoints_PointMode == mode) {
glPointSize(SkScalarToFloat(width));
} else {
glLineWidth(SkScalarToFloat(width));
}
const SkGLVertex* verts;
#if GLSCALAR_IS_SCALAR
verts = (const SkGLVertex*)pts;
#else
SkAutoSTMalloc<32, SkGLVertex> storage(count);
SkGLVertex* v = storage.get();
v->setPoints(pts, count);
verts = v;
#endif
const SkGLVertex* texs = shader.useTex() ? verts : NULL;
SkGL::DrawVertices(count, gPointMode2GL[mode], verts, texs, NULL, NULL,
this->updateMatrixClip());
}
/* create a triangle strip that strokes the specified triangle. There are 8
unique vertices, but we repreat the last 2 to close up. Alternatively we
could use an indices array, and then only send 8 verts, but not sure that
would be faster.
*/
static void setStrokeRectStrip(SkGLVertex verts[10], const SkRect& rect,
SkScalar width) {
const SkScalar rad = SkScalarHalf(width);
verts[0].setScalars(rect.fLeft + rad, rect.fTop + rad);
verts[1].setScalars(rect.fLeft - rad, rect.fTop - rad);
verts[2].setScalars(rect.fRight - rad, rect.fTop + rad);
verts[3].setScalars(rect.fRight + rad, rect.fTop - rad);
verts[4].setScalars(rect.fRight - rad, rect.fBottom - rad);
verts[5].setScalars(rect.fRight + rad, rect.fBottom + rad);
verts[6].setScalars(rect.fLeft + rad, rect.fBottom - rad);
verts[7].setScalars(rect.fLeft - rad, rect.fBottom + rad);
verts[8] = verts[0];
verts[9] = verts[1];
}
void SkGLDevice::drawRect(const SkDraw& draw, const SkRect& rect,
const SkPaint& paint) {
TRACE_DRAW("coreDrawRect", this, draw);
bool doStroke = paint.getStyle() == SkPaint::kStroke_Style;
if (doStroke) {
if (paint.getStrokeJoin() != SkPaint::kMiter_Join) {
SkGL_unimpl("non-miter stroke rect");
return;
}
} else if (paint.getStrokeJoin() != SkPaint::kMiter_Join) {
SkPath path;
path.addRect(rect);
this->drawPath(draw, path, paint);
return;
}
AutoPaintShader shader(this, paint);
SkScalar width = paint.getStrokeWidth();
SkGLVertex vertex[10]; // max needed for all cases
int vertCount;
GLenum vertMode;
if (doStroke) {
if (width > 0) {
vertCount = 10;
vertMode = GL_TRIANGLE_STRIP;
setStrokeRectStrip(vertex, rect, width);
} else { // hairline
vertCount = 5;
vertMode = GL_LINE_STRIP;
vertex[0].setScalars(rect.fLeft, rect.fTop);
vertex[1].setScalars(rect.fRight, rect.fTop);
vertex[2].setScalars(rect.fRight, rect.fBottom);
vertex[3].setScalars(rect.fLeft, rect.fBottom);
vertex[4].setScalars(rect.fLeft, rect.fTop);
glLineWidth(1);
}
} else {
vertCount = 4;
vertMode = GL_TRIANGLE_FAN;
vertex->setRectFan(rect);
}
const SkGLVertex* texs = shader.useTex() ? vertex : NULL;
SkGL::DrawVertices(vertCount, vertMode, vertex, texs, NULL, NULL,
this->updateMatrixClip());
}
void SkGLDevice::drawPath(const SkDraw& draw, const SkPath& path,
const SkPaint& paint) {
TRACE_DRAW("coreDrawPath", this, draw);
if (paint.getStyle() == SkPaint::kStroke_Style) {
SkGL_unimpl("stroke path");
return;
}
AutoPaintShader shader(this, paint);
SkGL::FillPath(path, paint, shader.useTex(), this->updateMatrixClip());
}
void SkGLDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
const SkMatrix& m, const SkPaint& paint) {
TRACE_DRAW("coreDrawBitmap", this, draw);
SkAutoLockPixels alp(bitmap);
if (!bitmap.readyToDraw()) {
return;
}
SkGLClipIter* iter = this->updateMatrixClip();
SkPoint max;
GLenum name;
SkAutoLockTexCache(bitmap, &name, &max);
// the lock has already called glBindTexture for us
SkGL::SetTexParamsClamp(paint.isFilterBitmap());
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
SkGL::MultMatrix(m);
SkGLVertex pts[4], tex[4];
pts->setIRectFan(0, 0, bitmap.width(), bitmap.height());
tex->setRectFan(0, 0, max.fX, max.fY);
// now draw the mesh
SkGL::SetPaintAlpha(paint);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
SkGL::DrawVertices(4, GL_TRIANGLE_FAN, pts, tex, NULL, NULL, iter);
glPopMatrix();
}
// move this guy into SkGL, so we can call it from SkGLDevice
static void gl_drawSprite(int x, int y, int w, int h, const SkPoint& max,
const SkPaint& paint, SkGLClipIter* iter) {
SkGL::SetTexParamsClamp(false);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
SkGLVertex pts[4], tex[4];
// if h < 0, then the texture is bottom-to-top, but since our projection
// matrix always inverts Y, we have to re-invert our texture coord here
if (h < 0) {
h = -h;
tex->setRectFan(0, max.fY, max.fX, 0);
} else {
tex->setRectFan(0, 0, max.fX, max.fY);
}
pts->setIRectFan(x, y, x + w, y + h);
SkGL::SetPaintAlpha(paint);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
// should look to use glDrawTexi() has we do for text...
SkGL::DrawVertices(4, GL_TRIANGLE_FAN, pts, tex, NULL, NULL, iter);
glPopMatrix();
}
void SkGLDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
int left, int top, const SkPaint& paint) {
TRACE_DRAW("coreDrawSprite", this, draw);
SkAutoLockPixels alp(bitmap);
if (!bitmap.readyToDraw()) {
return;
}
SkGLClipIter* iter = this->updateMatrixClip();
SkPoint max;
GLuint name;
SkAutoLockTexCache(bitmap, &name, &max);
gl_drawSprite(left, top, bitmap.width(), bitmap.height(), max, paint, iter);
}
void SkGLDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
int x, int y, const SkPaint& paint) {
TRACE_DRAW("coreDrawDevice", this, draw);
SkGLDevice::TexOrientation to = ((SkGLDevice*)dev)->bindDeviceAsTexture();
if (SkGLDevice::kNo_TexOrientation != to) {
SkGLClipIter* iter = this->updateMatrixClip();
const SkBitmap& bm = dev->accessBitmap(false);
int w = bm.width();
int h = bm.height();
SkPoint max;
max.set(SkFixedToScalar(w << (16 - SkNextLog2(bm.rowBytesAsPixels()))),
SkFixedToScalar(h << (16 - SkNextLog2(h))));
if (SkGLDevice::kBottomToTop_TexOrientation == to) {
h = -h;
}
gl_drawSprite(x, y, w, h, max, paint, iter);
}
}
///////////////////////////////////////////////////////////////////////////////
static const GLenum gVertexModeToGL[] = {
GL_TRIANGLES, // kTriangles_VertexMode,
GL_TRIANGLE_STRIP, // kTriangleStrip_VertexMode,
GL_TRIANGLE_FAN // kTriangleFan_VertexMode
};
#include "SkShader.h"
void SkGLDevice::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) {
if (false) {
SkRect bounds;
SkIRect ibounds;
bounds.set(vertices, vertexCount);
bounds.round(&ibounds);
SkDebugf("---- drawverts: %d pts, texs=%d colors=%d indices=%d bounds [%d %d]\n",
vertexCount, texs!=0, colors!=0, indexCount, ibounds.width(), ibounds.height());
}
SkGLClipIter* iter = this->updateMatrixClip();
SkGL::SetPaint(paint);
const SkGLVertex* glVerts;
const SkGLVertex* glTexs = NULL;
#if GLSCALAR_IS_SCALAR
glVerts = (const SkGLVertex*)vertices;
#else
SkAutoSTMalloc<32, SkGLVertex> storage(vertexCount);
storage.get()->setPoints(vertices, vertexCount);
glVerts = storage.get();
#endif
uint8_t* colorArray = NULL;
if (colors) {
colorArray = (uint8_t*)sk_malloc_throw(vertexCount*4);
SkGL::SetRGBA(colorArray, colors, vertexCount);
}
SkAutoFree afca(colorArray);
SkGLVertex* texArray = NULL;
TexCache* cache = NULL;
if (texs && paint.getShader()) {
SkShader* shader = paint.getShader();
// if (!shader->setContext(this->accessBitmap(), paint, *draw.fMatrix)) {
if (!shader->setContext(*draw.fBitmap, paint, *draw.fMatrix)) {
goto DONE;
}
SkBitmap bitmap;
SkMatrix matrix;
SkShader::TileMode tileModes[2];
if (shader->asABitmap(&bitmap, &matrix, tileModes)) {
SkPoint max;
GLuint name;
cache = SkGLDevice::LockTexCache(bitmap, &name, &max);
if (NULL == cache) {
return;
}
matrix.postScale(max.fX / bitmap.width(), max.fY / bitmap.height());
glMatrixMode(GL_TEXTURE);
SkGL::LoadMatrix(matrix);
glMatrixMode(GL_MODELVIEW);
#if GLSCALAR_IS_SCALAR
glTexs = (const SkGLVertex*)texs;
#else
texArray = (SkGLVertex*)sk_malloc_throw(vertexCount * sizeof(SkGLVertex));
texArray->setPoints(texs, vertexCount);
glTexs = texArray;
#endif
SkGL::SetPaintAlpha(paint);
SkGL::SetTexParams(paint.isFilterBitmap(),
tileModes[0], tileModes[1]);
}
}
DONE:
SkAutoFree aftex(texArray);
SkGL::DrawVertices(indices ? indexCount : vertexCount,
gVertexModeToGL[vmode],
glVerts, glTexs, colorArray, indices, iter);
if (cache) {
SkGLDevice::UnlockTexCache(cache);
}
}
///////////////////////////////////////////////////////////////////////////////
#include "SkGlyphCache.h"
#include "SkGLTextCache.h"
void SkGLDevice::GlyphCacheAuxProc(void* data) {
SkDebugf("-------------- delete text texture cache\n");
SkDELETE((SkGLTextCache*)data);
}
#ifdef SK_SCALAR_IS_FIXED
#define SkDiv16ToScalar(numer, denom) (SkIntToFixed(numer) / (denom))
#else
#define SkDiv16ToScalar(numer, denom) SkScalarDiv(numer, denom)
#endif
// stolen from SkDraw.cpp - D1G_NoBounder_RectClip
static void SkGL_Draw1Glyph(const SkDraw1Glyph& state, const SkGlyph& glyph,
int x, int y) {
SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
SkGLDrawProcs* procs = (SkGLDrawProcs*)state.fDraw->fProcs;
x += glyph.fLeft;
y += glyph.fTop;
// check if we're clipped out (nothing to draw)
SkIRect bounds;
bounds.set(x, y, x + glyph.fWidth, y + glyph.fHeight);
if (!SkIRect::Intersects(state.fClip->getBounds(), bounds)) {
return;
}
// now dig up our texture cache
SkGlyphCache* gcache = state.fCache;
void* auxData;
SkGLTextCache* textCache = NULL;
if (gcache->getAuxProcData(SkGLDevice::GlyphCacheAuxProc, &auxData)) {
textCache = (SkGLTextCache*)auxData;
}
if (NULL == textCache) {
// need to create one
textCache = SkNEW(SkGLTextCache);
gcache->setAuxProc(SkGLDevice::GlyphCacheAuxProc, textCache);
}
int offset;
SkGLTextCache::Strike* strike = textCache->findGlyph(glyph, &offset);
if (NULL == strike) {
// make sure the glyph has an image
uint8_t* aa = (uint8_t*)glyph.fImage;
if (NULL == aa) {
aa = (uint8_t*)gcache->findImage(glyph);
if (NULL == aa) {
return; // can't rasterize glyph
}
}
strike = textCache->addGlyphAndBind(glyph, aa, &offset);
if (NULL == strike) {
SkGL_unimpl("addGlyphAndBind failed, too big");
// too big to cache, need to draw as is...
return;
}
}
const int shiftW = strike->widthShift();
const int shiftH = strike->heightShift();
SkFixed left = offset << (16 - shiftW);
SkFixed right = (offset + glyph.fWidth) << (16 - shiftW);
SkFixed bottom = glyph.fHeight << (16 - shiftH);
procs->addQuad(strike->texture(), x, y, glyph, left, right, bottom);
}
#if 1
// matches the orientation used in SkGL::setRectFan. Too bad we can't rely on
// QUADS in android's GL
static const uint8_t gQuadIndices[] = {
0, 1, 2, 0, 2, 3,
4, 5, 6, 4, 6, 7,
8, 9, 10, 8, 10, 11,
12, 13, 14, 12, 14, 15,
16, 17, 18, 16, 18, 19,
20, 21, 22, 20, 22, 23,
24, 25, 26, 24, 26, 27,
28, 29, 30, 28, 30, 31,
32, 33, 34, 32, 34, 35,
36, 37, 38, 36, 38, 39,
40, 41, 42, 40, 42, 43,
44, 45, 46, 44, 46, 47,
48, 49, 50, 48, 50, 51,
52, 53, 54, 52, 54, 55,
56, 57, 58, 56, 58, 59,
60, 61, 62, 60, 62, 63,
64, 65, 66, 64, 66, 67,
68, 69, 70, 68, 70, 71,
72, 73, 74, 72, 74, 75,
76, 77, 78, 76, 78, 79,
80, 81, 82, 80, 82, 83,
84, 85, 86, 84, 86, 87,
88, 89, 90, 88, 90, 91,
92, 93, 94, 92, 94, 95,
96, 97, 98, 96, 98, 99,
100, 101, 102, 100, 102, 103,
104, 105, 106, 104, 106, 107,
108, 109, 110, 108, 110, 111,
112, 113, 114, 112, 114, 115,
116, 117, 118, 116, 118, 119,
120, 121, 122, 120, 122, 123,
124, 125, 126, 124, 126, 127
};
#else
static void generateQuadIndices(int n) {
int index = 0;
for (int i = 0; i < n; i++) {
SkDebugf(" %3d, %3d, %3d, %3d, %3d, %3d,\n",
index, index + 1, index + 2, index, index + 2, index + 3);
index += 4;
}
}
#endif
void SkGLDrawProcs::drawQuads() {
SkASSERT(SK_ARRAY_COUNT(gQuadIndices) == MAX_QUADS * 6);
glBindTexture(GL_TEXTURE_2D, fCurrTexture);
#if 0
static bool gOnce;
if (!gOnce) {
generateQuadIndices(MAX_QUADS);
gOnce = true;
}
#endif
// convert from quad vertex count to triangle vertex count
// 6/4 * n == n + (n >> 1) since n is always a multiple of 4
SkASSERT((fCurrQuad & 3) == 0);
int count = fCurrQuad + (fCurrQuad >> 1);
if (fClip->isComplex()) {
SkGLClipIter iter(fViewportHeight);
iter.reset(*fClip);
while (!iter.done()) {
iter.scissor();
glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_BYTE, gQuadIndices);
iter.next();
}
} else {
glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_BYTE, gQuadIndices);
}
}
void SkGLDevice::setupForText(SkDraw* draw, const SkPaint& paint) {
// we handle complex clips in the SkDraw common code, so we don't check
// for it here
this->updateMatrixClip();
SkGL::SetPaint(paint, false);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
// deferred allocation
if (NULL == fDrawProcs) {
fDrawProcs = SkNEW(SkGLDrawProcs);
fDrawProcs->fD1GProc = SkGL_Draw1Glyph;
}
// init our (and GL's) state
fDrawProcs->init(draw->fClip, this->height());
// assign to the caller's SkDraw
draw->fProcs = fDrawProcs;
glEnable(GL_TEXTURE_2D);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glShadeModel(GL_FLAT);
}
void SkGLDevice::drawText(const SkDraw& draw, const void* text,
size_t byteLength, SkScalar x, SkScalar y,
const SkPaint& paint) {
/* Currently, perspective text is draw via paths, invoked directly by
SkDraw. This can't work for us, since the bitmap that our draw points
to has no pixels, so we just abort if we're in perspective.
Better fix would be to...
- have a callback inside draw to handle path drawing
- option to have draw call the font cache, which we could patch (?)
*/
if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
SkGL_unimpl("drawText in perspective");
return;
}
SkDraw myDraw(draw);
this->setupForText(&myDraw, paint);
this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
fDrawProcs->flush();
glPopMatrix(); // GL_MODELVIEW
}
void SkGLDevice::drawPosText(const SkDraw& draw, const void* text,
size_t byteLength, const SkScalar pos[],
SkScalar constY, int scalarsPerPos,
const SkPaint& paint) {
if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
SkGL_unimpl("drawPosText in perspective");
return;
}
SkDraw myDraw(draw);
this->setupForText(&myDraw, paint);
this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
scalarsPerPos, paint);
fDrawProcs->flush();
glPopMatrix(); // GL_MODELVIEW
}
void SkGLDevice::drawTextOnPath(const SkDraw& draw, const void* text,
size_t byteLength, const SkPath& path,
const SkMatrix* m, const SkPaint& paint) {
SkGL_unimpl("drawTextOnPath");
}
///////////////////////////////////////////////////////////////////////////////
#include "SkTextureCache.h"
#include "SkThread.h"
SK_DECLARE_STATIC_MUTEX(gTextureCacheMutex);
static SkTextureCache gTextureCache(kTexCountMax_Default, kTexSizeMax_Default);
SkGLDevice::TexCache* SkGLDevice::LockTexCache(const SkBitmap& bitmap,
GLuint* name, SkPoint* size) {
SkAutoMutexAcquire amc(gTextureCacheMutex);
SkTextureCache::Entry* entry = gTextureCache.lock(bitmap);
if (NULL != entry) {
if (name) {
*name = entry->name();
}
if (size) {
*size = entry->texSize();
}
}
return (TexCache*)entry;
}
void SkGLDevice::UnlockTexCache(TexCache* cache) {
SkAutoMutexAcquire amc(gTextureCacheMutex);
gTextureCache.unlock((SkTextureCache::Entry*)cache);
}
// public exposure of texture cache settings
size_t SkGLDevice::GetTextureCacheMaxCount() {
SkAutoMutexAcquire amc(gTextureCacheMutex);
return gTextureCache.getMaxCount();
}
size_t SkGLDevice::GetTextureCacheMaxSize() {
SkAutoMutexAcquire amc(gTextureCacheMutex);
return gTextureCache.getMaxSize();
}
void SkGLDevice::SetTextureCacheMaxCount(size_t count) {
SkAutoMutexAcquire amc(gTextureCacheMutex);
gTextureCache.setMaxCount(count);
}
void SkGLDevice::SetTextureCacheMaxSize(size_t size) {
SkAutoMutexAcquire amc(gTextureCacheMutex);
gTextureCache.setMaxSize(size);
}
///////////////////////////////////////////////////////////////////////////////
#include "SkGLTextCache.h"
static bool deleteCachesProc(SkGlyphCache* cache, void* texturesAreValid) {
void* auxData;
if (cache->getAuxProcData(SkGLDevice::GlyphCacheAuxProc, &auxData)) {
bool valid = texturesAreValid != NULL;
SkGLTextCache* textCache = static_cast<SkGLTextCache*>(auxData);
// call this before delete, in case valid is false
textCache->deleteAllStrikes(valid);
// now free the memory for the cache itself
SkDELETE(textCache);
// now remove the entry in the glyphcache (does not call the proc)
cache->removeAuxProc(SkGLDevice::GlyphCacheAuxProc);
}
return false; // keep going
}
void SkGLDevice::DeleteAllTextures() {
// free the textures in our cache
gTextureCacheMutex.acquire();
gTextureCache.deleteAllCaches(true);
gTextureCacheMutex.release();
// now free the textures in the font cache
SkGlyphCache::VisitAllCaches(deleteCachesProc, reinterpret_cast<void*>(true)
);
}
void SkGLDevice::AbandonAllTextures() {
// abandon the textures in our cache
gTextureCacheMutex.acquire();
gTextureCache.deleteAllCaches(false);
gTextureCacheMutex.release();
// abandon the textures in the font cache
SkGlyphCache::VisitAllCaches(deleteCachesProc, reinterpret_cast<void*>(false
));
}

View File

@ -1,170 +0,0 @@
/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkGLDevice_DEFINED
#define SkGLDevice_DEFINED
#include "SkDevice.h"
#include "SkGL.h"
#include "SkRegion.h"
#ifdef SK_BUILD_FOR_MAC
#include <OpenGL/gl.h>
#elif defined(ANDROID)
#include <GLES/gl.h>
#endif
class SkGLDeviceFactory : public SkDeviceFactory {
public:
virtual SkDevice* newDevice(SkBitmap::Config config, int width, int height,
bool isOpaque, bool isForLayer);
};
struct SkGLDrawProcs;
class SkGLDevice : public SkDevice {
public:
SkGLDevice(const SkBitmap& bitmap, bool offscreen);
virtual ~SkGLDevice();
virtual SkDeviceFactory* getDeviceFactory() {
return SkNEW(SkGLDeviceFactory);
}
virtual uint32_t getDeviceCapabilities() { return kGL_Capability; }
// used to identify GLTextCache data in the glyphcache
static void GlyphCacheAuxProc(void* data);
enum TexOrientation {
kNo_TexOrientation,
kTopToBottom_TexOrientation,
kBottomToTop_TexOrientation
};
/** Called when this device is no longer a candidate for a render target,
but will instead be used as a texture to be drawn. Be sure to call
the base impl if you override, as it will compute size and max.
*/
virtual TexOrientation bindDeviceAsTexture();
// returns true if complex
SkGLClipIter* updateMatrixClip();
// call to set the clip to the specified rect
void scissor(const SkIRect&);
// overrides from SkDevice
virtual void gainFocus(SkCanvas*);
virtual void setMatrixClip(const SkMatrix& matrix, const SkRegion& clip);
virtual void drawPaint(const SkDraw&, const SkPaint& paint);
virtual void drawPoints(const SkDraw&, SkCanvas::PointMode mode, size_t count,
const SkPoint[], const SkPaint& paint);
virtual void drawRect(const SkDraw&, const SkRect& r,
const SkPaint& paint);
virtual void drawPath(const SkDraw&, const SkPath& path,
const SkPaint& paint);
virtual void drawBitmap(const SkDraw&, const SkBitmap& bitmap,
const SkMatrix& matrix, const SkPaint& paint);
virtual void drawSprite(const SkDraw&, const SkBitmap& bitmap,
int x, int y, const SkPaint& paint);
virtual void drawText(const SkDraw&, const void* text, size_t len,
SkScalar x, SkScalar y, const SkPaint& paint);
virtual void drawPosText(const SkDraw&, const void* text, size_t len,
const SkScalar pos[], SkScalar constY,
int scalarsPerPos, const SkPaint& paint);
virtual void drawTextOnPath(const SkDraw&, const void* text, size_t len,
const SkPath& path, const SkMatrix* matrix,
const SkPaint& paint);
virtual void drawVertices(const SkDraw&, SkCanvas::VertexMode, int vertexCount,
const SkPoint verts[], const SkPoint texs[],
const SkColor colors[], SkXfermode* xmode,
const uint16_t indices[], int indexCount,
const SkPaint& paint);
virtual void drawDevice(const SkDraw&, SkDevice*, int x, int y,
const SkPaint&);
// settings for the global texture cache
static size_t GetTextureCacheMaxCount();
static void SetTextureCacheMaxCount(size_t count);
static size_t GetTextureCacheMaxSize();
static void SetTextureCacheMaxSize(size_t size);
/** Call glDeleteTextures for all textures (including those for text)
This should be called while the gl-context is still valid. Its purpose
is to free up gl resources. Note that if a bitmap or text is drawn after
this call, new caches will be created.
*/
static void DeleteAllTextures();
/** Forget all textures without calling delete (including those for text).
This should be called if the gl-context has changed, and the texture
IDs that have been cached are no longer valid.
*/
static void AbandonAllTextures();
protected:
/** Return the current glmatrix, from a previous call to setMatrixClip */
const SkMatrix& matrix() const { return fMatrix; }
/** Return the current clip, from a previous call to setMatrixClip */
const SkRegion& clip() const { return fClip; }
private:
SkGLMatrix fGLMatrix;
SkMatrix fMatrix;
SkRegion fClip;
bool fDirty;
SkGLClipIter fClipIter;
SkGLDrawProcs* fDrawProcs;
void setupForText(SkDraw* draw, const SkPaint& paint);
// global texture cache methods
class TexCache;
static TexCache* LockTexCache(const SkBitmap&, GLuint* name,
SkPoint* size);
static void UnlockTexCache(TexCache*);
class SkAutoLockTexCache {
public:
SkAutoLockTexCache(const SkBitmap& bitmap, GLuint* name,
SkPoint* size) {
fTex = SkGLDevice::LockTexCache(bitmap, name, size);
}
~SkAutoLockTexCache() {
if (fTex) {
SkGLDevice::UnlockTexCache(fTex);
}
}
TexCache* get() const { return fTex; }
private:
TexCache* fTex;
};
friend class SkAutoTexCache;
// returns cache if the texture is bound for the shader
TexCache* setupGLPaintShader(const SkPaint& paint);
class AutoPaintShader {
public:
AutoPaintShader(SkGLDevice*, const SkPaint& paint);
~AutoPaintShader();
bool useTex() const { return fTexCache != 0; }
private:
SkGLDevice* fDevice;
TexCache* fTexCache;
};
friend class AutoPaintShader;
typedef SkDevice INHERITED;
};
#endif

View File

@ -1,64 +0,0 @@
/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkGLDevice_FBO.h"
#include "SkRegion.h"
SkGLDevice_FBO::SkGLDevice_FBO(const SkBitmap& bitmap, bool offscreen)
: SkGLDevice(bitmap, offscreen) {
fFBO = 0;
fTextureID = 0;
if (offscreen) {
int nw = SkNextPow2(bitmap.rowBytesAsPixels());
int nh = SkNextPow2(bitmap.height());
glGenFramebuffersEXT(1, &fFBO);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fFBO);
glGenTextures(1, &fTextureID);
glBindTexture(GL_TEXTURE_2D, fTextureID);
SkGL::SetTexParamsClamp(false);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, nw, nh, 0,
GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
GL_TEXTURE_2D, fTextureID, 0);
GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
SkDebugf("-- glCheckFramebufferStatusEXT %x\n", status);
}
// now reset back to "normal" drawing target
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
}
}
SkGLDevice_FBO::~SkGLDevice_FBO() {
if (fTextureID) {
glDeleteTextures(1, &fTextureID);
}
if (fFBO) {
glDeleteFramebuffersEXT(1, &fFBO);
}
}
SkGLDevice::TexOrientation SkGLDevice_FBO::bindDeviceAsTexture() {
if (fTextureID) {
glBindTexture(GL_TEXTURE_2D, fTextureID);
return kBottomToTop_TexOrientation;
}
return kNo_TexOrientation;
}
void SkGLDevice_FBO::gainFocus(SkCanvas* canvas) {
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fFBO);
// now we're ready for the viewport and projection matrix
this->INHERITED::gainFocus(canvas);
}

View File

@ -1,30 +0,0 @@
/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkGLDevice_FBO_DEFINED
#define SkGLDevice_FBO_DEFINED
#include "SkGLDevice.h"
class SkGLDevice_FBO : public SkGLDevice {
public:
SkGLDevice_FBO(const SkBitmap& bitmap, bool offscreen);
virtual ~SkGLDevice_FBO();
// overrides from SkGLDevice
virtual void gainFocus(SkCanvas*);
virtual TexOrientation bindDeviceAsTexture();
private:
GLuint fFBO;
GLuint fTextureID;
typedef SkGLDevice INHERITED;
};
#endif

View File

@ -1,98 +0,0 @@
/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkGLDevice_SWLayer.h"
#include "SkRegion.h"
SkGLDevice_SWLayer::SkGLDevice_SWLayer(const SkBitmap& bitmap)
: SkGLDevice(bitmap, true) {
fTextureID = 0;
SkASSERT(bitmap.getPixels());
}
SkGLDevice_SWLayer::~SkGLDevice_SWLayer() {
if (fTextureID) {
glDeleteTextures(1, &fTextureID);
}
}
SkGLDevice::TexOrientation SkGLDevice_SWLayer::bindDeviceAsTexture() {
const SkBitmap& bitmap = this->accessBitmap(false);
if (0 == fTextureID) {
fTextureID = SkGL::BindNewTexture(bitmap, NULL);
}
return kTopToBottom_TexOrientation;
}
///////////////////////////////////////////////////////////////////////////////
#include "SkDraw.h"
void SkGLDevice_SWLayer::drawPaint(const SkDraw& draw, const SkPaint& paint) {
draw.drawPaint(paint);
}
void SkGLDevice_SWLayer::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count,
const SkPoint pts[], const SkPaint& paint) {
draw.drawPoints(mode, count, pts, paint);
}
void SkGLDevice_SWLayer::drawRect(const SkDraw& draw, const SkRect& r,
const SkPaint& paint) {
draw.drawRect(r, paint);
}
void SkGLDevice_SWLayer::drawPath(const SkDraw& draw, const SkPath& path,
const SkPaint& paint) {
draw.drawPath(path, paint);
}
void SkGLDevice_SWLayer::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
const SkMatrix& matrix, const SkPaint& paint) {
draw.drawBitmap(bitmap, matrix, paint);
}
void SkGLDevice_SWLayer::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
int x, int y, const SkPaint& paint) {
draw.drawSprite(bitmap, x, y, paint);
}
void SkGLDevice_SWLayer::drawText(const SkDraw& draw, const void* text, size_t len,
SkScalar x, SkScalar y, const SkPaint& paint) {
draw.drawText((const char*)text, len, x, y, paint);
}
void SkGLDevice_SWLayer::drawPosText(const SkDraw& draw, const void* text, size_t len,
const SkScalar xpos[], SkScalar y,
int scalarsPerPos, const SkPaint& paint) {
draw.drawPosText((const char*)text, len, xpos, y, scalarsPerPos, paint);
}
void SkGLDevice_SWLayer::drawTextOnPath(const SkDraw& draw, const void* text,
size_t len, const SkPath& path,
const SkMatrix* matrix,
const SkPaint& paint) {
draw.drawTextOnPath((const char*)text, len, path, matrix, paint);
}
void SkGLDevice_SWLayer::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
int vertexCount,
const SkPoint verts[], const SkPoint textures[],
const SkColor colors[], SkXfermode* xmode,
const uint16_t indices[], int indexCount,
const SkPaint& paint) {
draw.drawVertices(vmode, vertexCount, verts, textures, colors, xmode,
indices, indexCount, paint);
}
void SkGLDevice_SWLayer::drawDevice(const SkDraw& draw, SkDevice* dev,
int x, int y, const SkPaint& paint) {
this->SkDevice::drawDevice(draw, dev, x, y, paint);
}

View File

@ -1,56 +0,0 @@
/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkGLDevice_SWLayer_DEFINED
#define SkGLDevice_SWLayer_DEFINED
#include "SkGLDevice.h"
class SkGLDevice_SWLayer : public SkGLDevice {
public:
SkGLDevice_SWLayer(const SkBitmap& bitmap);
virtual ~SkGLDevice_SWLayer();
// overrides from SkGLDevice
virtual TexOrientation bindDeviceAsTexture();
// overrides from SkDevice
virtual void drawPaint(const SkDraw&, const SkPaint& paint);
virtual void drawPoints(const SkDraw&, SkCanvas::PointMode mode, size_t count,
const SkPoint[], const SkPaint& paint);
virtual void drawRect(const SkDraw&, const SkRect& r,
const SkPaint& paint);
virtual void drawPath(const SkDraw&, const SkPath& path,
const SkPaint& paint);
virtual void drawBitmap(const SkDraw&, const SkBitmap& bitmap,
const SkMatrix& matrix, const SkPaint& paint);
virtual void drawSprite(const SkDraw&, const SkBitmap& bitmap,
int x, int y, const SkPaint& paint);
virtual void drawText(const SkDraw&, const void* text, size_t len,
SkScalar x, SkScalar y, const SkPaint& paint);
virtual void drawPosText(const SkDraw&, const void* text, size_t len,
const SkScalar pos[], SkScalar constY,
int scalarsPerPos, const SkPaint& paint);
virtual void drawTextOnPath(const SkDraw&, const void* text, size_t len,
const SkPath& path, const SkMatrix* matrix,
const SkPaint& paint);
virtual void drawVertices(const SkDraw&, SkCanvas::VertexMode, int vertexCount,
const SkPoint verts[], const SkPoint texs[],
const SkColor colors[], SkXfermode* xmode,
const uint16_t indices[], int indexCount,
const SkPaint& paint);
virtual void drawDevice(const SkDraw&, SkDevice*, int x, int y,
const SkPaint&);
private:
GLuint fTextureID;
typedef SkGLDevice INHERITED;
};
#endif

View File

@ -1,162 +0,0 @@
/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkGLState.h"
#include "SkColorPriv.h"
// here is our global instance
SkGLState SkGLState::gState;
// this is an illegal pmcolor, since its alpha (0) is less than its red
#define UNKNOWN_PMCOLOR (SK_R32_MASK << SK_R32_SHIFT)
#define UNKNOWN_GLENUM ((GLenum)-1)
// MUST be in the same order as SkGLState::Caps enum
static const GLenum gCapsTable[] = {
GL_DITHER,
GL_TEXTURE_2D,
};
// MUST be in the same order as SkGLState::ClientState enum
static const GLenum gClientStateTable[] = {
GL_TEXTURE_COORD_ARRAY,
GL_COLOR_ARRAY,
};
static const GLenum gShadeModelTable[] = {
GL_FLAT,
GL_SMOOTH
};
///////////////////////////////////////////////////////////////////////////////
SkGLState::SkGLState() :
fCapsPtr(gCapsTable),
fClientPtr(gClientStateTable),
fShadePtr(gShadeModelTable) {
this->init();
}
void SkGLState::init() {
fCapBits = 0;
fClientStateBits = 0;
fShadeModel = UNKNOWN_GLENUM;
fScissorSize.set(-1, -1);
fPMColor = UNKNOWN_PMCOLOR;
fSrcBlend = fDstBlend = UNKNOWN_GLENUM;
fPointSize = fLineWidth = -1;
}
void SkGLState::reset() {
this->init();
size_t i;
for (i = 0; i < SK_ARRAY_COUNT(gCapsTable); i++) {
glDisable(fCapsPtr[i]);
}
for (i = 0; i < SK_ARRAY_COUNT(gClientStateTable); i++) {
glDisableClientState(fClientPtr[i]);
}
}
///////////////////////////////////////////////////////////////////////////////
void SkGLState::enable(Caps c) {
unsigned mask = 1 << c;
if ((fCapBits & mask) == 0) {
fCapBits |= mask;
glEnable(fCapsPtr[c]);
}
}
void SkGLState::disable(Caps c) {
unsigned mask = 1 << c;
if (fCapBits & mask) {
fCapBits &= ~mask;
glDisable(fCapsPtr[c]);
}
}
void SkGLState::enableClientState(ClientState c) {
unsigned mask = 1 << c;
if ((fClientStateBits & mask) == 0) {
fClientStateBits |= mask;
glEnableClientState(fClientPtr[c]);
}
}
void SkGLState::disableClientState(ClientState c) {
unsigned mask = 1 << c;
if (fClientStateBits & mask) {
fClientStateBits &= ~mask;
glDisableClientState(fClientPtr[c]);
}
}
void SkGLState::shadeModel(ShadeModel s) {
if (fShadeModel != s) {
fShadeModel = s;
glShadeModel(fShadePtr[s]);
}
}
void SkGLState::scissor(int x, int y, int w, int h) {
SkASSERT(w >= 0 && h >= 0);
if (!fScissorLoc.equals(x, y) || !fScissorSize.equals(w, h)) {
fScissorLoc.set(x, y);
fScissorSize.set(w, h);
glScissor(x, y, w, h);
}
}
void SkGLState::pointSize(float x) {
if (fPointSize != x) {
fPointSize = x;
glPointSize(x);
}
}
void SkGLState::lineWidth(float x) {
if (fLineWidth != x) {
fLineWidth = x;
glLineWidth(x);
}
}
void SkGLState::blendFunc(GLenum src, GLenum dst) {
if (fSrcBlend != src || fDstBlend != dst) {
fSrcBlend = src;
fDstBlend = dst;
glBlendFunc(src, dst);
}
}
///////////////////////////////////////////////////////////////////////////////
#ifdef SK_GL_HAS_COLOR4UB
static inline void gl_pmcolor(U8CPU r, U8CPU g, U8CPU b, U8CPU a) {
glColor4ub(r, g, b, a);
}
#else
static inline SkFixed byte2fixed(U8CPU value) {
return ((value << 8) | value) + (value >> 7);
}
static inline void gl_pmcolor(U8CPU r, U8CPU g, U8CPU b, U8CPU a) {
glColor4x(byte2fixed(r), byte2fixed(g), byte2fixed(b), byte2fixed(a));
}
#endif
void SkGLState::pmColor(SkPMColor c) {
if (fPMColor != c) {
fPMColor = c;
gl_pmcolor(SkGetPackedR32(c), SkGetPackedG32(c),
SkGetPackedB32(c), SkGetPackedA32(c));
}
}

View File

@ -1,81 +0,0 @@
/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkGLState_DEFINED
#define SkGLState_DEFINED
#include "SkGL.h"
#include "SkSize.h"
class SkGLState {
public:
static SkGLState& GlobalState() { return gState; }
SkGLState();
void reset();
// internally, these are bit_shifts, so they must be 0, 1, ...
enum Caps {
kDITHER,
kTEXTURE_2D,
};
void enable(Caps);
void disable(Caps);
// internally, these are bit_shifts, so they must be 0, 1, ...
enum ClientState {
kTEXTURE_COORD_ARRAY,
kCOLOR_ARRAY,
};
void enableClientState(ClientState);
void disableClientState(ClientState);
// we use -1 for unknown, so the enum must be >= 0
enum ShadeModel {
kFLAT,
kSMOOTH,
};
void shadeModel(ShadeModel);
void scissor(int x, int y, int w, int h);
void color(SkColor c) {
this->pmColor(SkPreMultiplyColor(c));
}
void alpha(U8CPU a) {
this->pmColor((a << 24) | (a << 16) | (a << 8) | a);
}
void pmColor(SkPMColor);
void blendFunc(GLenum src, GLenum dst);
void pointSize(float);
void lineWidth(float);
private:
void init();
unsigned fCapBits;
unsigned fClientStateBits;
int fShadeModel;
SkIPoint fScissorLoc;
SkISize fScissorSize;
SkPMColor fPMColor;
GLenum fSrcBlend, fDstBlend;
float fPointSize;
float fLineWidth;
const GLenum* fCapsPtr;
const GLenum* fClientPtr;
const GLenum* fShadePtr;
static SkGLState gState;
};
#endif

View File

@ -1,198 +0,0 @@
/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkGLTextCache.h"
#include "SkScalerContext.h"
#include "SkTSearch.h"
const GLenum gTextTextureFormat = GL_ALPHA;
const GLenum gTextTextureType = GL_UNSIGNED_BYTE;
SkGLTextCache::Strike::Strike(Strike* next, int width, int height) {
fStrikeWidth = SkNextPow2(SkMax32(kMinStrikeWidth, width));
fStrikeHeight = SkNextPow2(height);
fGlyphCount = 0;
fNextFreeOffsetX = 0;
fNext = next;
fStrikeWidthShift = SkNextLog2(fStrikeWidth);
fStrikeHeightShift = SkNextLog2(fStrikeHeight);
if (next) {
SkASSERT(next->fStrikeHeight == fStrikeHeight);
}
// create an empty texture to receive glyphs
fTexName = 0;
glGenTextures(1, &fTexName);
glBindTexture(GL_TEXTURE_2D, fTexName);
glTexImage2D(GL_TEXTURE_2D, 0, gTextTextureFormat,
fStrikeWidth, fStrikeHeight, 0,
gTextTextureFormat, gTextTextureType, NULL);
SK_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
SK_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
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);
}
SkGLTextCache::Strike::~Strike() {
if (fTexName != 0) {
glDeleteTextures(1, &fTexName);
}
}
SkGLTextCache::Strike*
SkGLTextCache::Strike::findGlyph(const SkGlyph& glyph, int* offset) {
Strike* strike = this;
SkDEBUGCODE(const int height = SkNextPow2(glyph.fHeight);)
do {
SkASSERT(height == strike->fStrikeHeight);
int index = SkTSearch(strike->fGlyphIDArray, strike->fGlyphCount,
glyph.fID, sizeof(strike->fGlyphIDArray[0]));
if (index >= 0) {
if (offset) {
*offset = strike->fGlyphOffsetX[index];
}
return strike;
}
strike = strike->fNext;
} while (NULL != strike);
return NULL;
}
static void make_a_whole(void* buffer, int index, int count, size_t elemSize) {
SkASSERT(index >= 0 && index <= count);
size_t offset = index * elemSize;
memmove((char*)buffer + offset + elemSize,
(const char*)buffer + offset,
(count - index) * elemSize);
}
SkGLTextCache::Strike*
SkGLTextCache::Strike::addGlyphAndBind(const SkGlyph& glyph,
const uint8_t image[], int* offset) {
#ifdef SK_DEBUG
SkASSERT(this->findGlyph(glyph, NULL) == NULL);
const int height = SkNextPow2(glyph.fHeight);
SkASSERT(height <= fStrikeHeight && height > (fStrikeHeight >> 1));
#endif
int rowBytes = glyph.rowBytes();
SkASSERT(rowBytes >= glyph.fWidth);
Strike* strike;
if (fGlyphCount == kMaxGlyphCount ||
fNextFreeOffsetX + rowBytes >= fStrikeWidth) {
// this will bind the next texture for us
// SkDebugf("--- extend strike %p\n", this);
strike = SkNEW_ARGS(Strike, (this, rowBytes, glyph.fHeight));
} else {
glBindTexture(GL_TEXTURE_2D, fTexName);
strike = this;
}
uint32_t* idArray = strike->fGlyphIDArray;
uint16_t* offsetArray = strike->fGlyphOffsetX;
const int glyphCount = strike->fGlyphCount;
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexSubImage2D(GL_TEXTURE_2D, 0, strike->fNextFreeOffsetX, 0, rowBytes,
glyph.fHeight, gTextTextureFormat, gTextTextureType,
image);
// need to insert the offset
int index = SkTSearch(idArray, glyphCount, glyph.fID, sizeof(idArray[0]));
SkASSERT(index < 0);
index = ~index; // this is where we should insert it
make_a_whole(idArray, index, glyphCount, sizeof(idArray));
make_a_whole(offsetArray, index, glyphCount, sizeof(offsetArray[0]));
idArray[index] = glyph.fID;
offsetArray[index] = strike->fNextFreeOffsetX;
if (offset) {
*offset = strike->fNextFreeOffsetX;
}
#if 0
SkDebugf("--- strike %p glyph %x [%d %d] offset %d count %d\n",
strike, glyph.fID, glyph.fWidth, glyph.fHeight,
strike->fNextFreeOffsetX, glyphCount + 1);
#endif
// now update our header
strike->fGlyphCount = glyphCount + 1;
strike->fNextFreeOffsetX += glyph.fWidth;
return strike;
}
///////////////////////////////////////////////////////////////////////////////
SkGLTextCache::SkGLTextCache() {
sk_bzero(fStrikeList, sizeof(fStrikeList));
}
SkGLTextCache::~SkGLTextCache() {
this->deleteAllStrikes(true);
}
void SkGLTextCache::deleteAllStrikes(bool texturesAreValid) {
for (size_t i = 0; i < SK_ARRAY_COUNT(fStrikeList); i++) {
Strike* strike = fStrikeList[i];
while (strike != NULL) {
Strike* next = strike->fNext;
if (!texturesAreValid) {
strike->abandonTexture();
}
SkDELETE(strike);
strike = next;
}
}
sk_bzero(fStrikeList, sizeof(fStrikeList));
}
SkGLTextCache::Strike* SkGLTextCache::findGlyph(const SkGlyph& glyph,
int* offset) {
SkASSERT(glyph.fWidth != 0);
SkASSERT(glyph.fHeight != 0);
size_t index = SkNextLog2(glyph.fHeight);
if (index >= SK_ARRAY_COUNT(fStrikeList)) {
// too big for us to cache;
return NULL;
}
Strike* strike = fStrikeList[index];
if (strike) {
strike = strike->findGlyph(glyph, offset);
}
return strike;
}
SkGLTextCache::Strike* SkGLTextCache::addGlyphAndBind(const SkGlyph& glyph,
const uint8_t image[], int* offset) {
SkASSERT(image != NULL);
SkASSERT(glyph.fWidth != 0);
SkASSERT(glyph.fHeight != 0);
size_t index = SkNextLog2(glyph.fHeight);
if (index >= SK_ARRAY_COUNT(fStrikeList)) {
// too big for us to cache;
return NULL;
}
Strike* strike = fStrikeList[index];
if (NULL == strike) {
strike = SkNEW_ARGS(Strike, (NULL, glyph.rowBytes(), glyph.fHeight));
// SkDebugf("--- create strike [%d] %p cache %p\n", index, strike, this);
}
strike = strike->addGlyphAndBind(glyph, image, offset);
fStrikeList[index] = strike;
return strike;
}

View File

@ -1,93 +0,0 @@
/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkGLTextCache_DEFINED
#define SkGLTextCache_DEFINED
#include "SkGL.h"
class SkGlyph;
class SkGLTextCache {
public:
SkGLTextCache();
~SkGLTextCache();
/** Delete all of the strikes in the cache. Pass true if the texture IDs are
still valid, in which case glDeleteTextures will be called. Pass false
if they are invalid (e.g. the gl-context has changed), in which case
they will just be abandoned.
*/
void deleteAllStrikes(bool texturesAreValid);
class Strike {
public:
int width() const { return fStrikeWidth; }
int height() const { return fStrikeHeight; }
GLuint texture() const { return fTexName; }
int widthShift() const { return fStrikeWidthShift; }
int heightShift() const { return fStrikeHeightShift; }
// call this to force us to ignore the texture name in our destructor
// only call it right before our destructor
void abandonTexture() { fTexName = 0; }
private:
// if next is non-null, its height must match our height
Strike(Strike* next, int width, int height);
~Strike();
Strike* findGlyph(const SkGlyph&, int* offset);
Strike* addGlyphAndBind(const SkGlyph&, const uint8_t*, int* offset);
enum {
kMinStrikeWidth = 1024,
kMaxGlyphCount = 256
};
Strike* fNext;
GLuint fTexName;
uint32_t fGlyphIDArray[kMaxGlyphCount]; // stores glyphIDs
uint16_t fGlyphOffsetX[kMaxGlyphCount]; // stores x-offsets
uint16_t fGlyphCount;
uint16_t fNextFreeOffsetX;
uint16_t fStrikeWidth;
uint16_t fStrikeHeight;
uint8_t fStrikeWidthShift; // pow2(fStrikeWidth)
uint8_t fStrikeHeightShift; // pow2(fStrikeHeight)
friend class SkGLTextCache;
};
/** If found, returns the exact strike containing it (there may be more than
one with a given height), and sets offset to the offset for that glyph
(if not null). Does NOT bind the texture.
If not found, returns null and ignores offset param.
*/
Strike* findGlyph(const SkGlyph&, int* offset);
/** Adds the specified glyph to this list of strikes, returning the new
head of the list. If offset is not null, it is set to the offset
for this glyph within the strike. The associated texture is bound
to the gl context.
*/
Strike* addGlyphAndBind(const SkGlyph&, const uint8_t image[], int* offset);
private:
enum {
// greater than this we won't cache
kMaxGlyphHeightShift = 9,
kMaxGlyphHeight = 1 << kMaxGlyphHeightShift,
kMaxStrikeListCount = kMaxGlyphHeightShift + 1
};
// heads of the N families, one for each pow2 height
Strike* fStrikeList[kMaxStrikeListCount];
};
#endif

View File

@ -1,370 +0,0 @@
/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkTextureCache.h"
//#define TRACE_HASH_HITS
//#define TRACE_TEXTURE_CACHE_PURGE
SkTextureCache::Entry::Entry(const SkBitmap& bitmap)
: fName(0), fKey(bitmap), fPrev(NULL), fNext(NULL) {
fMemSize = SkGL::ComputeTextureMemorySize(bitmap);
fLockCount = 0;
}
SkTextureCache::Entry::~Entry() {
if (fName != 0) {
glDeleteTextures(1, &fName);
}
}
///////////////////////////////////////////////////////////////////////////////
SkTextureCache::SkTextureCache(size_t countMax, size_t sizeMax)
: fHead(NULL), fTail(NULL),
fTexCountMax(countMax), fTexSizeMax(sizeMax),
fTexCount(0), fTexSize(0) {
sk_bzero(fHash, sizeof(fHash));
this->validate();
}
SkTextureCache::~SkTextureCache() {
#ifdef SK_DEBUG
Entry* entry = fHead;
while (entry) {
SkASSERT(entry->lockCount() == 0);
entry = entry->fNext;
}
#endif
this->validate();
}
void SkTextureCache::deleteAllCaches(bool texturesAreValid) {
this->validate();
Entry* entry = fHead;
while (entry) {
Entry* next = entry->fNext;
if (!texturesAreValid) {
entry->abandonTexture();
}
SkDELETE(entry);
entry = next;
}
fSorted.reset();
sk_bzero(fHash, sizeof(fHash));
fTexCount = 0;
fTexSize = 0;
fTail = fHead = NULL;
this->validate();
}
///////////////////////////////////////////////////////////////////////////////
int SkTextureCache::findInSorted(const Key& key) const {
int count = fSorted.count();
if (count == 0) {
return ~0;
}
Entry** sorted = fSorted.begin();
int lo = 0;
int hi = count - 1;
while (lo < hi) {
int mid = (hi + lo) >> 1;
if (sorted[mid]->getKey() < key) {
lo = mid + 1;
} else {
hi = mid;
}
}
// hi is now our best guess
const Entry* entry = sorted[hi];
if (entry->getKey() == key) {
return hi;
}
// return where to insert it
if (entry->getKey() < key) {
hi += 1;
}
return ~hi; // we twiddle to indicate not-found
}
#ifdef TRACE_HASH_HITS
static int gHashHits;
static int gSortedHits;
#endif
SkTextureCache::Entry* SkTextureCache::find(const Key& key, int* insert) const {
int count = fSorted.count();
if (count == 0) {
*insert = 0;
return NULL;
}
// check the hash first
int hashIndex = key.getHashIndex();
Entry* entry = fHash[hashIndex];
if (NULL != entry && entry->getKey() == key) {
#ifdef TRACE_HASH_HITS
gHashHits += 1;
#endif
return entry;
}
int index = this->findInSorted(key);
if (index >= 0) {
#ifdef TRACE_HASH_HITS
gSortedHits += 1;
#endif
entry = fSorted[index];
fHash[hashIndex] = entry;
return entry;
}
// ~index is where to insert the entry
*insert = ~index;
return NULL;
}
SkTextureCache::Entry* SkTextureCache::lock(const SkBitmap& bitmap) {
this->validate();
// call this before we call find(), so we don't reorder after find() and
// invalidate our index
this->purgeIfNecessary(SkGL::ComputeTextureMemorySize(bitmap));
Key key(bitmap);
int index;
Entry* entry = this->find(key, &index);
if (NULL == entry) {
entry = SkNEW_ARGS(Entry, (bitmap));
entry->fName = SkGL::BindNewTexture(bitmap, &entry->fTexSize);
if (0 == entry->fName) {
SkDELETE(entry);
return NULL;
}
fHash[key.getHashIndex()] = entry;
*fSorted.insert(index) = entry;
fTexCount += 1;
fTexSize += entry->memSize();
} else {
// detach from our llist
Entry* prev = entry->fPrev;
Entry* next = entry->fNext;
if (prev) {
prev->fNext = next;
} else {
SkASSERT(fHead == entry);
fHead = next;
}
if (next) {
next->fPrev = prev;
} else {
SkASSERT(fTail == entry);
fTail = prev;
}
// now bind the texture
glBindTexture(GL_TEXTURE_2D, entry->fName);
}
// add to head of llist for LRU
entry->fPrev = NULL;
entry->fNext = fHead;
if (NULL != fHead) {
SkASSERT(NULL == fHead->fPrev);
fHead->fPrev = entry;
}
fHead = entry;
if (NULL == fTail) {
fTail = entry;
}
this->validate();
entry->lock();
#ifdef TRACE_HASH_HITS
SkDebugf("---- texture cache hash=%d sorted=%d\n", gHashHits, gSortedHits);
#endif
return entry;
}
void SkTextureCache::unlock(Entry* entry) {
this->validate();
#ifdef SK_DEBUG
SkASSERT(entry);
int index = this->findInSorted(entry->getKey());
SkASSERT(fSorted[index] == entry);
#endif
SkASSERT(entry->fLockCount > 0);
entry->unlock();
}
void SkTextureCache::purgeIfNecessary(size_t extraSize) {
this->validate();
size_t countMax = fTexCountMax;
size_t sizeMax = fTexSizeMax;
// take extraSize into account, but watch for underflow of size_t
if (extraSize > sizeMax) {
sizeMax = 0;
} else {
sizeMax -= extraSize;
}
Entry* entry = fTail;
while (entry) {
if (fTexCount <= countMax && fTexSize <= sizeMax) {
break;
}
Entry* prev = entry->fPrev;
// don't purge an entry that is locked
if (entry->isLocked()) {
entry = prev;
continue;
}
fTexCount -= 1;
fTexSize -= entry->memSize();
// remove from our sorted and hash arrays
int index = this->findInSorted(entry->getKey());
SkASSERT(index >= 0);
fSorted.remove(index);
index = entry->getKey().getHashIndex();
if (entry == fHash[index]) {
fHash[index] = NULL;
}
// now detach it from our llist
Entry* next = entry->fNext;
if (prev) {
prev->fNext = next;
} else {
fHead = next;
}
if (next) {
next->fPrev = prev;
} else {
fTail = prev;
}
// now delete it
#ifdef TRACE_TEXTURE_CACHE_PURGE
SkDebugf("---- purge texture cache %d size=%d\n",
entry->name(), entry->memSize());
#endif
SkDELETE(entry);
// keep going
entry = prev;
}
this->validate();
}
void SkTextureCache::setMaxCount(size_t count) {
if (fTexCountMax != count) {
fTexCountMax = count;
this->purgeIfNecessary(0);
}
}
void SkTextureCache::setMaxSize(size_t size) {
if (fTexSizeMax != size) {
fTexSizeMax = size;
this->purgeIfNecessary(0);
}
}
///////////////////////////////////////////////////////////////////////////////
#ifdef SK_DEBUG
void SkTextureCache::validate() const {
if (0 == fTexCount) {
SkASSERT(0 == fTexSize);
SkASSERT(NULL == fHead);
SkASSERT(NULL == fTail);
return;
}
SkASSERT(fTexSize); // do we allow a zero-sized texture?
SkASSERT(fHead);
SkASSERT(fTail);
SkASSERT(NULL == fHead->fPrev);
SkASSERT(NULL == fTail->fNext);
if (1 == fTexCount) {
SkASSERT(fHead == fTail);
}
const Entry* entry = fHead;
size_t count = 0;
size_t size = 0;
size_t i;
while (entry != NULL) {
SkASSERT(count < fTexCount);
SkASSERT(size < fTexSize);
size += entry->memSize();
count += 1;
if (NULL == entry->fNext) {
SkASSERT(fTail == entry);
}
entry = entry->fNext;
}
SkASSERT(count == fTexCount);
SkASSERT(size == fTexSize);
count = 0;
size = 0;
entry = fTail;
while (entry != NULL) {
SkASSERT(count < fTexCount);
SkASSERT(size < fTexSize);
size += entry->memSize();
count += 1;
if (NULL == entry->fPrev) {
SkASSERT(fHead == entry);
}
entry = entry->fPrev;
}
SkASSERT(count == fTexCount);
SkASSERT(size == fTexSize);
SkASSERT(count == (size_t)fSorted.count());
for (i = 1; i < count; i++) {
SkASSERT(fSorted[i-1]->getKey() < fSorted[i]->getKey());
}
for (i = 0; i < kHashCount; i++) {
if (fHash[i]) {
size_t index = fHash[i]->getKey().getHashIndex();
SkASSERT(index == i);
index = fSorted.find(fHash[i]);
SkASSERT((size_t)index < count);
}
}
}
#endif

View File

@ -1,168 +0,0 @@
/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkTextureCache_DEFINED
#define SkTextureCache_DEFINED
#include "SkBitmap.h"
#include "SkPoint.h"
#include "SkGL.h"
#include "SkTDArray.h"
class SkTextureCache {
public:
SkTextureCache(size_t maxCount, size_t maxSize);
~SkTextureCache();
size_t getMaxCount() { return fTexCountMax; }
size_t getMaxSize() { return fTexSizeMax; }
void setMaxCount(size_t count);
void setMaxSize(size_t size);
/** Deletes all the caches. Pass true if the texture IDs are still valid,
and if so, it will call glDeleteTextures. Pass false if the texture IDs
are invalid (e.g. the gl-context has changed), in which case they will
just be abandoned.
*/
void deleteAllCaches(bool texturesAreValid);
static int HashMask() { return kHashMask; }
class Key {
public:
Key(const SkBitmap& bm) {
fGenID = bm.getGenerationID();
fOffset = bm.pixelRefOffset();
fWH = (bm.width() << 16) | bm.height();
this->computeHash();
}
int getHashIndex() const { return fHashIndex; }
friend bool operator==(const Key& a, const Key& b) {
return a.fHash == b.fHash &&
a.fGenID == b.fGenID &&
a.fOffset == b.fOffset &&
a.fWH == b.fWH;
}
friend bool operator<(const Key& a, const Key& b) {
if (a.fHash < b.fHash) {
return true;
} else if (a.fHash > b.fHash) {
return false;
}
if (a.fGenID < b.fGenID) {
return true;
} else if (a.fGenID > b.fGenID) {
return false;
}
if (a.fOffset < b.fOffset) {
return true;
} else if (a.fOffset > b.fOffset) {
return false;
}
return a.fWH < b.fWH;
}
private:
void computeHash() {
uint32_t hash = fGenID ^ fOffset ^ fWH;
fHash = hash;
hash ^= hash >> 16;
fHashIndex = hash & SkTextureCache::HashMask();
}
uint32_t fHash; // computed from the other fields
uint32_t fGenID;
size_t fOffset;
uint32_t fWH;
// for indexing into the texturecache's fHash
int fHashIndex;
};
class Entry {
public:
GLuint name() const { return fName; }
SkPoint texSize() const { return fTexSize; }
size_t memSize() const { return fMemSize; }
const Key& getKey() const { return fKey; }
// call this to clear the texture name, in case the context has changed
// in which case we should't reference or delete this texture in GL
void abandonTexture() { fName = 0; }
private:
Entry(const SkBitmap& bitmap);
~Entry();
int lockCount() const { return fLockCount; }
bool isLocked() const { return fLockCount > 0; }
void lock() { fLockCount += 1; }
void unlock() {
SkASSERT(fLockCount > 0);
fLockCount -= 1;
}
private:
GLuint fName;
SkPoint fTexSize;
Key fKey;
size_t fMemSize;
int fLockCount;
Entry* fPrev;
Entry* fNext;
friend class SkTextureCache;
};
Entry* lock(const SkBitmap&);
void unlock(Entry*);
private:
void purgeIfNecessary(size_t extraSize);
#ifdef SK_DEBUG
void validate() const;
#else
void validate() const {}
#endif
Entry* fHead;
Entry* fTail;
// limits for the cache
size_t fTexCountMax;
size_t fTexSizeMax;
// current values for the cache
size_t fTexCount;
size_t fTexSize;
enum {
kHashBits = 6,
kHashCount = 1 << kHashBits,
kHashMask = kHashCount - 1
};
mutable Entry* fHash[kHashCount];
SkTDArray<Entry*> fSorted;
/* If we find the key, return the entry and ignore index. If we don't,
return NULL and set index to the place to insert the entry in fSorted
*/
Entry* find(const Key&, int* index) const;
// returns index or <0 if not found. Does NOT update hash
int findInSorted(const Key& key) const;
};
#endif