mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-03-20 09:21:09 +00:00
[qfvis] Use cmem for memory management
While the main bulk of the improvement (36s down from 42s for gmsp3v2.bsp on my i7-6850K) comes from using a high-tide allocator for the windings (which necessitated using a fixed size), it is ever so slightly faster than using malloc as the back-end.
This commit is contained in:
parent
0cdcb64f51
commit
72280186bf
4 changed files with 97 additions and 42 deletions
|
@ -115,4 +115,46 @@ void delete_memsuper (memsuper_t *super);
|
|||
void *cmemalloc (memsuper_t *super, size_t size);
|
||||
void cmemfree (memsuper_t *super, void *mem);
|
||||
|
||||
/** High-tide structure allocator for use in linked lists.
|
||||
|
||||
Using a free-list with the name of \c NAME_freelist, return a single
|
||||
element.
|
||||
The type of the element must be a structure with a field named \c next.
|
||||
When the free-list is empty, memory is claimed from the system in blocks.
|
||||
Elements may be returned to the pool by linking them into the free-list.
|
||||
|
||||
\param s The number of structures in the block.
|
||||
\param t The structure type.
|
||||
\param n The \c NAME portion of the \c NAME_freelist free-list.
|
||||
\param super The memsuper_t super block from which to allocate memory.
|
||||
|
||||
\hideinitializer
|
||||
*/
|
||||
#define CMEMALLOC(s, t, n, super) \
|
||||
({ \
|
||||
if (!n##_freelist) { \
|
||||
int i; \
|
||||
n##_freelist = cmemalloc ((super), (s) * sizeof (t)); \
|
||||
for (i = 0; i < (s) - 1; i++) \
|
||||
n##_freelist[i].next = &n##_freelist[i + 1]; \
|
||||
n##_freelist[i].next = 0; \
|
||||
} \
|
||||
t *v = n##_freelist; \
|
||||
n##_freelist = n##_freelist->next; \
|
||||
v; \
|
||||
})
|
||||
|
||||
/** Free a block allocated by #ALLOC
|
||||
|
||||
\param n The \c NAME portion of the \c NAME_freelist free-list.
|
||||
\param p The pointer to the block to be freed.
|
||||
|
||||
\hideinitializer
|
||||
*/
|
||||
#define CMEMFREE(n, p) \
|
||||
do { \
|
||||
p->next = n##_freelist; \
|
||||
n##_freelist = p; \
|
||||
} while (0)
|
||||
|
||||
#endif//__QF_cmem_h
|
||||
|
|
|
@ -82,10 +82,11 @@ extern pthread_rwlock_t *portal_locks;
|
|||
#define MAX_POINTS_ON_WINDING 64
|
||||
#define MAX_PORTALS_ON_CLUSTER 128
|
||||
|
||||
typedef struct {
|
||||
typedef struct winding_s {
|
||||
struct winding_s *next;
|
||||
qboolean original; // don't free, it's part of the portal
|
||||
int numpoints;
|
||||
vec3_t points[8]; // variable sized
|
||||
vec3_t points[MAX_PORTALS_ON_CLUSTER]; // variable sized
|
||||
} winding_t;
|
||||
|
||||
typedef enum {
|
||||
|
@ -158,7 +159,9 @@ typedef struct threaddata_s {
|
|||
portal_t *base; ///< portal for which this thread is being run
|
||||
pstack_t pstack_head;
|
||||
sep_t *sep_freelist; ///< per-thread list of free separators
|
||||
winding_t *winding_freelist; ///< per-thread list of free windings
|
||||
set_pool_t set_pool;
|
||||
struct memsuper_s *memsuper;
|
||||
} threaddata_t;
|
||||
|
||||
typedef struct {
|
||||
|
@ -179,10 +182,10 @@ extern cluster_t *clusters;
|
|||
extern int *leafcluster;
|
||||
extern byte *uncompressed;
|
||||
|
||||
void FreeWinding (winding_t *w);
|
||||
winding_t *NewWinding (int points);
|
||||
winding_t *ClipWinding (winding_t *in, const plane_t *split, qboolean keepon);
|
||||
winding_t *CopyWinding (const winding_t *w);
|
||||
void FreeWinding (threaddata_t *thread, winding_t *w);
|
||||
winding_t *NewWinding (threaddata_t *thread, int points);
|
||||
winding_t *ClipWinding (threaddata_t *thread, winding_t *in, const plane_t *split, qboolean keepon);
|
||||
winding_t *CopyWinding (threaddata_t *thread, const winding_t *w);
|
||||
|
||||
void ClusterFlow (int clusternum);
|
||||
void PortalBase (basethread_t *thread, portal_t *portal);
|
||||
|
|
|
@ -48,8 +48,8 @@
|
|||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "QF/alloc.h"
|
||||
#include "QF/bspfile.h"
|
||||
#include "QF/cmem.h"
|
||||
#include "QF/cmd.h"
|
||||
#include "QF/mathlib.h"
|
||||
#include "QF/quakefs.h"
|
||||
|
@ -90,14 +90,14 @@ new_separator (threaddata_t *thread)
|
|||
{
|
||||
sep_t *sep;
|
||||
|
||||
ALLOC (128, sep_t, thread->sep, sep);
|
||||
sep = CMEMALLOC (32, sep_t, thread->sep, thread->memsuper);
|
||||
return sep;
|
||||
}
|
||||
|
||||
static void
|
||||
delete_separator (threaddata_t *thread, sep_t *sep)
|
||||
{
|
||||
FREE (thread->sep, sep);
|
||||
CMEMFREE (thread->sep, sep);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -247,12 +247,12 @@ FindSeparators (threaddata_t *thread,
|
|||
}
|
||||
|
||||
static winding_t *
|
||||
ClipToSeparators (const sep_t *separators, winding_t *target)
|
||||
ClipToSeparators (threaddata_t *thread, const sep_t *separators, winding_t *target)
|
||||
{
|
||||
const sep_t *sep;
|
||||
|
||||
for (sep = separators; target && sep; sep = sep->next) {
|
||||
target = ClipWinding (target, &sep->plane, false);
|
||||
target = ClipWinding (thread, target, &sep->plane, false);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
@ -360,7 +360,7 @@ RecursiveClusterFlow (int clusternum, threaddata_t *thread, pstack_t *prevstack)
|
|||
thread->stats.portalcheck++;
|
||||
|
||||
target_winding = target_portal->winding;
|
||||
target_winding = ClipWinding (target_winding, source_plane, false);
|
||||
target_winding = ClipWinding (thread, target_winding, source_plane, false);
|
||||
if (!target_winding)
|
||||
continue;
|
||||
|
||||
|
@ -374,21 +374,21 @@ RecursiveClusterFlow (int clusternum, threaddata_t *thread, pstack_t *prevstack)
|
|||
stack->pass_portal = target_portal;
|
||||
|
||||
RecursiveClusterFlow (target_portal->cluster, thread, stack);
|
||||
FreeWinding (target_winding);
|
||||
FreeWinding (thread, target_winding);
|
||||
continue;
|
||||
}
|
||||
|
||||
target_winding = ClipWinding (target_winding, pass_plane, false);
|
||||
target_winding = ClipWinding (thread, target_winding, pass_plane, false);
|
||||
if (!target_winding)
|
||||
continue;
|
||||
|
||||
// copy source_winding because it likely is already a copy and thus
|
||||
// if it gets clipped away, earlier stack levels will get corrupted
|
||||
source_winding = CopyWinding (prevstack->source_winding);
|
||||
source_winding = CopyWinding (thread, prevstack->source_winding);
|
||||
|
||||
source_winding = ClipWinding (source_winding, &backplane, false);
|
||||
source_winding = ClipWinding (thread, source_winding, &backplane, false);
|
||||
if (!source_winding) {
|
||||
FreeWinding (target_winding);
|
||||
FreeWinding (thread, target_winding);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -402,11 +402,12 @@ RecursiveClusterFlow (int clusternum, threaddata_t *thread, pstack_t *prevstack)
|
|||
source_winding,
|
||||
*source_plane,
|
||||
pass_winding, 0);
|
||||
target_winding = ClipToSeparators (stack->separators[0],
|
||||
target_winding = ClipToSeparators (thread,
|
||||
stack->separators[0],
|
||||
target_winding);
|
||||
if (!target_winding) {
|
||||
thread->stats.targetclipped++;
|
||||
FreeWinding (source_winding);
|
||||
FreeWinding (thread, source_winding);
|
||||
continue;
|
||||
}
|
||||
if (target_winding != old)
|
||||
|
@ -420,11 +421,12 @@ RecursiveClusterFlow (int clusternum, threaddata_t *thread, pstack_t *prevstack)
|
|||
pass_winding,
|
||||
*pass_plane,
|
||||
source_winding, 1);
|
||||
target_winding = ClipToSeparators (stack->separators[1],
|
||||
target_winding = ClipToSeparators (thread,
|
||||
stack->separators[1],
|
||||
target_winding);
|
||||
if (!target_winding) {
|
||||
thread->stats.targetclipped++;
|
||||
FreeWinding (source_winding);
|
||||
FreeWinding (thread, source_winding);
|
||||
continue;
|
||||
}
|
||||
if (target_winding != old)
|
||||
|
@ -438,11 +440,11 @@ RecursiveClusterFlow (int clusternum, threaddata_t *thread, pstack_t *prevstack)
|
|||
sep = FindSeparators (thread,
|
||||
target_winding, target_portal->plane,
|
||||
pass_winding, 0);
|
||||
source_winding = ClipToSeparators (sep, source_winding);
|
||||
source_winding = ClipToSeparators (thread, sep, source_winding);
|
||||
free_separators (thread, sep);
|
||||
if (!source_winding) {
|
||||
thread->stats.sourceclipped++;
|
||||
FreeWinding (target_winding);
|
||||
FreeWinding (thread, target_winding);
|
||||
continue;
|
||||
}
|
||||
if (source_winding != old)
|
||||
|
@ -454,11 +456,11 @@ RecursiveClusterFlow (int clusternum, threaddata_t *thread, pstack_t *prevstack)
|
|||
sep_t *sep;
|
||||
sep = FindSeparators (thread, pass_winding, *pass_plane,
|
||||
target_winding, 1);
|
||||
source_winding = ClipToSeparators (sep, source_winding);
|
||||
source_winding = ClipToSeparators (thread, sep, source_winding);
|
||||
free_separators (thread, sep);
|
||||
if (!source_winding) {
|
||||
thread->stats.sourceclipped++;
|
||||
FreeWinding (target_winding);
|
||||
FreeWinding (thread, target_winding);
|
||||
continue;
|
||||
}
|
||||
if (source_winding != old)
|
||||
|
@ -476,8 +478,8 @@ RecursiveClusterFlow (int clusternum, threaddata_t *thread, pstack_t *prevstack)
|
|||
// flow through it for real
|
||||
RecursiveClusterFlow (target_portal->cluster, thread, stack);
|
||||
|
||||
FreeWinding (source_winding);
|
||||
FreeWinding (target_winding);
|
||||
FreeWinding (thread, source_winding);
|
||||
FreeWinding (thread, target_winding);
|
||||
}
|
||||
free_separators (thread, stack->separators[1]);
|
||||
free_separators (thread, stack->separators[0]);
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
|
||||
#include "QF/bspfile.h"
|
||||
#include "QF/cmd.h"
|
||||
#include "QF/cmem.h"
|
||||
#include "QF/dstring.h"
|
||||
#include "QF/mathlib.h"
|
||||
#include "QF/qtypes.h"
|
||||
|
@ -71,6 +72,7 @@ bsp_t *bsp;
|
|||
|
||||
options_t options;
|
||||
|
||||
static threaddata_t main_thread;
|
||||
static visstat_t stats;
|
||||
int base_mightsee;
|
||||
|
||||
|
@ -144,7 +146,7 @@ PlaneFromWinding (winding_t *winding, plane_t *plane)
|
|||
}
|
||||
|
||||
winding_t *
|
||||
NewWinding (int points)
|
||||
NewWinding (threaddata_t *thread, int points)
|
||||
{
|
||||
winding_t *winding;
|
||||
size_t size;
|
||||
|
@ -153,38 +155,40 @@ NewWinding (int points)
|
|||
Sys_Error ("NewWinding: %i points", points);
|
||||
|
||||
size = field_offset (winding_t, points[points]);
|
||||
winding = calloc (1, size);
|
||||
winding = CMEMALLOC (13, winding_t, thread->winding, thread->memsuper);
|
||||
memset (winding, 0, size);
|
||||
|
||||
return winding;
|
||||
}
|
||||
|
||||
void
|
||||
FreeWinding (winding_t *w)
|
||||
FreeWinding (threaddata_t *thread, winding_t *w)
|
||||
{
|
||||
if (!w->original)
|
||||
free (w);
|
||||
if (!w->original) {
|
||||
CMEMFREE (thread->winding, w);
|
||||
}
|
||||
}
|
||||
|
||||
winding_t *
|
||||
CopyWinding (const winding_t *w)
|
||||
CopyWinding (threaddata_t *thread, const winding_t *w)
|
||||
{
|
||||
size_t size;
|
||||
winding_t *copy;
|
||||
|
||||
size = field_offset (winding_t, points[w->numpoints]);
|
||||
copy = malloc (size);
|
||||
copy = CMEMALLOC (13, winding_t, thread->winding, thread->memsuper);
|
||||
memcpy (copy, w, size);
|
||||
copy->original = false;
|
||||
return copy;
|
||||
}
|
||||
|
||||
static winding_t *
|
||||
NewFlippedWinding (const winding_t *w)
|
||||
NewFlippedWinding (threaddata_t *thread, const winding_t *w)
|
||||
{
|
||||
winding_t *flipped;
|
||||
int i;
|
||||
|
||||
flipped = NewWinding (w->numpoints);
|
||||
flipped = NewWinding (thread, w->numpoints);
|
||||
for (i = 0; i < w->numpoints; i++)
|
||||
VectorCopy (w->points[i], flipped->points[w->numpoints - 1 - i]);
|
||||
flipped->numpoints = w->numpoints;
|
||||
|
@ -203,7 +207,7 @@ NewFlippedWinding (const winding_t *w)
|
|||
it will be clipped away.
|
||||
*/
|
||||
winding_t *
|
||||
ClipWinding (winding_t *in, const plane_t *split, qboolean keepon)
|
||||
ClipWinding (threaddata_t *thread, winding_t *in, const plane_t *split, qboolean keepon)
|
||||
{
|
||||
int maxpts, i, j;
|
||||
int counts[3], sides[MAX_POINTS_ON_WINDING];
|
||||
|
@ -236,7 +240,7 @@ ClipWinding (winding_t *in, const plane_t *split, qboolean keepon)
|
|||
return in;
|
||||
|
||||
if (!counts[0]) {
|
||||
FreeWinding (in);
|
||||
FreeWinding (thread, in);
|
||||
return NULL;
|
||||
}
|
||||
if (!counts[1])
|
||||
|
@ -244,7 +248,7 @@ ClipWinding (winding_t *in, const plane_t *split, qboolean keepon)
|
|||
|
||||
maxpts = in->numpoints + 4; // can't use counts[0] + 2 because
|
||||
// of fp grouping errors
|
||||
neww = NewWinding (maxpts);
|
||||
neww = NewWinding (thread, maxpts);
|
||||
|
||||
for (i = 0; i < in->numpoints; i++) {
|
||||
p1 = in->points[i];
|
||||
|
@ -284,7 +288,7 @@ ClipWinding (winding_t *in, const plane_t *split, qboolean keepon)
|
|||
if (neww->numpoints > maxpts)
|
||||
Sys_Error ("ClipWinding: points exceeded estimate");
|
||||
// free the original winding
|
||||
FreeWinding (in);
|
||||
FreeWinding (thread, in);
|
||||
|
||||
return neww;
|
||||
}
|
||||
|
@ -384,6 +388,7 @@ LeafThread (void *_thread)
|
|||
|
||||
memset (&data, 0, sizeof (data));
|
||||
set_pool_init (&data.set_pool);
|
||||
data.memsuper = new_memsuper ();
|
||||
do {
|
||||
portal = GetNextPortal ();
|
||||
if (!portal)
|
||||
|
@ -408,6 +413,7 @@ LeafThread (void *_thread)
|
|||
printf ("thread %d done\n", thread);
|
||||
if (working)
|
||||
working[thread] = -1;
|
||||
delete_memsuper (data.memsuper);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -1033,7 +1039,7 @@ LoadPortals (char *name)
|
|||
|| (unsigned) clusternums[1] > (unsigned) portalclusters)
|
||||
Sys_Error ("LoadPortals: reading portal %i", i);
|
||||
|
||||
winding = portal->winding = NewWinding (numpoints);
|
||||
winding = portal->winding = NewWinding (&main_thread, numpoints);
|
||||
winding->original = true;
|
||||
winding->numpoints = numpoints;
|
||||
|
||||
|
@ -1085,7 +1091,7 @@ LoadPortals (char *name)
|
|||
|
||||
// Use a flipped winding for the reverse portal so the winding
|
||||
// direction and plane normal match.
|
||||
portal->winding = NewFlippedWinding (winding);
|
||||
portal->winding = NewFlippedWinding (&main_thread, winding);
|
||||
portal->winding->original = true;
|
||||
portal->plane = plane;
|
||||
portal->cluster = clusternums[0];
|
||||
|
@ -1115,6 +1121,8 @@ main (int argc, char **argv)
|
|||
dstring_t *portalfile = dstring_new ();
|
||||
QFile *f;
|
||||
|
||||
main_thread.memsuper = new_memsuper ();
|
||||
|
||||
start = Sys_DoubleTime ();
|
||||
|
||||
this_program = argv[0];
|
||||
|
|
Loading…
Reference in a new issue