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:
parent
022a3e1f3e
commit
f97ef2f98e
@ -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);
|
||||
}
|
||||
}
|
||||
|
314
obsolete/SkGL.h
314
obsolete/SkGL.h
@ -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
|
||||
|
@ -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();
|
||||
}
|
@ -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
|
@ -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
|
||||
));
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -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
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
@ -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
|
||||
|
||||
|
@ -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
|
Loading…
Reference in New Issue
Block a user