Commit c06f4c40 authored by Krzysztof Kowalczyk's avatar Krzysztof Kowalczyk
Browse files

Perf improvement for some scenarios by caching SplashPath.

PDF from https://bugs.freedesktop.org/show_bug.cgi?id=11849
shows a high rate of creation/destruction of SplashPath
objects. At the same time, only a few exists at the same
time. This patch implements a small cache to recycle
SplashPath objects. In my test rendering time for the above
PDF dropped ~4%, mostly thanks to decent reduction in
malloc/free calls.
parent 1636f44d
......@@ -1170,7 +1170,7 @@ void SplashOutputDev::stroke(GfxState *state) {
}
path = convertPath(state, state->getPath());
splash->stroke(path);
delete path;
SplashPath::destroy(path);
}
void SplashOutputDev::fill(GfxState *state) {
......@@ -1181,7 +1181,7 @@ void SplashOutputDev::fill(GfxState *state) {
}
path = convertPath(state, state->getPath());
splash->fill(path, gFalse);
delete path;
SplashPath::destroy(path);
}
void SplashOutputDev::eoFill(GfxState *state) {
......@@ -1192,7 +1192,7 @@ void SplashOutputDev::eoFill(GfxState *state) {
}
path = convertPath(state, state->getPath());
splash->fill(path, gTrue);
delete path;
SplashPath::destroy(path);
}
void SplashOutputDev::clip(GfxState *state) {
......@@ -1200,7 +1200,7 @@ void SplashOutputDev::clip(GfxState *state) {
path = convertPath(state, state->getPath());
splash->clipToPath(path, gFalse);
delete path;
SplashPath::destroy(path);
}
void SplashOutputDev::eoClip(GfxState *state) {
......@@ -1208,7 +1208,7 @@ void SplashOutputDev::eoClip(GfxState *state) {
path = convertPath(state, state->getPath());
splash->clipToPath(path, gTrue);
delete path;
SplashPath::destroy(path);
}
void SplashOutputDev::clipToStrokePath(GfxState *state) {
......@@ -1216,9 +1216,9 @@ void SplashOutputDev::clipToStrokePath(GfxState *state) {
path = convertPath(state, state->getPath());
path2 = splash->makeStrokePath(path);
delete path;
SplashPath::destroy(path);
splash->clipToPath(path2, gFalse);
delete path2;
SplashPath::destroy(path2);
}
SplashPath *SplashOutputDev::convertPath(GfxState * /*state*/, GfxPath *path) {
......@@ -1226,7 +1226,7 @@ SplashPath *SplashOutputDev::convertPath(GfxState * /*state*/, GfxPath *path) {
GfxSubpath *subpath;
int i, j;
sPath = new SplashPath();
sPath = SplashPath::create();
for (i = 0; i < path->getNumSubpaths(); ++i) {
subpath = path->getSubpath(i);
if (subpath->getNumPoints() > 0) {
......@@ -1291,9 +1291,9 @@ void SplashOutputDev::drawChar(GfxState *state, double x, double y,
if ((render & 3) == 1 || (render & 3) == 2) {
if (!state->getStrokeColorSpace()->isNonMarking()) {
if ((path = font->getGlyphPath(code))) {
path->offset((SplashCoord)x, (SplashCoord)y);
splash->stroke(path);
delete path;
path->offset((SplashCoord)x, (SplashCoord)y);
splash->stroke(path);
SplashPath::destroy(path);
}
}
}
......@@ -1303,10 +1303,10 @@ void SplashOutputDev::drawChar(GfxState *state, double x, double y,
if ((path = font->getGlyphPath(code))) {
path->offset((SplashCoord)x, (SplashCoord)y);
if (textClipPath) {
textClipPath->append(path);
delete path;
textClipPath->append(path);
SplashPath::destroy(path);
} else {
textClipPath = path;
textClipPath = path;
}
}
}
......@@ -1585,7 +1585,7 @@ void SplashOutputDev::drawType3Glyph(T3FontCache *t3Font,
void SplashOutputDev::endTextObject(GfxState *state) {
if (textClipPath) {
splash->clipToPath(textClipPath, gFalse);
delete textClipPath;
SplashPath::destroy(textClipPath);
textClipPath = NULL;
}
}
......
......@@ -1184,7 +1184,7 @@ SplashError Splash::stroke(SplashPath *path) {
path2 = flattenPath(path, state->matrix, state->flatness);
if (state->lineDashLength > 0) {
dPath = makeDashedPath(path2);
delete path2;
SplashPath::destroy(path2);
path2 = dPath;
}
if (state->lineWidth == 0) {
......@@ -1192,7 +1192,7 @@ SplashError Splash::stroke(SplashPath *path) {
} else {
strokeWide(path2);
}
delete path2;
SplashPath::destroy(path2);
return splashOk;
}
......@@ -1310,7 +1310,7 @@ void Splash::strokeWide(SplashPath *path) {
path2 = makeStrokePath(path, gFalse);
fillWithPattern(path2, gFalse, state->strokePattern, state->strokeAlpha);
delete path2;
SplashPath::destroy(path2);
}
SplashPath *Splash::flattenPath(SplashPath *path, SplashCoord *matrix,
......@@ -1320,7 +1320,7 @@ SplashPath *Splash::flattenPath(SplashPath *path, SplashCoord *matrix,
Guchar flag;
int i;
fPath = new SplashPath();
fPath = SplashPath::create();
flatness2 = flatness * flatness;
i = 0;
while (i < path->length) {
......@@ -1451,7 +1451,7 @@ SplashPath *Splash::makeDashedPath(SplashPath *path) {
++lineDashStartIdx;
}
dPath = new SplashPath();
dPath = SplashPath::create();
// process each subpath
i = 0;
......@@ -3219,7 +3219,7 @@ SplashPath *Splash::makeStrokePath(SplashPath *path, GBool flatten) {
pathIn = flattenPath(path, state->matrix, state->flatness);
if (state->lineDashLength > 0) {
pathOut = makeDashedPath(pathIn);
delete pathIn;
SplashPath::destroy(pathIn);
pathIn = pathOut;
}
} else {
......@@ -3231,7 +3231,7 @@ SplashPath *Splash::makeStrokePath(SplashPath *path, GBool flatten) {
left0 = left1 = right0 = right1 = join0 = join1 = 0; // make gcc happy
leftFirst = rightFirst = firstPt = 0; // make gcc happy
pathOut = new SplashPath();
pathOut = SplashPath::create();
w = state->lineWidth;
for (i = 0; i < pathIn->length - 1; ++i) {
......@@ -3491,7 +3491,7 @@ SplashPath *Splash::makeStrokePath(SplashPath *path, GBool flatten) {
}
if (pathIn != path) {
delete pathIn;
SplashPath::destroy(pathIn);
}
return pathOut;
......
......@@ -268,7 +268,7 @@ SplashPath *SplashFTFont::getGlyphPath(int c) {
if (FT_Get_Glyph(slot, &glyph)) {
return NULL;
}
path.path = new SplashPath();
path.path = SplashPath::create();
path.textScale = textScale;
path.needClose = gFalse;
FT_Outline_Decompose(&((FT_OutlineGlyph)glyph)->outline,
......
......@@ -15,6 +15,42 @@
#include "SplashErrorCodes.h"
#include "SplashPath.h"
// According to my profiling, number of SplahPath objects created at the same
// time rarely exceeds 4, so this is a good number for the size of the cache
#define CACHE_SIZE 4
static int cachedCount = 0;
static SplashPath* splashPathCache[CACHE_SIZE] = { NULL };
SplashPath* SplashPath::create()
{
SplashPath* result = NULL;
if (cachedCount > 0) {
result = splashPathCache[--cachedCount];
} else {
result = new SplashPath();
}
return result;
}
void SplashPath::destroy(SplashPath* path)
{
if (cachedCount < CACHE_SIZE) {
path->Reset();
splashPathCache[cachedCount++] = path;
}
else
delete path;
}
void SplashPath::emptyCache()
{
for (int i=0; i < cachedCount; i++) {
delete splashPathCache[i];
}
cachedCount = 0;
}
//------------------------------------------------------------------------
// SplashPath
//------------------------------------------------------------------------
......@@ -182,3 +218,12 @@ GBool SplashPath::getCurPt(SplashCoord *x, SplashCoord *y) {
*y = pts[length - 1].y;
return gTrue;
}
void SplashPath::Reset()
{
// TODO: possibly free data if size is above some threshold to avoid
// cache eating too much memory
length = 0;
hintsLength = 0;
}
......@@ -54,14 +54,13 @@ struct SplashPathHint {
class SplashPath {
public:
// Create an empty path.
SplashPath();
static SplashPath* create();
static void destroy(SplashPath* path);
static void emptyCache();
// Copy a path.
SplashPath *copy() { return new SplashPath(this); }
~SplashPath();
// Append <path> to <this>.
void append(SplashPath *path);
......@@ -96,9 +95,15 @@ public:
// Get the current point.
GBool getCurPt(SplashCoord *x, SplashCoord *y);
void Reset();
private:
// Create an empty path.
SplashPath();
SplashPath(SplashPath *path);
~SplashPath();
void grow(int nPts);
GBool noCurrentPoint() { return curSubpath == length; }
GBool onePointSubpath() { return curSubpath == length - 1; }
......
......@@ -238,7 +238,7 @@ SplashPath *SplashT1Font::getGlyphPath(int c) {
T1_TransformFont(outlineID, &matrix);
}
path = new SplashPath();
path = SplashPath::create();
if ((outline = T1_GetCharOutline(outlineID, c, outlineSize, NULL))) {
x = 0;
y = 0;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment