1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

Tweaked the rate at which EdgeTable grows its internal storage, to improve performance rendering large and complex paths

This commit is contained in:
jules 2017-10-09 14:53:56 +01:00
parent be3e9161be
commit 93a22599d1
2 changed files with 110 additions and 109 deletions

View file

@ -30,12 +30,10 @@ namespace juce
const int juce_edgeTableDefaultEdgesPerLine = 32;
//==============================================================================
EdgeTable::EdgeTable (const Rectangle<int>& area,
const Path& path, const AffineTransform& transform)
EdgeTable::EdgeTable (Rectangle<int> area, const Path& path, const AffineTransform& transform)
: bounds (area),
maxEdgesPerLine (juce_edgeTableDefaultEdgesPerLine),
lineStrideElements (juce_edgeTableDefaultEdgesPerLine * 2 + 1),
needToCheckEmptiness (true)
lineStrideElements (juce_edgeTableDefaultEdgesPerLine * 2 + 1)
{
allocate();
int* t = table;
@ -46,24 +44,24 @@ EdgeTable::EdgeTable (const Rectangle<int>& area,
t += lineStrideElements;
}
const int leftLimit = bounds.getX() << 8;
const int topLimit = bounds.getY() << 8;
const int rightLimit = bounds.getRight() << 8;
const int heightLimit = bounds.getHeight() << 8;
auto leftLimit = bounds.getX() << 8;
auto topLimit = bounds.getY() << 8;
auto rightLimit = bounds.getRight() << 8;
auto heightLimit = bounds.getHeight() << 8;
PathFlatteningIterator iter (path, transform);
while (iter.next())
{
int y1 = roundToInt (iter.y1 * 256.0f);
int y2 = roundToInt (iter.y2 * 256.0f);
auto y1 = roundToInt (iter.y1 * 256.0f);
auto y2 = roundToInt (iter.y2 * 256.0f);
if (y1 != y2)
{
y1 -= topLimit;
y2 -= topLimit;
const int startY = y1;
auto startY = y1;
int direction = -1;
if (y1 > y2)
@ -82,12 +80,12 @@ EdgeTable::EdgeTable (const Rectangle<int>& area,
{
const double startX = 256.0f * iter.x1;
const double multiplier = (iter.x2 - iter.x1) / (iter.y2 - iter.y1);
const int stepSize = jlimit (1, 256, 256 / (1 + (int) std::abs (multiplier)));
auto stepSize = jlimit (1, 256, 256 / (1 + (int) std::abs (multiplier)));
do
{
const int step = jmin (stepSize, y2 - y1, 256 - (y1 & 255));
int x = roundToInt (startX + multiplier * ((y1 + (step >> 1)) - startY));
auto step = jmin (stepSize, y2 - y1, 256 - (y1 & 255));
auto x = roundToInt (startX + multiplier * ((y1 + (step >> 1)) - startY));
if (x < leftLimit)
x = leftLimit;
@ -105,19 +103,18 @@ EdgeTable::EdgeTable (const Rectangle<int>& area,
sanitiseLevels (path.isUsingNonZeroWinding());
}
EdgeTable::EdgeTable (const Rectangle<int>& rectangleToAdd)
EdgeTable::EdgeTable (Rectangle<int> rectangleToAdd)
: bounds (rectangleToAdd),
maxEdgesPerLine (juce_edgeTableDefaultEdgesPerLine),
lineStrideElements (juce_edgeTableDefaultEdgesPerLine * 2 + 1),
needToCheckEmptiness (true)
lineStrideElements (juce_edgeTableDefaultEdgesPerLine * 2 + 1)
{
allocate();
table[0] = 0;
const int x1 = rectangleToAdd.getX() << 8;
const int x2 = rectangleToAdd.getRight() << 8;
auto x1 = rectangleToAdd.getX() << 8;
auto x2 = rectangleToAdd.getRight() << 8;
int* t = table;
for (int i = rectangleToAdd.getHeight(); --i >= 0;)
{
t[0] = 2;
@ -140,9 +137,9 @@ EdgeTable::EdgeTable (const RectangleList<int>& rectanglesToAdd)
for (auto& r : rectanglesToAdd)
{
const int x1 = r.getX() << 8;
const int x2 = r.getRight() << 8;
int y = r.getY() - bounds.getY();
auto x1 = r.getX() << 8;
auto x2 = r.getRight() << 8;
auto y = r.getY() - bounds.getY();
for (int j = r.getHeight(); --j >= 0;)
addEdgePointPair (x1, x2, y++, 255);
@ -154,8 +151,7 @@ EdgeTable::EdgeTable (const RectangleList<int>& rectanglesToAdd)
EdgeTable::EdgeTable (const RectangleList<float>& rectanglesToAdd)
: bounds (rectanglesToAdd.getBounds().getSmallestIntegerContainer()),
maxEdgesPerLine (rectanglesToAdd.getNumRectangles() * 2),
lineStrideElements (rectanglesToAdd.getNumRectangles() * 4 + 1),
needToCheckEmptiness (true)
lineStrideElements (rectanglesToAdd.getNumRectangles() * 4 + 1)
{
bounds.setHeight (bounds.getHeight() + 1);
allocate();
@ -163,17 +159,17 @@ EdgeTable::EdgeTable (const RectangleList<float>& rectanglesToAdd)
for (auto& r : rectanglesToAdd)
{
const int x1 = roundToInt (r.getX() * 256.0f);
const int x2 = roundToInt (r.getRight() * 256.0f);
auto x1 = roundToInt (r.getX() * 256.0f);
auto x2 = roundToInt (r.getRight() * 256.0f);
const int y1 = roundToInt (r.getY() * 256.0f) - (bounds.getY() << 8);
const int y2 = roundToInt (r.getBottom() * 256.0f) - (bounds.getY() << 8);
auto y1 = roundToInt (r.getY() * 256.0f) - (bounds.getY() << 8);
auto y2 = roundToInt (r.getBottom() * 256.0f) - (bounds.getY() << 8);
if (x2 <= x1 || y2 <= y1)
continue;
int y = y1 >> 8;
const int lastLine = y2 >> 8;
auto y = y1 >> 8;
auto lastLine = y2 >> 8;
if (y == lastLine)
{
@ -194,25 +190,23 @@ EdgeTable::EdgeTable (const RectangleList<float>& rectanglesToAdd)
sanitiseLevels (true);
}
EdgeTable::EdgeTable (const Rectangle<float>& rectangleToAdd)
: bounds (Rectangle<int> ((int) std::floor (rectangleToAdd.getX()),
roundToInt (rectangleToAdd.getY() * 256.0f) >> 8,
2 + (int) rectangleToAdd.getWidth(),
2 + (int) rectangleToAdd.getHeight())),
EdgeTable::EdgeTable (Rectangle<float> rectangleToAdd)
: bounds ((int) std::floor (rectangleToAdd.getX()),
roundToInt (rectangleToAdd.getY() * 256.0f) >> 8,
2 + (int) rectangleToAdd.getWidth(),
2 + (int) rectangleToAdd.getHeight()),
maxEdgesPerLine (juce_edgeTableDefaultEdgesPerLine),
lineStrideElements ((juce_edgeTableDefaultEdgesPerLine << 1) + 1),
needToCheckEmptiness (true)
lineStrideElements ((juce_edgeTableDefaultEdgesPerLine * 2) + 1)
{
jassert (! rectangleToAdd.isEmpty());
allocate();
table[0] = 0;
const int x1 = roundToInt (rectangleToAdd.getX() * 256.0f);
const int x2 = roundToInt (rectangleToAdd.getRight() * 256.0f);
int y1 = roundToInt (rectangleToAdd.getY() * 256.0f) - (bounds.getY() << 8);
auto x1 = roundToInt (rectangleToAdd.getX() * 256.0f);
auto x2 = roundToInt (rectangleToAdd.getRight() * 256.0f);
auto y1 = roundToInt (rectangleToAdd.getY() * 256.0f) - (bounds.getY() << 8);
auto y2 = roundToInt (rectangleToAdd.getBottom() * 256.0f) - (bounds.getY() << 8);
jassert (y1 < 256);
int y2 = roundToInt (rectangleToAdd.getBottom() * 256.0f) - (bounds.getY() << 8);
if (x2 <= x1 || y2 <= y1)
{
@ -308,6 +302,7 @@ void EdgeTable::allocate()
void EdgeTable::clearLineSizes() noexcept
{
int* t = table;
for (int i = bounds.getHeight(); --i >= 0;)
{
*t = 0;
@ -315,7 +310,7 @@ void EdgeTable::clearLineSizes() noexcept
}
}
void EdgeTable::copyEdgeTableData (int* dest, const int destLineStride, const int* src, const int srcLineStride, int numLines) noexcept
void EdgeTable::copyEdgeTableData (int* dest, int destLineStride, const int* src, int srcLineStride, int numLines) noexcept
{
while (--numLines >= 0)
{
@ -332,24 +327,24 @@ void EdgeTable::sanitiseLevels (const bool useNonZeroWinding) noexcept
for (int y = bounds.getHeight(); --y >= 0;)
{
int num = lineStart[0];
auto num = lineStart[0];
if (num > 0)
{
LineItem* items = reinterpret_cast<LineItem*> (lineStart + 1);
LineItem* const itemsEnd = items + num;
auto* items = reinterpret_cast<LineItem*> (lineStart + 1);
auto* itemsEnd = items + num;
// sort the X coords
std::sort (items, itemsEnd);
const LineItem* src = items;
int correctedNum = num;
auto* src = items;
auto correctedNum = num;
int level = 0;
while (src < itemsEnd)
{
level += src->level;
const int x = src->x;
auto x = src->x;
++src;
while (src < itemsEnd && src->x == x)
@ -359,7 +354,7 @@ void EdgeTable::sanitiseLevels (const bool useNonZeroWinding) noexcept
--correctedNum;
}
int corrected = std::abs (level);
auto corrected = std::abs (level);
if (corrected >> 8)
{
@ -370,6 +365,7 @@ void EdgeTable::sanitiseLevels (const bool useNonZeroWinding) noexcept
else
{
corrected &= 511;
if (corrected >> 8)
corrected = 511 - corrected;
}
@ -395,7 +391,7 @@ void EdgeTable::remapTableForNumEdges (const int newNumEdgesPerLine)
maxEdgesPerLine = newNumEdgesPerLine;
jassert (bounds.getHeight() > 0);
const int newLineStrideElements = maxEdgesPerLine * 2 + 1;
auto newLineStrideElements = maxEdgesPerLine * 2 + 1;
HeapBlock<int> newTable (getEdgeTableAllocationSize (newLineStrideElements, bounds.getHeight()));
@ -406,12 +402,18 @@ void EdgeTable::remapTableForNumEdges (const int newNumEdgesPerLine)
}
}
inline void EdgeTable::remapWithExtraSpace (int numPoints)
{
remapTableForNumEdges (numPoints + jmax (juce_edgeTableDefaultEdgesPerLine, numPoints / 2));
jassert (numPoints < maxEdgesPerLine);
}
void EdgeTable::optimiseTable()
{
int maxLineElements = 0;
for (int i = bounds.getHeight(); --i >= 0;)
maxLineElements = jmax (maxLineElements, table [i * lineStrideElements]);
maxLineElements = jmax (maxLineElements, table[i * lineStrideElements]);
remapTableForNumEdges (maxLineElements);
}
@ -420,56 +422,54 @@ void EdgeTable::addEdgePoint (const int x, const int y, const int winding)
{
jassert (y >= 0 && y < bounds.getHeight());
int* line = table + lineStrideElements * y;
const int numPoints = line[0];
auto* line = table + lineStrideElements * y;
auto numPoints = line[0];
if (numPoints >= maxEdgesPerLine)
{
remapTableForNumEdges (maxEdgesPerLine + juce_edgeTableDefaultEdgesPerLine);
jassert (numPoints < maxEdgesPerLine);
remapWithExtraSpace (numPoints);
line = table + lineStrideElements * y;
}
line[0]++;
int n = numPoints << 1;
line [n + 1] = x;
line [n + 2] = winding;
line[0] = numPoints + 1;
line += numPoints * 2;
line[1] = x;
line[2] = winding;
}
void EdgeTable::addEdgePointPair (int x1, int x2, int y, int winding)
{
jassert (y >= 0 && y < bounds.getHeight());
int* line = table + lineStrideElements * y;
const int numPoints = line[0];
auto* line = table + lineStrideElements * y;
auto numPoints = line[0];
if (numPoints + 1 >= maxEdgesPerLine)
{
remapTableForNumEdges (maxEdgesPerLine + juce_edgeTableDefaultEdgesPerLine);
jassert (numPoints < maxEdgesPerLine);
remapWithExtraSpace (numPoints + 1);
line = table + lineStrideElements * y;
}
line[0] = numPoints + 2;
line += numPoints << 1;
line += numPoints * 2;
line[1] = x1;
line[2] = winding;
line[3] = x2;
line[4] = -winding;
}
void EdgeTable::translate (float dx, const int dy) noexcept
void EdgeTable::translate (float dx, int dy) noexcept
{
bounds.translate ((int) std::floor (dx), dy);
int* lineStart = table;
const int intDx = (int) (dx * 256.0f);
auto intDx = (int) (dx * 256.0f);
for (int i = bounds.getHeight(); --i >= 0;)
{
int* line = lineStart;
auto* line = lineStart;
lineStart += lineStrideElements;
int num = *line++;
auto num = *line++;
while (--num >= 0)
{
@ -482,12 +482,12 @@ void EdgeTable::translate (float dx, const int dy) noexcept
void EdgeTable::multiplyLevels (float amount)
{
int* lineStart = table;
const int multiplier = (int) (amount * 256.0f);
auto multiplier = (int) (amount * 256.0f);
for (int y = 0; y < bounds.getHeight(); ++y)
{
int numPoints = lineStart[0];
LineItem* item = reinterpret_cast<LineItem*> (lineStart + 1);
auto numPoints = lineStart[0];
auto* item = reinterpret_cast<LineItem*> (lineStart + 1);
lineStart += lineStrideElements;
while (--numPoints > 0)
@ -502,13 +502,13 @@ void EdgeTable::intersectWithEdgeTableLine (const int y, const int* const otherL
{
jassert (y >= 0 && y < bounds.getHeight());
int* srcLine = table + lineStrideElements * y;
int srcNum1 = *srcLine;
auto* srcLine = table + lineStrideElements * y;
auto srcNum1 = *srcLine;
if (srcNum1 == 0)
return;
int srcNum2 = *otherLine;
auto srcNum2 = *otherLine;
if (srcNum2 == 0)
{
@ -516,7 +516,7 @@ void EdgeTable::intersectWithEdgeTableLine (const int y, const int* const otherL
return;
}
const int right = bounds.getRight() << 8;
auto right = bounds.getRight() << 8;
// optimise for the common case where our line lies entirely within a
// single pair of points, as happens when clipping to a simple rect.
@ -529,10 +529,10 @@ void EdgeTable::intersectWithEdgeTableLine (const int y, const int* const otherL
bool isUsingTempSpace = false;
const int* src1 = srcLine + 1;
int x1 = *src1++;
auto x1 = *src1++;
const int* src2 = otherLine + 1;
int x2 = *src2++;
auto x2 = *src2++;
int destIndex = 0, destTotal = 0;
int level1 = 0, level2 = 0;
@ -571,7 +571,7 @@ void EdgeTable::intersectWithEdgeTableLine (const int y, const int* const otherL
lastX = nextX;
const int nextLevel = (level1 * (level2 + 1)) >> 8;
auto nextLevel = (level1 * (level2 + 1)) >> 8;
jassert (isPositiveAndBelow (nextLevel, 256));
if (nextLevel != lastLevel)
@ -582,14 +582,14 @@ void EdgeTable::intersectWithEdgeTableLine (const int y, const int* const otherL
if (isUsingTempSpace)
{
const size_t tempSize = (size_t) srcNum1 * 2 * sizeof (int);
int* const oldTemp = static_cast<int*> (alloca (tempSize));
auto tempSize = (size_t) srcNum1 * 2 * sizeof (int);
auto oldTemp = static_cast<int*> (alloca (tempSize));
memcpy (oldTemp, src1, tempSize);
remapTableForNumEdges (jmax (256, destTotal * 2));
srcLine = table + lineStrideElements * y;
int* const newTemp = table + lineStrideElements * bounds.getHeight();
auto* newTemp = table + lineStrideElements * bounds.getHeight();
memcpy (newTemp, oldTemp, tempSize);
src1 = newTemp;
}
@ -606,7 +606,7 @@ void EdgeTable::intersectWithEdgeTableLine (const int y, const int* const otherL
if (! isUsingTempSpace)
{
isUsingTempSpace = true;
int* const temp = table + lineStrideElements * bounds.getHeight();
auto* temp = table + lineStrideElements * bounds.getHeight();
memcpy (temp, src1, (size_t) srcNum1 * 2 * sizeof (int));
src1 = temp;
}
@ -661,7 +661,7 @@ void EdgeTable::clipEdgeTableLineToRange (int* dest, const int x1, const int x2)
while (lastItem[0] > x1)
lastItem -= 2;
const int itemsRemoved = (int) (lastItem - (dest + 1)) / 2;
auto itemsRemoved = (int) (lastItem - (dest + 1)) / 2;
if (itemsRemoved > 0)
{
@ -677,7 +677,7 @@ void EdgeTable::clipEdgeTableLineToRange (int* dest, const int x1, const int x2)
//==============================================================================
void EdgeTable::clipToRectangle (const Rectangle<int>& r)
{
const Rectangle<int> clipped (r.getIntersection (bounds));
auto clipped = r.getIntersection (bounds);
if (clipped.isEmpty())
{
@ -686,19 +686,19 @@ void EdgeTable::clipToRectangle (const Rectangle<int>& r)
}
else
{
const int top = clipped.getY() - bounds.getY();
const int bottom = clipped.getBottom() - bounds.getY();
auto top = clipped.getY() - bounds.getY();
auto bottom = clipped.getBottom() - bounds.getY();
if (bottom < bounds.getHeight())
bounds.setHeight (bottom);
for (int i = top; --i >= 0;)
table [lineStrideElements * i] = 0;
for (int i = 0; i < top; ++i)
table[lineStrideElements * i] = 0;
if (clipped.getX() > bounds.getX() || clipped.getRight() < bounds.getRight())
{
const int x1 = clipped.getX() << 8;
const int x2 = jmin (bounds.getRight(), clipped.getRight()) << 8;
auto x1 = clipped.getX() << 8;
auto x2 = jmin (bounds.getRight(), clipped.getRight()) << 8;
int* line = table + lineStrideElements * top;
for (int i = bottom - top; --i >= 0;)
@ -716,12 +716,12 @@ void EdgeTable::clipToRectangle (const Rectangle<int>& r)
void EdgeTable::excludeRectangle (const Rectangle<int>& r)
{
const Rectangle<int> clipped (r.getIntersection (bounds));
auto clipped = r.getIntersection (bounds);
if (! clipped.isEmpty())
{
const int top = clipped.getY() - bounds.getY();
const int bottom = clipped.getBottom() - bounds.getY();
auto top = clipped.getY() - bounds.getY();
auto bottom = clipped.getBottom() - bounds.getY();
const int rectLine[] = { 4, std::numeric_limits<int>::min(), 255,
clipped.getX() << 8, 0,
@ -737,7 +737,7 @@ void EdgeTable::excludeRectangle (const Rectangle<int>& r)
void EdgeTable::clipToEdgeTable (const EdgeTable& other)
{
const Rectangle<int> clipped (other.bounds.getIntersection (bounds));
auto clipped = other.bounds.getIntersection (bounds);
if (clipped.isEmpty())
{
@ -746,8 +746,8 @@ void EdgeTable::clipToEdgeTable (const EdgeTable& other)
}
else
{
const int top = clipped.getY() - bounds.getY();
const int bottom = clipped.getBottom() - bounds.getY();
auto top = clipped.getY() - bounds.getY();
auto bottom = clipped.getBottom() - bounds.getY();
if (bottom < bounds.getHeight())
bounds.setHeight (bottom);
@ -756,9 +756,9 @@ void EdgeTable::clipToEdgeTable (const EdgeTable& other)
bounds.setRight (clipped.getRight());
for (int i = 0; i < top; ++i)
table [lineStrideElements * i] = 0;
table[lineStrideElements * i] = 0;
const int* otherLine = other.table + other.lineStrideElements * (clipped.getY() - other.bounds.getY());
auto* otherLine = other.table + other.lineStrideElements * (clipped.getY() - other.bounds.getY());
for (int i = top; i < bottom; ++i)
{
@ -781,16 +781,16 @@ void EdgeTable::clipLineToMask (int x, int y, const uint8* mask, int maskStride,
if (numPixels <= 0)
{
table [lineStrideElements * y] = 0;
table[lineStrideElements * y] = 0;
return;
}
int* tempLine = static_cast<int*> (alloca ((size_t) (numPixels * 2 + 4) * sizeof (int)));
auto* tempLine = static_cast<int*> (alloca ((size_t) (numPixels * 2 + 4) * sizeof (int)));
int destIndex = 0, lastLevel = 0;
while (--numPixels >= 0)
{
const int alpha = *mask;
auto alpha = *mask;
mask += maskStride;
if (alpha != lastLevel)

View file

@ -46,12 +46,15 @@ public:
@param pathToAdd the path to add to the table
@param transform a transform to apply to the path being added
*/
EdgeTable (const Rectangle<int>& clipLimits,
EdgeTable (Rectangle<int> clipLimits,
const Path& pathToAdd,
const AffineTransform& transform);
/** Creates an edge table containing a rectangle. */
explicit EdgeTable (const Rectangle<int>& rectangleToAdd);
explicit EdgeTable (Rectangle<int> rectangleToAdd);
/** Creates an edge table containing a rectangle. */
explicit EdgeTable (Rectangle<float> rectangleToAdd);
/** Creates an edge table containing a rectangle list. */
explicit EdgeTable (const RectangleList<int>& rectanglesToAdd);
@ -59,9 +62,6 @@ public:
/** Creates an edge table containing a rectangle list. */
explicit EdgeTable (const RectangleList<float>& rectanglesToAdd);
/** Creates an edge table containing a rectangle. */
explicit EdgeTable (const Rectangle<float>& rectangleToAdd);
/** Creates a copy of another edge table. */
EdgeTable (const EdgeTable&);
@ -202,13 +202,14 @@ private:
HeapBlock<int> table;
Rectangle<int> bounds;
int maxEdgesPerLine, lineStrideElements;
bool needToCheckEmptiness;
bool needToCheckEmptiness = true;
void allocate();
void clearLineSizes() noexcept;
void addEdgePoint (int x, int y, int winding);
void addEdgePointPair (int x1, int x2, int y, int winding);
void remapTableForNumEdges (int newNumEdgesPerLine);
void remapWithExtraSpace (int numPointsNeeded);
void intersectWithEdgeTableLine (int y, const int* otherLine);
void clipEdgeTableLineToRange (int* line, int x1, int x2) noexcept;
void sanitiseLevels (bool useNonZeroWinding) noexcept;