Allocate only the vertices we need for text.

This restructures the vertex allocation for text rendering to compute
the max number of vertices we would need for a line of text, and then
only allocate that much. If this number exceeds the quad index limit,
then it will allocate for the max number of quads, and reallocate for
the rest later.

Review URL: https://codereview.chromium.org/663423003
This commit is contained in:
jvanverth 2014-10-23 11:57:12 -07:00 committed by Commit bot
parent 70649c174b
commit 73f1053450
6 changed files with 114 additions and 114 deletions

View File

@ -47,8 +47,10 @@ extern const GrVertexAttrib gTextVertexWithColorAttribs[] = {
{kVec2f_GrVertexAttribType, sizeof(SkPoint) + sizeof(GrColor), kGeometryProcessor_GrVertexAttribBinding}
};
static const size_t kTextVAColorSize = 2 * sizeof(SkPoint) + sizeof(GrColor);
static const size_t kTextVAColorSize = 2 * sizeof(SkPoint) + sizeof(GrColor);
static const int kVerticesPerGlyph = 4;
static const int kIndicesPerGlyph = 6;
};
GrBitmapTextContext::GrBitmapTextContext(GrContext* context,
@ -57,11 +59,12 @@ GrBitmapTextContext::GrBitmapTextContext(GrContext* context,
fStrike = NULL;
fCurrTexture = NULL;
fCurrVertex = 0;
fEffectTextureUniqueID = SK_InvalidUniqueID;
fVertices = NULL;
fMaxVertices = 0;
fCurrVertex = 0;
fAllocVertexCount = 0;
fTotalVertexCount = 0;
fVertexBounds.setLargestInverted();
}
@ -72,7 +75,7 @@ GrBitmapTextContext* GrBitmapTextContext::Create(GrContext* context,
}
GrBitmapTextContext::~GrBitmapTextContext() {
this->flush();
this->finish();
}
bool GrBitmapTextContext::canDraw(const SkPaint& paint) {
@ -88,7 +91,8 @@ inline void GrBitmapTextContext::init(const GrPaint& paint, const SkPaint& skPai
fCurrVertex = 0;
fVertices = NULL;
fMaxVertices = 0;
fAllocVertexCount = 0;
fTotalVertexCount = 0;
}
void GrBitmapTextContext::onDrawText(const GrPaint& paint, const SkPaint& skPaint,
@ -118,13 +122,13 @@ void GrBitmapTextContext::onDrawText(const GrPaint& paint, const SkPaint& skPain
}
// need to measure first
int numGlyphs;
if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) {
SkVector stop;
SkVector stopVector;
numGlyphs = MeasureText(cache, glyphCacheProc, text, byteLength, &stopVector);
MeasureText(cache, glyphCacheProc, text, byteLength, &stop);
SkScalar stopX = stop.fX;
SkScalar stopY = stop.fY;
SkScalar stopX = stopVector.fX;
SkScalar stopY = stopVector.fY;
if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) {
stopX = SkScalarHalf(stopX);
@ -132,7 +136,10 @@ void GrBitmapTextContext::onDrawText(const GrPaint& paint, const SkPaint& skPain
}
x -= stopX;
y -= stopY;
} else {
numGlyphs = fSkPaint.textToGlyphs(text, byteLength, NULL);
}
fTotalVertexCount = kVerticesPerGlyph*numGlyphs;
const char* stop = text + byteLength;
@ -207,6 +214,9 @@ void GrBitmapTextContext::onDrawPosText(const GrPaint& paint, const SkPaint& skP
GrContext::AutoMatrix autoMatrix;
autoMatrix.setIdentity(fContext, &fPaint);
int numGlyphs = fSkPaint.textToGlyphs(text, byteLength, NULL);
fTotalVertexCount = kVerticesPerGlyph*numGlyphs;
const char* stop = text + byteLength;
SkTextAlignProc alignProc(fSkPaint.getTextAlign());
SkTextMapStateProc tmsProc(ctm, offset, scalarsPerPosition);
@ -335,6 +345,28 @@ void GrBitmapTextContext::onDrawPosText(const GrPaint& paint, const SkPaint& skP
this->finish();
}
static void* alloc_vertices(GrDrawTarget* drawTarget, int numVertices, bool useColorVerts) {
if (numVertices <= 0) {
return NULL;
}
// set up attributes
if (useColorVerts) {
drawTarget->drawState()->setVertexAttribs<gTextVertexWithColorAttribs>(
SK_ARRAY_COUNT(gTextVertexWithColorAttribs), kTextVAColorSize);
} else {
drawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
SK_ARRAY_COUNT(gTextVertexAttribs), kTextVASize);
}
void* vertices = NULL;
bool success = drawTarget->reserveVertexAndIndexSpace(numVertices,
0,
&vertices,
NULL);
GrAlwaysAssert(success);
return vertices;
}
void GrBitmapTextContext::appendGlyph(GrGlyph::PackedID packed,
SkFixed vx, SkFixed vy,
GrFontScaler* scaler) {
@ -418,6 +450,9 @@ void GrBitmapTextContext::appendGlyph(GrGlyph::PackedID packed,
am.setPreConcat(fContext, translate, &tmpPaint);
GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle);
fContext->drawPath(tmpPaint, *glyph->fPath, strokeInfo);
// remove this glyph from the vertices we need to allocate
fTotalVertexCount -= kVerticesPerGlyph;
return;
}
@ -434,7 +469,7 @@ HAS_ATLAS:
GrTexture* texture = glyph->fPlot->texture();
SkASSERT(texture);
if (fCurrTexture != texture || fCurrVertex + 4 > fMaxVertices) {
if (fCurrTexture != texture || fCurrVertex + kVerticesPerGlyph > fAllocVertexCount) {
this->flush();
fCurrTexture = texture;
fCurrTexture->ref();
@ -444,44 +479,9 @@ HAS_ATLAS:
bool useColorVerts = kA8_GrMaskFormat == fCurrMaskFormat;
if (NULL == fVertices) {
// If we need to reserve vertices allow the draw target to suggest
// a number of verts to reserve and whether to perform a flush.
fMaxVertices = kMinRequestedVerts;
if (useColorVerts) {
fDrawTarget->drawState()->setVertexAttribs<gTextVertexWithColorAttribs>(
SK_ARRAY_COUNT(gTextVertexWithColorAttribs), kTextVAColorSize);
} else {
fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
SK_ARRAY_COUNT(gTextVertexAttribs), kTextVASize);
}
bool flush = fDrawTarget->geometryHints(&fMaxVertices, NULL);
if (flush) {
this->flush();
fContext->flush();
if (useColorVerts) {
fDrawTarget->drawState()->setVertexAttribs<gTextVertexWithColorAttribs>(
SK_ARRAY_COUNT(gTextVertexWithColorAttribs), kTextVAColorSize);
} else {
fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
SK_ARRAY_COUNT(gTextVertexAttribs), kTextVASize);
}
}
fMaxVertices = kDefaultRequestedVerts;
// ignore return, no point in flushing again.
fDrawTarget->geometryHints(&fMaxVertices, NULL);
int maxQuadVertices = 4 * fContext->getQuadIndexBuffer()->maxQuads();
if (fMaxVertices < kMinRequestedVerts) {
fMaxVertices = kDefaultRequestedVerts;
} else if (fMaxVertices > maxQuadVertices) {
// don't exceed the limit of the index buffer
fMaxVertices = maxQuadVertices;
}
bool success = fDrawTarget->reserveVertexAndIndexSpace(fMaxVertices,
0,
&fVertices,
NULL);
GrAlwaysAssert(success);
int maxQuadVertices = kVerticesPerGlyph * fContext->getQuadIndexBuffer()->maxQuads();
fAllocVertexCount = SkMin32(fTotalVertexCount, maxQuadVertices);
fVertices = alloc_vertices(fDrawTarget, fAllocVertexCount, useColorVerts);
}
SkFixed tx = SkIntToFixed(glyph->fAtlasLocation.fX);
@ -597,15 +597,17 @@ void GrBitmapTextContext::flush() {
default:
SkFAIL("Unexpected mask format.");
}
int nGlyphs = fCurrVertex / 4;
int nGlyphs = fCurrVertex / kVerticesPerGlyph;
fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
fDrawTarget->drawIndexedInstances(kTriangles_GrPrimitiveType,
nGlyphs,
4, 6, &fVertexBounds);
kVerticesPerGlyph, kIndicesPerGlyph, &fVertexBounds);
fDrawTarget->resetVertexSource();
fVertices = NULL;
fMaxVertices = 0;
fAllocVertexCount = 0;
// reset to be those that are left
fTotalVertexCount -= fCurrVertex;
fCurrVertex = 0;
fVertexBounds.setLargestInverted();
SkSafeSetNull(fCurrTexture);
@ -614,6 +616,7 @@ void GrBitmapTextContext::flush() {
inline void GrBitmapTextContext::finish() {
this->flush();
fTotalVertexCount = 0;
GrTextContext::finish();
}

View File

@ -23,17 +23,11 @@ public:
virtual ~GrBitmapTextContext();
private:
enum {
kMinRequestedGlyphs = 1,
kDefaultRequestedGlyphs = 64,
kMinRequestedVerts = kMinRequestedGlyphs * 4,
kDefaultRequestedVerts = kDefaultRequestedGlyphs * 4,
};
GrTextStrike* fStrike;
void* fVertices;
int fCurrVertex;
int fMaxVertices;
int fAllocVertexCount;
int fTotalVertexCount;
SkRect fVertexBounds;
GrTexture* fCurrTexture;
GrMaskFormat fCurrMaskFormat;

View File

@ -56,6 +56,8 @@ extern const GrVertexAttrib gTextVertexWithColorAttribs[] = {
static const size_t kTextVAColorSize = 2 * sizeof(SkPoint) + sizeof(GrColor);
static const int kVerticesPerGlyph = 4;
static const int kIndicesPerGlyph = 6;
};
GrDistanceFieldTextContext::GrDistanceFieldTextContext(GrContext* context,
@ -70,14 +72,15 @@ GrDistanceFieldTextContext::GrDistanceFieldTextContext(GrContext* context,
fStrike = NULL;
fGammaTexture = NULL;
fCurrTexture = NULL;
fCurrVertex = 0;
fEffectTextureUniqueID = SK_InvalidUniqueID;
fEffectColor = GrColor_ILLEGAL;
fEffectFlags = 0;
fVertices = NULL;
fMaxVertices = 0;
fCurrVertex = 0;
fAllocVertexCount = 0;
fTotalVertexCount = 0;
fCurrTexture = NULL;
fVertexBounds.setLargestInverted();
}
@ -93,7 +96,7 @@ GrDistanceFieldTextContext* GrDistanceFieldTextContext::Create(GrContext* contex
}
GrDistanceFieldTextContext::~GrDistanceFieldTextContext() {
this->flush();
this->finish();
SkSafeSetNull(fGammaTexture);
}
@ -145,9 +148,10 @@ inline void GrDistanceFieldTextContext::init(const GrPaint& paint, const SkPaint
scaledTextSize *= maxScale;
}
fCurrVertex = 0;
fVertices = NULL;
fCurrVertex = 0;
fAllocVertexCount = 0;
fTotalVertexCount = 0;
if (scaledTextSize <= kSmallDFFontLimit) {
fTextRatio = textSize / kSmallDFFontSize;
@ -166,7 +170,6 @@ inline void GrDistanceFieldTextContext::init(const GrPaint& paint, const SkPaint
fSkPaint.setAutohinted(false);
fSkPaint.setHinting(SkPaint::kNormal_Hinting);
fSkPaint.setSubpixelText(true);
}
static void setup_gamma_texture(GrContext* context, const SkGlyphCache* cache,
@ -293,6 +296,9 @@ void GrDistanceFieldTextContext::onDrawPosText(const GrPaint& paint, const SkPai
setup_gamma_texture(fContext, cache, fDeviceProperties, &fGammaTexture);
int numGlyphs = fSkPaint.textToGlyphs(text, byteLength, NULL);
fTotalVertexCount = kVerticesPerGlyph*numGlyphs;
const char* stop = text + byteLength;
SkTArray<char> fallbackTxt;
SkTArray<SkScalar> fallbackPos;
@ -371,6 +377,28 @@ static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) {
return GrColorPackRGBA(r, g, b, 0xff);
}
static void* alloc_vertices(GrDrawTarget* drawTarget, int numVertices, bool useColorVerts) {
if (numVertices <= 0) {
return NULL;
}
// set up attributes
if (useColorVerts) {
drawTarget->drawState()->setVertexAttribs<gTextVertexWithColorAttribs>(
SK_ARRAY_COUNT(gTextVertexWithColorAttribs), kTextVAColorSize);
} else {
drawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
SK_ARRAY_COUNT(gTextVertexAttribs), kTextVASize);
}
void* vertices = NULL;
bool success = drawTarget->reserveVertexAndIndexSpace(numVertices,
0,
&vertices,
NULL);
GrAlwaysAssert(success);
return vertices;
}
void GrDistanceFieldTextContext::setupCoverageEffect(const SkColor& filteredColor) {
GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kBilerp_FilterMode);
GrTextureParams gammaParams(SkShader::kClamp_TileMode, GrTextureParams::kNone_FilterMode);
@ -515,6 +543,9 @@ bool GrDistanceFieldTextContext::appendGlyph(GrGlyph::PackedID packed,
am.setPreConcat(fContext, ctm, &tmpPaint);
GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle);
fContext->drawPath(tmpPaint, *glyph->fPath, strokeInfo);
// remove this glyph from the vertices we need to allocate
fTotalVertexCount -= kVerticesPerGlyph;
return true;
}
@ -526,7 +557,7 @@ HAS_ATLAS:
GrTexture* texture = glyph->fPlot->texture();
SkASSERT(texture);
if (fCurrTexture != texture || fCurrVertex + 4 > fMaxVertices) {
if (fCurrTexture != texture || fCurrVertex + kVerticesPerGlyph > fTotalVertexCount) {
this->flush();
fCurrTexture = texture;
fCurrTexture->ref();
@ -535,44 +566,9 @@ HAS_ATLAS:
bool useColorVerts = !fUseLCDText;
if (NULL == fVertices) {
// If we need to reserve vertices allow the draw target to suggest
// a number of verts to reserve and whether to perform a flush.
fMaxVertices = kMinRequestedVerts;
if (useColorVerts) {
fDrawTarget->drawState()->setVertexAttribs<gTextVertexWithColorAttribs>(
SK_ARRAY_COUNT(gTextVertexWithColorAttribs), kTextVAColorSize);
} else {
fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
SK_ARRAY_COUNT(gTextVertexAttribs), kTextVASize);
}
bool flush = fDrawTarget->geometryHints(&fMaxVertices, NULL);
if (flush) {
this->flush();
fContext->flush();
if (useColorVerts) {
fDrawTarget->drawState()->setVertexAttribs<gTextVertexWithColorAttribs>(
SK_ARRAY_COUNT(gTextVertexWithColorAttribs), kTextVAColorSize);
} else {
fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
SK_ARRAY_COUNT(gTextVertexAttribs), kTextVASize);
}
}
fMaxVertices = kDefaultRequestedVerts;
// ignore return, no point in flushing again.
fDrawTarget->geometryHints(&fMaxVertices, NULL);
int maxQuadVertices = 4 * fContext->getQuadIndexBuffer()->maxQuads();
if (fMaxVertices < kMinRequestedVerts) {
fMaxVertices = kDefaultRequestedVerts;
} else if (fMaxVertices > maxQuadVertices) {
// don't exceed the limit of the index buffer
fMaxVertices = maxQuadVertices;
}
bool success = fDrawTarget->reserveVertexAndIndexSpace(fMaxVertices,
0,
&fVertices,
NULL);
GrAlwaysAssert(success);
int maxQuadVertices = kVerticesPerGlyph * fContext->getQuadIndexBuffer()->maxQuads();
fAllocVertexCount = SkMin32(fTotalVertexCount, maxQuadVertices);
fVertices = alloc_vertices(fDrawTarget, fAllocVertexCount, useColorVerts);
}
SkScalar dx = SkIntToScalar(glyph->fBounds.fLeft + SK_DistanceFieldInset);
@ -687,14 +683,14 @@ void GrDistanceFieldTextContext::flush() {
// We're using per-vertex color.
SkASSERT(drawState->hasColorVertexAttribute());
}
int nGlyphs = fCurrVertex / 4;
int nGlyphs = fCurrVertex / kVerticesPerGlyph;
fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
fDrawTarget->drawIndexedInstances(kTriangles_GrPrimitiveType,
nGlyphs,
4, 6, &fVertexBounds);
kVerticesPerGlyph, kIndicesPerGlyph, &fVertexBounds);
fDrawTarget->resetVertexSource();
fVertices = NULL;
fMaxVertices = 0;
fTotalVertexCount -= fCurrVertex;
fCurrVertex = 0;
SkSafeSetNull(fCurrTexture);
fVertexBounds.setLargestInverted();
@ -703,6 +699,7 @@ void GrDistanceFieldTextContext::flush() {
inline void GrDistanceFieldTextContext::finish() {
this->flush();
fTotalVertexCount = 0;
GrTextContext::finish();
}

View File

@ -41,9 +41,10 @@ private:
uint32_t fEffectFlags;
GrTexture* fGammaTexture;
void* fVertices;
int32_t fMaxVertices;
GrTexture* fCurrTexture;
int fCurrVertex;
int fAllocVertexCount;
int fTotalVertexCount;
GrTexture* fCurrTexture;
SkRect fVertexBounds;
GrDistanceFieldTextContext(GrContext*, const SkDeviceProperties&, bool enable);

View File

@ -76,13 +76,14 @@ bool GrTextContext::drawPosText(const GrPaint& paint, const SkPaint& skPaint,
//*** change to output positions?
void GrTextContext::MeasureText(SkGlyphCache* cache, SkDrawCacheProc glyphCacheProc,
int GrTextContext::MeasureText(SkGlyphCache* cache, SkDrawCacheProc glyphCacheProc,
const char text[], size_t byteLength, SkVector* stopVector) {
SkFixed x = 0, y = 0;
const char* stop = text + byteLength;
SkAutoKern autokern;
int numGlyphs = 0;
while (text < stop) {
// don't need x, y here, since all subpixel variants will have the
// same advance
@ -90,10 +91,13 @@ void GrTextContext::MeasureText(SkGlyphCache* cache, SkDrawCacheProc glyphCacheP
x += autokern.adjust(glyph) + glyph.fAdvanceX;
y += glyph.fAdvanceY;
++numGlyphs;
}
stopVector->set(SkFixedToScalar(x), SkFixedToScalar(y));
SkASSERT(text == stop);
return numGlyphs;
}
static void GlyphCacheAuxProc(void* data) {

View File

@ -57,8 +57,9 @@ protected:
void finish() { fDrawTarget = NULL; }
static GrFontScaler* GetGrFontScaler(SkGlyphCache* cache);
static void MeasureText(SkGlyphCache* cache, SkDrawCacheProc glyphCacheProc,
const char text[], size_t byteLength, SkVector* stopVector);
// sets extent in stopVector and returns glyph count
static int MeasureText(SkGlyphCache* cache, SkDrawCacheProc glyphCacheProc,
const char text[], size_t byteLength, SkVector* stopVector);
};
#endif