support lcd16 in text atlas (sans shader support)

git-svn-id: http://skia.googlecode.com/svn/trunk@939 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
reed@google.com 2011-03-15 15:40:16 +00:00
parent b7e9aee1ac
commit 98539c607b
10 changed files with 128 additions and 49 deletions

View File

@ -28,10 +28,11 @@ class GrAtlasMgr;
class GrAtlas { class GrAtlas {
public: public:
GrAtlas(GrAtlasMgr*, int plotX, int plotY); GrAtlas(GrAtlasMgr*, int plotX, int plotY, GrMaskFormat);
int getPlotX() const { return fPlot.fX; } int getPlotX() const { return fPlot.fX; }
int getPlotY() const { return fPlot.fY; } int getPlotY() const { return fPlot.fY; }
GrMaskFormat getMaskFormat() const { return fMaskFormat; }
GrTexture* texture() const { return fTexture; } GrTexture* texture() const { return fTexture; }
@ -56,6 +57,7 @@ private:
GrRectanizer* fRects; GrRectanizer* fRects;
GrAtlasMgr* fAtlasMgr; GrAtlasMgr* fAtlasMgr;
GrIPoint16 fPlot; GrIPoint16 fPlot;
GrMaskFormat fMaskFormat;
friend class GrAtlasMgr; friend class GrAtlasMgr;
}; };
@ -68,7 +70,7 @@ public:
~GrAtlasMgr(); ~GrAtlasMgr();
GrAtlas* addToAtlas(GrAtlas*, int width, int height, const void*, GrAtlas* addToAtlas(GrAtlas*, int width, int height, const void*,
GrIPoint16*); GrMaskFormat, GrIPoint16*);
GrTexture* getTexture() const { return fTexture; } GrTexture* getTexture() const { return fTexture; }

View File

@ -33,6 +33,7 @@ class GrPath;
class GrFontScaler : public GrRefCnt { class GrFontScaler : public GrRefCnt {
public: public:
virtual const GrKey* getKey() = 0; virtual const GrKey* getKey() = 0;
virtual GrMaskFormat getMaskFormat() = 0;
virtual bool getPackedGlyphBounds(GrGlyph::PackedID, GrIRect* bounds) = 0; virtual bool getPackedGlyphBounds(GrGlyph::PackedID, GrIRect* bounds) = 0;
virtual bool getPackedGlyphImage(GrGlyph::PackedID, int width, int height, virtual bool getPackedGlyphImage(GrGlyph::PackedID, int width, int height,
int rowBytes, void* image) = 0; int rowBytes, void* image) = 0;

View File

@ -35,11 +35,13 @@ class GrFontPurgeListener;
*/ */
class GrTextStrike { class GrTextStrike {
public: public:
GrTextStrike(GrFontCache*, const GrKey* fontScalerKey, GrAtlasMgr*); GrTextStrike(GrFontCache*, const GrKey* fontScalerKey, GrMaskFormat,
GrAtlasMgr*);
~GrTextStrike(); ~GrTextStrike();
const GrKey* getFontScalerKey() const { return fFontScalerKey; } const GrKey* getFontScalerKey() const { return fFontScalerKey; }
GrFontCache* getFontCache() const { return fFontCache; } GrFontCache* getFontCache() const { return fFontCache; }
GrMaskFormat getMaskFormat() const { return fMaskFormat; }
inline GrGlyph* getGlyph(GrGlyph::PackedID, GrFontScaler*); inline GrGlyph* getGlyph(GrGlyph::PackedID, GrFontScaler*);
bool getGlyphAtlas(GrGlyph*, GrFontScaler*); bool getGlyphAtlas(GrGlyph*, GrFontScaler*);
@ -66,6 +68,8 @@ private:
GrAtlasMgr* fAtlasMgr; GrAtlasMgr* fAtlasMgr;
GrAtlas* fAtlas; // linklist GrAtlas* fAtlas; // linklist
GrMaskFormat fMaskFormat;
GrGlyph* generateGlyph(GrGlyph::PackedID packed, GrFontScaler* scaler); GrGlyph* generateGlyph(GrGlyph::PackedID packed, GrFontScaler* scaler);
// returns true if after the purge, the strike is empty // returns true if after the purge, the strike is empty
bool purgeAtlasAtY(GrAtlas* atlas, int yCoord); bool purgeAtlasAtY(GrAtlas* atlas, int yCoord);

View File

@ -188,6 +188,22 @@ enum GrBlendCoeff {
kIDA_BlendCoeff, //<! one minus dst alpha kIDA_BlendCoeff, //<! one minus dst alpha
}; };
/**
* Formats for masks, used by the font cache
*/
enum GrMaskFormat {
kA8_GrMaskFormat, //!< 1-byte per pixel
kA565_GrMaskFormat //!< 2-bytes per pixel
};
/**
* Return the number of bytes-per-pixel for the specified mask format.
*/
static inline int GrMaskFormatBytesPerPixel(GrMaskFormat format) {
GrAssert((unsigned)format <= 1);
return (int)format + 1;
}
/** /**
* Set Operations used to construct clips. * Set Operations used to construct clips.
*/ */

View File

@ -51,7 +51,7 @@
static int gCounter; static int gCounter;
#endif #endif
GrAtlas::GrAtlas(GrAtlasMgr* mgr, int plotX, int plotY) { GrAtlas::GrAtlas(GrAtlasMgr* mgr, int plotX, int plotY, GrMaskFormat format) {
fAtlasMgr = mgr; // just a pointer, not an owner fAtlasMgr = mgr; // just a pointer, not an owner
fNext = NULL; fNext = NULL;
fTexture = mgr->getTexture(); // we're not an owner, just a pointer fTexture = mgr->getTexture(); // we're not an owner, just a pointer
@ -60,6 +60,8 @@ GrAtlas::GrAtlas(GrAtlasMgr* mgr, int plotX, int plotY) {
fRects = GrRectanizer::Factory(GR_ATLAS_WIDTH - BORDER, fRects = GrRectanizer::Factory(GR_ATLAS_WIDTH - BORDER,
GR_ATLAS_HEIGHT - BORDER); GR_ATLAS_HEIGHT - BORDER);
fMaskFormat = format;
#if GR_DEBUG #if GR_DEBUG
GrPrintf(" GrAtlas %p [%d %d] %d\n", this, plotX, plotY, gCounter); GrPrintf(" GrAtlas %p [%d %d] %d\n", this, plotX, plotY, gCounter);
gCounter += 1; gCounter += 1;
@ -82,6 +84,13 @@ static void adjustForPlot(GrIPoint16* loc, const GrIPoint16& plot) {
loc->fY += plot.fY * GR_ATLAS_HEIGHT; loc->fY += plot.fY * GR_ATLAS_HEIGHT;
} }
static uint8_t* zerofill(uint8_t* ptr, int count) {
while (--count >= 0) {
*ptr++ = 0;
}
return ptr;
}
bool GrAtlas::addSubImage(int width, int height, const void* image, bool GrAtlas::addSubImage(int width, int height, const void* image,
GrIPoint16* loc) { GrIPoint16* loc) {
if (!fRects->addRect(width + BORDER, height + BORDER, loc)) { if (!fRects->addRect(width + BORDER, height + BORDER, loc)) {
@ -89,23 +98,26 @@ bool GrAtlas::addSubImage(int width, int height, const void* image,
} }
GrAutoSMalloc<1024> storage; GrAutoSMalloc<1024> storage;
int srcW = width + 2*BORDER; int dstW = width + 2*BORDER;
int srcH = height + 2*BORDER; int dstH = height + 2*BORDER;
if (BORDER) { if (BORDER) {
uint8_t* ptr = (uint8_t*)storage.realloc(srcW * srcH); const int bpp = GrMaskFormatBytesPerPixel(fMaskFormat);
Gr_bzero(ptr, srcW); // zero top row const size_t dstRB = dstW * bpp;
ptr += srcW; uint8_t* dst = (uint8_t*)storage.realloc(dstH * dstRB);
Gr_bzero(dst, dstRB); // zero top row
dst += dstRB;
for (int y = 0; y < height; y++) { for (int y = 0; y < height; y++) {
*ptr++ = 0; // zero left edge dst = zerofill(dst, bpp); // zero left edge
memcpy(ptr, image, width); ptr += width; memcpy(dst, image, width * bpp);
*ptr++ = 0; // zero right edge dst += width * bpp;
image = (const void*)((const char*)image + width); dst = zerofill(dst, bpp); // zero right edge
image = (const void*)((const char*)image + width * bpp);
} }
Gr_bzero(ptr, srcW); // zero bottom row Gr_bzero(dst, dstRB); // zero bottom row
image = storage.get(); image = storage.get();
} }
adjustForPlot(loc, fPlot); adjustForPlot(loc, fPlot);
fTexture->uploadTextureData(loc->fX, loc->fY, srcW, srcH, image); fTexture->uploadTextureData(loc->fX, loc->fY, dstW, dstH, image);
// now tell the caller to skip the top/left BORDER // now tell the caller to skip the top/left BORDER
loc->fX += BORDER; loc->fX += BORDER;
@ -128,9 +140,23 @@ GrAtlasMgr::~GrAtlasMgr() {
fGpu->unref(); fGpu->unref();
} }
static GrTexture::PixelConfig maskformat2pixelconfig(GrMaskFormat format) {
switch (format) {
case kA8_GrMaskFormat:
return GrTexture::kAlpha_8_PixelConfig;
case kA565_GrMaskFormat:
return GrTexture::kRGB_565_PixelConfig;
default:
GrAssert(!"unknown maskformat");
}
return GrTexture::kUnknown_PixelConfig;
}
GrAtlas* GrAtlasMgr::addToAtlas(GrAtlas* atlas, GrAtlas* GrAtlasMgr::addToAtlas(GrAtlas* atlas,
int width, int height, const void* image, int width, int height, const void* image,
GrMaskFormat format,
GrIPoint16* loc) { GrIPoint16* loc) {
GrAssert(NULL == atlas || atlas->getMaskFormat() == format);
if (atlas && atlas->addSubImage(width, height, image, loc)) { if (atlas && atlas->addSubImage(width, height, image, loc)) {
return atlas; return atlas;
} }
@ -149,7 +175,7 @@ GrAtlas* GrAtlasMgr::addToAtlas(GrAtlas* atlas,
GrGpu::kNone_AALevel, GrGpu::kNone_AALevel,
GR_ATLAS_TEXTURE_WIDTH, GR_ATLAS_TEXTURE_WIDTH,
GR_ATLAS_TEXTURE_HEIGHT, GR_ATLAS_TEXTURE_HEIGHT,
GrTexture::kAlpha_8_PixelConfig maskformat2pixelconfig(format)
}; };
fTexture = fGpu->createTexture(desc, NULL, 0); fTexture = fGpu->createTexture(desc, NULL, 0);
if (NULL == fTexture) { if (NULL == fTexture) {
@ -157,7 +183,7 @@ GrAtlas* GrAtlasMgr::addToAtlas(GrAtlas* atlas,
} }
} }
GrAtlas* newAtlas = new GrAtlas(this, plot.fX, plot.fY); GrAtlas* newAtlas = new GrAtlas(this, plot.fX, plot.fY, format);
if (!newAtlas->addSubImage(width, height, image, loc)) { if (!newAtlas->addSubImage(width, height, image, loc)) {
delete newAtlas; delete newAtlas;
return NULL; return NULL;

View File

@ -41,7 +41,8 @@ GrTextStrike* GrFontCache::generateStrike(GrFontScaler* scaler,
if (NULL == fAtlasMgr) { if (NULL == fAtlasMgr) {
fAtlasMgr = new GrAtlasMgr(fGpu); fAtlasMgr = new GrAtlasMgr(fGpu);
} }
GrTextStrike* strike = new GrTextStrike(this, scaler->getKey(), fAtlasMgr); GrTextStrike* strike = new GrTextStrike(this, scaler->getKey(),
scaler->getMaskFormat(), fAtlasMgr);
fCache.insert(key, strike); fCache.insert(key, strike);
if (fHead) { if (fHead) {
@ -131,6 +132,7 @@ void GrFontCache::validate() const {
*/ */
GrTextStrike::GrTextStrike(GrFontCache* cache, const GrKey* key, GrTextStrike::GrTextStrike(GrFontCache* cache, const GrKey* key,
GrMaskFormat format,
GrAtlasMgr* atlasMgr) : fPool(64) { GrAtlasMgr* atlasMgr) : fPool(64) {
fFontScalerKey = key; fFontScalerKey = key;
fFontScalerKey->ref(); fFontScalerKey->ref();
@ -139,6 +141,8 @@ GrTextStrike::GrTextStrike(GrFontCache* cache, const GrKey* key,
fAtlasMgr = atlasMgr; // no need to ref, it won't go away before we do fAtlasMgr = atlasMgr; // no need to ref, it won't go away before we do
fAtlas = NULL; fAtlas = NULL;
fMaskFormat = format;
#if GR_DEBUG #if GR_DEBUG
GrPrintf(" GrTextStrike %p %d\n", this, gCounter); GrPrintf(" GrTextStrike %p %d\n", this, gCounter);
gCounter += 1; gCounter += 1;
@ -181,16 +185,19 @@ bool GrTextStrike::getGlyphAtlas(GrGlyph* glyph, GrFontScaler* scaler) {
GrAutoRef ar(scaler); GrAutoRef ar(scaler);
size_t size = glyph->fBounds.area(); int bytesPerPixel = GrMaskFormatBytesPerPixel(fMaskFormat);
size_t size = glyph->fBounds.area() * bytesPerPixel;
GrAutoSMalloc<1024> storage(size); GrAutoSMalloc<1024> storage(size);
if (!scaler->getPackedGlyphImage(glyph->fPackedID, glyph->width(), if (!scaler->getPackedGlyphImage(glyph->fPackedID, glyph->width(),
glyph->height(), glyph->width(), glyph->height(),
glyph->width() * bytesPerPixel,
storage.get())) { storage.get())) {
return false; return false;
} }
GrAtlas* atlas = fAtlasMgr->addToAtlas(fAtlas, glyph->width(), GrAtlas* atlas = fAtlasMgr->addToAtlas(fAtlas, glyph->width(),
glyph->height(), storage.get(), glyph->height(), storage.get(),
fMaskFormat,
&glyph->fAtlasLocation); &glyph->fAtlasLocation);
if (NULL == atlas) { if (NULL == atlas) {
return false; return false;

View File

@ -222,6 +222,10 @@ public:
SkScalerContext(const SkDescriptor* desc); SkScalerContext(const SkDescriptor* desc);
virtual ~SkScalerContext(); virtual ~SkScalerContext();
SkMask::Format getMaskFormat() const {
return (SkMask::Format)fRec.fMaskFormat;
}
// remember our glyph offset/base // remember our glyph offset/base
void setBaseGlyphCount(unsigned baseGlyphCount) { void setBaseGlyphCount(unsigned baseGlyphCount) {
fBaseGlyphCount = baseGlyphCount; fBaseGlyphCount = baseGlyphCount;

View File

@ -275,6 +275,7 @@ public:
// overrides // overrides
virtual const GrKey* getKey(); virtual const GrKey* getKey();
virtual GrMaskFormat getMaskFormat();
virtual bool getPackedGlyphBounds(GrGlyph::PackedID, GrIRect* bounds); virtual bool getPackedGlyphBounds(GrGlyph::PackedID, GrIRect* bounds);
virtual bool getPackedGlyphImage(GrGlyph::PackedID, int width, int height, virtual bool getPackedGlyphImage(GrGlyph::PackedID, int width, int height,
int rowBytes, void* image); int rowBytes, void* image);

View File

@ -98,6 +98,10 @@ public:
const SkDescriptor& getDescriptor() const { return *fDesc; } const SkDescriptor& getDescriptor() const { return *fDesc; }
SkMask::Format getMaskFormat() const {
return fScalerContext->getMaskFormat();
}
/* AuxProc/Data allow a client to associate data with this cache entry. /* AuxProc/Data allow a client to associate data with this cache entry.
Multiple clients can use this, as their data is keyed with a function Multiple clients can use this, as their data is keyed with a function
pointer. In addition to serving as a key, the function pointer is called pointer. In addition to serving as a key, the function pointer is called

View File

@ -83,6 +83,19 @@ SkGrFontScaler::~SkGrFontScaler() {
GrSafeUnref(fKey); GrSafeUnref(fKey);
} }
GrMaskFormat SkGrFontScaler::getMaskFormat() {
SkMask::Format format = fStrike->getMaskFormat();
switch (format) {
case SkMask::kA8_Format:
return kA8_GrMaskFormat;
case SkMask::kLCD16_Format:
return kA565_GrMaskFormat;
default:
GrAssert(!"unsupported SkMask::Format");
return kA8_GrMaskFormat;
}
}
const GrKey* SkGrFontScaler::getKey() { const GrKey* SkGrFontScaler::getKey() {
if (NULL == fKey) { if (NULL == fKey) {
fKey = new SkGrDescKey(fStrike->getDescriptor()); fKey = new SkGrDescKey(fStrike->getDescriptor());
@ -117,8 +130,9 @@ bool SkGrFontScaler::getPackedGlyphImage(GrGlyph::PackedID packed,
if (srcRB == dstRB) { if (srcRB == dstRB) {
memcpy(dst, src, dstRB * height); memcpy(dst, src, dstRB * height);
} else { } else {
const int bbp = GrMaskFormatBytesPerPixel(this->getMaskFormat());
for (int y = 0; y < height; y++) { for (int y = 0; y < height; y++) {
memcpy(dst, src, width); memcpy(dst, src, width * bbp);
src = (const char*)src + srcRB; src = (const char*)src + srcRB;
dst = (char*)dst + dstRB; dst = (char*)dst + dstRB;
} }