mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-10 15:22:04 +00:00
[renderer] Use better heuristics for scrap allocation
More tuning is needed on the actual splits as it falls over when the lower rect gets too low for the subrects being allocated. However, the scrap allocator itself will prefer exact width/height fits with larger cutoff over inexact cuts with smaller cutoff. Many thanks to tdb for the suggestions. Fixes the fps dropping from ~3700fps down to ~450fps (cumulative due to loss of POT rounding and very poor splitting layout), with a bonus boost to about 4900fps (all speeds at 800x450). The 2d sprites were mostly ok, but the lightmaps forming a capital gamma shape in a 4k texture really hurt. Now the lightmaps are a nice dense bar at the top of the texture, and 2d sprites are pretty good (slight improvement coming next).
This commit is contained in:
parent
1fdedbaf33
commit
058e919273
2 changed files with 44 additions and 9 deletions
|
@ -268,10 +268,37 @@ VRect_SubRect (const vrect_t *rect, int width, int height)
|
||||||
if (height > rect->height) {
|
if (height > rect->height) {
|
||||||
height = rect->height;
|
height = rect->height;
|
||||||
}
|
}
|
||||||
|
// First check for exact fits as no heuristics are necessary
|
||||||
|
if (width == rect->width) {
|
||||||
|
if (height == rect->height) {
|
||||||
|
// Exact fit, return a new rect of the same size
|
||||||
|
return VRect_New (rect->x, rect->y, rect->width, rect->height);
|
||||||
|
}
|
||||||
|
|
||||||
|
vrect_t *r = VRect_HSplit (rect, rect->y + height);
|
||||||
|
if (VRect_IsEmpty (r->next)) {
|
||||||
|
VRect_Delete (r->next);
|
||||||
|
r->next = 0;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
} else if (height == rect->height) {
|
||||||
|
// Because rect's width ks known to be greater than the requested
|
||||||
|
// width, the split is guaranteed to produce two non-empty rectangles.
|
||||||
|
return VRect_VSplit (rect, rect->x + width);
|
||||||
|
}
|
||||||
|
|
||||||
int a = rect->height - height;
|
int a = rect->height - height;
|
||||||
int b = rect->width - width;
|
int b = rect->width - width;
|
||||||
vrect_t *r, *s;
|
vrect_t *r, *s;
|
||||||
if (b * height > a * width) {
|
if (b * height <= a * width || 16 * a > 15 * rect->height) {
|
||||||
|
// horizontal cuts produce better memory locality so favor them
|
||||||
|
r = VRect_HSplit (rect, rect->y + height);
|
||||||
|
if (VRect_IsEmpty (r->next)) {
|
||||||
|
VRect_Delete (r->next);
|
||||||
|
r->next = 0;
|
||||||
|
}
|
||||||
|
s = VRect_VSplit (r, r->x + width);
|
||||||
|
} else {
|
||||||
// a horizontal cut produces a larger off-cut rectangle than a vertical
|
// a horizontal cut produces a larger off-cut rectangle than a vertical
|
||||||
// cut, so do a vertical cut first so the off-cut is as small as
|
// cut, so do a vertical cut first so the off-cut is as small as
|
||||||
// possible
|
// possible
|
||||||
|
@ -281,13 +308,6 @@ VRect_SubRect (const vrect_t *rect, int width, int height)
|
||||||
r->next = 0;
|
r->next = 0;
|
||||||
}
|
}
|
||||||
s = VRect_HSplit (r, r->y + height);
|
s = VRect_HSplit (r, r->y + height);
|
||||||
} else {
|
|
||||||
r = VRect_HSplit (rect, rect->y + height);
|
|
||||||
if (VRect_IsEmpty (r->next)) {
|
|
||||||
VRect_Delete (r->next);
|
|
||||||
r->next = 0;
|
|
||||||
}
|
|
||||||
s = VRect_VSplit (r, r->x + width);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (VRect_IsEmpty (s->next)) {
|
if (VRect_IsEmpty (s->next)) {
|
||||||
|
|
|
@ -83,8 +83,23 @@ R_ScrapAlloc (rscrap_t *scrap, int width, int height)
|
||||||
best = t;
|
best = t;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ((*t)->width <= (*best)->width || (*t)->height <= (*best)->height)
|
if ((*t)->width == width && (*t)->height == height) {
|
||||||
|
// exact fit
|
||||||
best = t;
|
best = t;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ((*best)->height == height) {
|
||||||
|
if ((*t)->height == height && (*t)->width < (*best)->width) {
|
||||||
|
best = t;
|
||||||
|
}
|
||||||
|
} else if ((*best)->width == width) {
|
||||||
|
if ((*t)->width == width && (*t)->height < (*best)->height) {
|
||||||
|
best = t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((*t)->width <= (*best)->width || (*t)->height <= (*best)->height) {
|
||||||
|
best = t;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!best)
|
if (!best)
|
||||||
return 0; // couldn't find a spot
|
return 0; // couldn't find a spot
|
||||||
|
|
Loading…
Reference in a new issue