View: optimize Fill/StrokePolygon with raw points array argument

Converting points array to `BPolygon` has significant cost, including
heap allocation, when drawing a lot of polygons.

Change-Id: I81e6b4031bac4beadcc79412c58eedddffc00a82
Reviewed-on: https://review.haiku-os.org/c/haiku/+/10337
Reviewed-by: waddlesplash <[email protected]>
This commit is contained in:
X512
2026-03-05 02:42:51 +00:00
committed by waddlesplash
parent 7ef695df5c
commit 02683a08de
3 changed files with 103 additions and 35 deletions
+1 -1
View File
@@ -40,7 +40,7 @@ private:
bool _AddPoints(const BPoint* points, int32 count,
bool computeBounds);
void _ComputeBounds();
static BRect _ComputeBounds(const BPoint* points, uint32 count);
void _MapPoint(BPoint* point, const BRect& source,
const BRect& destination);
void _MapRectangle(BRect* rect, const BRect& source,
+22 -22
View File
@@ -129,7 +129,7 @@ BPolygon::PrintToStream() const
//BPolygon::TransformBy(const BAffineTransform& transform)
//{
// transform.Apply(fPoints, (int32)fCount);
// _ComputeBounds();
// fBounds = _ComputeBounds(fPoints, fCount);
//}
//
//
@@ -177,35 +177,35 @@ BPolygon::_AddPoints(const BPoint* points, int32 count, bool computeBounds)
fCount += count;
if (computeBounds)
_ComputeBounds();
fBounds = _ComputeBounds(fPoints, fCount);
return true;
}
void
BPolygon::_ComputeBounds()
BRect
BPolygon::_ComputeBounds(const BPoint* points, uint32 count)
{
if (fCount == 0) {
fBounds = BRect(0.0, 0.0, -1.0f, -1.0f);
return;
if (count == 0)
return BRect(0.0, 0.0, -1.0f, -1.0f);
BRect bounds(points[0], points[0]);
for (uint32 i = 1; i < count; i++) {
if (points[i].x < bounds.left)
bounds.left = points[i].x;
if (points[i].y < bounds.top)
bounds.top = points[i].y;
if (points[i].x > bounds.right)
bounds.right = points[i].x;
if (points[i].y > bounds.bottom)
bounds.bottom = points[i].y;
}
fBounds = BRect(fPoints[0], fPoints[0]);
for (uint32 i = 1; i < fCount; i++) {
if (fPoints[i].x < fBounds.left)
fBounds.left = fPoints[i].x;
if (fPoints[i].y < fBounds.top)
fBounds.top = fPoints[i].y;
if (fPoints[i].x > fBounds.right)
fBounds.right = fPoints[i].x;
if (fPoints[i].y > fBounds.bottom)
fBounds.bottom = fPoints[i].y;
}
return bounds;
}
+80 -12
View File
@@ -3611,10 +3611,28 @@ void
BView::StrokePolygon(const BPoint* pointArray, int32 numPoints, bool closed,
::pattern pattern)
{
BPolygon polygon(pointArray, numPoints);
if (pointArray == NULL
|| numPoints <= 1
|| fOwner == NULL)
return;
StrokePolygon(polygon.fPoints, polygon.fCount, polygon.Frame(), closed,
pattern);
BRect bounds = BPolygon::_ComputeBounds(pointArray, numPoints);
_CheckLockAndSwitchCurrent();
_UpdatePattern(pattern);
if (fOwner->fLink->StartMessage(AS_STROKE_POLYGON,
numPoints * sizeof(BPoint) + sizeof(BRect) + sizeof(bool)
+ sizeof(int32)) == B_OK) {
fOwner->fLink->Attach<BRect>(bounds);
fOwner->fLink->Attach<bool>(closed);
fOwner->fLink->Attach<int32>(numPoints);
fOwner->fLink->Attach(pointArray, numPoints * sizeof(BPoint));
_FlushIfNotInTransaction();
} else {
fprintf(stderr, "ERROR: Can't send polygon to app_server!\n");
}
}
@@ -3663,10 +3681,28 @@ void
BView::StrokePolygon(const BPoint* pointArray, int32 numPoints, bool closed,
const BGradient& gradient)
{
BPolygon polygon(pointArray, numPoints);
if (pointArray == NULL
|| numPoints <= 1
|| fOwner == NULL)
return;
StrokePolygon(polygon.fPoints, polygon.fCount, polygon.Frame(), closed,
gradient);
BRect bounds = BPolygon::_ComputeBounds(pointArray, numPoints);
_CheckLockAndSwitchCurrent();
if (fOwner->fLink->StartMessage(AS_STROKE_POLYGON_GRADIENT,
numPoints * sizeof(BPoint) + sizeof(BRect) + sizeof(bool)
+ sizeof(int32)) == B_OK) {
fOwner->fLink->Attach<BRect>(bounds);
fOwner->fLink->Attach<bool>(closed);
fOwner->fLink->Attach<int32>(numPoints);
fOwner->fLink->Attach(pointArray, numPoints * sizeof(BPoint));
fOwner->fLink->AttachGradient(gradient);
_FlushIfNotInTransaction();
} else {
fprintf(stderr, "ERROR: Can't send polygon to app_server!\n");
}
}
@@ -3755,11 +3791,27 @@ BView::FillPolygon(const BPolygon* polygon, const BGradient& gradient)
void
BView::FillPolygon(const BPoint* pointArray, int32 numPoints, ::pattern pattern)
{
if (pointArray == NULL)
if (pointArray == NULL
|| numPoints <= 2
|| fOwner == NULL)
return;
BPolygon polygon(pointArray, numPoints);
FillPolygon(&polygon, pattern);
BRect bounds = BPolygon::_ComputeBounds(pointArray, numPoints);
_CheckLockAndSwitchCurrent();
_UpdatePattern(pattern);
if (fOwner->fLink->StartMessage(AS_FILL_POLYGON,
numPoints * sizeof(BPoint) + sizeof(BRect) + sizeof(int32))
== B_OK) {
fOwner->fLink->Attach<BRect>(bounds);
fOwner->fLink->Attach<int32>(numPoints);
fOwner->fLink->Attach(pointArray, numPoints * sizeof(BPoint));
_FlushIfNotInTransaction();
} else {
fprintf(stderr, "ERROR: Can't send polygon to app_server!\n");
}
}
@@ -3767,11 +3819,27 @@ void
BView::FillPolygon(const BPoint* pointArray, int32 numPoints,
const BGradient& gradient)
{
if (pointArray == NULL)
if (pointArray == NULL
|| numPoints <= 2
|| fOwner == NULL)
return;
BPolygon polygon(pointArray, numPoints);
FillPolygon(&polygon, gradient);
BRect bounds = BPolygon::_ComputeBounds(pointArray, numPoints);
_CheckLockAndSwitchCurrent();
if (fOwner->fLink->StartMessage(AS_FILL_POLYGON_GRADIENT,
numPoints * sizeof(BPoint) + sizeof(BRect) + sizeof(int32))
== B_OK) {
fOwner->fLink->Attach<BRect>(bounds);
fOwner->fLink->Attach<int32>(numPoints);
fOwner->fLink->Attach(pointArray, numPoints * sizeof(BPoint));
fOwner->fLink->AttachGradient(gradient);
_FlushIfNotInTransaction();
} else {
fprintf(stderr, "ERROR: Can't send polygon to app_server!\n");
}
}