From 815fd702652765819730e509d2d3b0e454167890 Mon Sep 17 00:00:00 2001 From: Kevin Shanahan Date: Sat, 19 Jan 2013 12:12:47 +1030 Subject: [PATCH] vis: use leafbits_t struct and helpers to represent vis bit strings Importing parts of this from TyrQuake - means that the base type used for managing the bit vectors is unsigned long. Not really a performance win or anything here, just a bit nicer to not have to cast from (byte *) to (long *) - just adds a little extra work before writing out the compressed data. Signed-off-by: Kevin Shanahan --- include/vis/leafbits.h | 69 ++++++++++++++++++++++++++++++ include/vis/vis.h | 10 ++--- vis/flow.c | 41 +++++++++--------- vis/vis.c | 96 +++++++++++++++++++----------------------- 4 files changed, 140 insertions(+), 76 deletions(-) create mode 100644 include/vis/leafbits.h diff --git a/include/vis/leafbits.h b/include/vis/leafbits.h new file mode 100644 index 00000000..f70826cf --- /dev/null +++ b/include/vis/leafbits.h @@ -0,0 +1,69 @@ +/* Copyright (C) 2012-2013 Kevin Shanahan + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + See file, 'COPYING', for details. +*/ + +#ifndef VIS_LEAFBITS_H +#define VIS_LEAFBITS_H + +#include +#include + +/* Use some GCC builtins */ +#ifndef ffsl +#define ffsl __builtin_ffsl +#endif +#ifndef offsetof +#define offsetof(type, member) __builtin_offsetof(type, member) +#endif + +typedef unsigned long leafblock_t; +typedef struct { + int numleafs; + leafblock_t bits[]; /* Variable Sized */ +} leafbits_t; + +int __ERRORLONGSIZE(void); /* to generate an error at link time */ +#define QBYTESHIFT(x) ((x) == 8 ? 6 : ((x) == 4 ? 5 : __ERRORLONGSIZE() )) +#define LEAFSHIFT QBYTESHIFT(sizeof(leafblock_t)) +#define LEAFMASK ((sizeof(leafblock_t) << 3) - 1UL) + +static inline int +TestLeafBit(const leafbits_t *bits, int leafnum) +{ + return !!(bits->bits[leafnum >> LEAFSHIFT] & (1UL << (leafnum & LEAFMASK))); +} + +static inline void +SetLeafBit(leafbits_t *bits, int leafnum) +{ + bits->bits[leafnum >> LEAFSHIFT] |= 1UL << (leafnum & LEAFMASK); +} + +static inline void +ClearLeafBit(leafbits_t *bits, int leafnum) +{ + bits->bits[leafnum >> LEAFSHIFT] &= ~(1UL << (leafnum & LEAFMASK)); +} + +static inline size_t +LeafbitsSize(int numleafs) +{ + return offsetof(leafbits_t, bits[(numleafs + LEAFMASK) >> LEAFSHIFT]); +} + +#endif /* VIS_LEAFBITS_H */ diff --git a/include/vis/vis.h b/include/vis/vis.h index 80d6fbc1..82dbcb8c 100644 --- a/include/vis/vis.h +++ b/include/vis/vis.h @@ -22,6 +22,7 @@ #include #include #include +#include #define PORTALFILE "PRT1" #define ON_EPSILON 0.1 @@ -41,7 +42,6 @@ typedef struct { vec3_t points[MAX_WINDING_FIXED]; // variable sized } winding_t; - winding_t *NewWinding(int points); winding_t *CopyWinding(winding_t * w); void PlaneFromWinding(const winding_t * w, plane_t *plane); @@ -54,8 +54,8 @@ typedef struct { int leaf; // neighbor winding_t *winding; pstatus_t status; - byte *visbits; - byte *mightsee; + leafbits_t *visbits; + leafbits_t *mightsee; int nummightsee; int numcansee; } portal_t; @@ -90,7 +90,7 @@ typedef struct pstack_s { winding_t windings[STACK_WINDINGS]; // Fixed size windings int freewindings[STACK_WINDINGS]; plane_t portalplane; - byte *mightsee; // bit string + leafbits_t *mightsee; // bit string plane_t separators[2][MAX_SEPARATORS]; /* Separator cache */ int numseparators[2]; } pstack_t; @@ -102,7 +102,7 @@ winding_t *ClipStackWinding(winding_t *in, pstack_t *stack, plane_t *split); int c_noclip; typedef struct { - byte *leafvis; // bit string + leafbits_t *leafvis; portal_t *base; pstack_t pstack_head; } threaddata_t; diff --git a/vis/flow.c b/vis/flow.c index b41948a4..867617a5 100644 --- a/vis/flow.c +++ b/vis/flow.c @@ -1,5 +1,6 @@ #include #include +#include unsigned long c_chains; int c_vistest, c_mighttest; @@ -15,8 +16,8 @@ CheckStack(leaf_t *leaf, threaddata_t *thread) for (p = thread->pstack_head.next; p; p = p->next) if (p->leaf == leaf) Error("%s: leaf recursion", __func__); -} +} /* ============== @@ -156,8 +157,8 @@ RecursiveLeafFlow(int leafnum, threaddata_t *thread, pstack_t *prevstack) portal_t *p; plane_t backplane; leaf_t *leaf; - int i, j; - long *test, *might, *vis, more; + int i, j, numblocks; + leafblock_t *test, *might, *vis, more; ++c_chains; @@ -165,8 +166,8 @@ RecursiveLeafFlow(int leafnum, threaddata_t *thread, pstack_t *prevstack) CheckStack(leaf, thread); // mark the leaf as visible - if (!(thread->leafvis[leafnum >> 3] & (1 << (leafnum & 7)))) { - thread->leafvis[leafnum >> 3] |= 1 << (leafnum & 7); + if (!TestLeafBit(thread->leafvis, leafnum)) { + SetLeafBit(thread->leafvis, leafnum); thread->base->numcansee++; } @@ -181,29 +182,31 @@ RecursiveLeafFlow(int leafnum, threaddata_t *thread, pstack_t *prevstack) for (i = 0; i < STACK_WINDINGS; i++) stack.freewindings[i] = 1; - stack.mightsee = malloc(leafbytes); - might = (long *)stack.mightsee; - vis = (long *)thread->leafvis; + stack.mightsee = malloc(LeafbitsSize(portalleafs)); + might = stack.mightsee->bits; + vis = thread->leafvis->bits; // check all portals for flowing into other leafs for (i = 0; i < leaf->numportals; i++) { p = leaf->portals[i]; - if (!(prevstack->mightsee[p->leaf >> 3] & (1 << (p->leaf & 7)))) { + if (!TestLeafBit(prevstack->mightsee, p->leaf)) { c_leafskip++; continue; // can't possibly see it } // if the portal can't see anything we haven't allready seen, skip it if (p->status == pstat_done) { c_vistest++; - test = (long *)p->visbits; + test = p->visbits->bits; } else { c_mighttest++; - test = (long *)p->mightsee; + test = p->mightsee->bits; } + more = 0; - for (j = 0; j < leaflongs; j++) { - might[j] = ((long *)prevstack->mightsee)[j] & test[j]; + numblocks = (portalleafs + LEAFMASK) >> LEAFSHIFT; + for (j = 0; j < numblocks; j++) { + might[j] = prevstack->mightsee->bits[j] & test[j]; more |= (might[j] & ~vis[j]); } @@ -358,8 +361,8 @@ PortalFlow(portal_t *p) if (p->status != pstat_working) Error("%s: reflowed", __func__); - p->visbits = malloc(leafbytes); - memset(p->visbits, 0, leafbytes); + p->visbits = malloc(LeafbitsSize(portalleafs)); + memset(p->visbits, 0, LeafbitsSize(portalleafs)); memset(&data, 0, sizeof(data)); data.leafvis = p->visbits; @@ -388,10 +391,10 @@ SimpleFlood(portal_t *srcportal, int leafnum, byte *portalsee) leaf_t *leaf; portal_t *p; - if (srcportal->mightsee[leafnum >> 3] & (1 << (leafnum & 7))) + if (TestLeafBit(srcportal->mightsee, leafnum)) return; - srcportal->mightsee[leafnum >> 3] |= (1 << (leafnum & 7)); + SetLeafBit(srcportal->mightsee, leafnum); srcportal->nummightsee++; leaf = &leafs[leafnum]; @@ -433,8 +436,8 @@ BasePortalThread(void *dummy) //printf("\r%i of %i: %i%%", i, numportals * 2, 50 * i / numportals); //fflush(stdout); - p->mightsee = malloc(leafbytes); - memset(p->mightsee, 0, leafbytes); + p->mightsee = malloc(LeafbitsSize(portalleafs)); + memset(p->mightsee, 0, LeafbitsSize(portalleafs)); memset(portalsee, 0, numportals * 2); diff --git a/vis/vis.c b/vis/vis.c index 225649c7..b0d92365 100644 --- a/vis/vis.c +++ b/vis/vis.c @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -380,8 +381,8 @@ UpdateMightsee(const leaf_t *source, const leaf_t *dest) p = source->portals[i]; if (p->status != pstat_none) continue; - if (p->mightsee[leafnum >> 3] & (1 << (leafnum & 7))) { - p->mightsee[leafnum >> 3] &= ~(1 << (leafnum & 7)); + if (TestLeafBit(p->mightsee, leafnum)) { + ClearLeafBit(p->mightsee, leafnum); p->nummightsee--; c_mightseeupdate++; } @@ -402,13 +403,12 @@ UpdateMightsee(const leaf_t *source, const leaf_t *dest) static void PortalCompleted(portal_t *completed) { - int i, j, k, bit; + int i, j, k, bit, numblocks; int leafnum; - portal_t *p, *p2; - leaf_t *myleaf; - unsigned long *might, *vis, *check; - unsigned long changed; - byte *bcheck, bmask; + const portal_t *p, *p2; + const leaf_t *myleaf; + const leafblock_t *might, *vis; + leafblock_t changed; ThreadLock(); @@ -424,9 +424,10 @@ PortalCompleted(portal_t *completed) if (p->status != pstat_done) continue; - might = (unsigned long *)p->mightsee; - vis = (unsigned long *)p->visbits; - for (j = 0; j < leaflongs; j++) { + might = p->mightsee->bits; + vis = p->visbits->bits; + numblocks = (portalleafs + LEAFMASK) >> LEAFSHIFT; + for (j = 0; j < numblocks; j++) { changed = might[j] & ~vis[j]; if (!changed) continue; @@ -440,29 +441,21 @@ PortalCompleted(portal_t *completed) continue; p2 = myleaf->portals[k]; if (p2->status == pstat_done) - check = (unsigned long *)p2->visbits; + changed &= ~p2->visbits->bits[j]; else - check = (unsigned long *)p2->mightsee; - changed &= ~check[j]; + changed &= ~p2->mightsee->bits[j]; if (!changed) break; } - if (!changed) - continue; /* * Update mightsee for any of the changed bits that survived */ - bcheck = (byte *)&changed; - for (k = 0; k < sizeof(changed); k++, bcheck++) { - if (!*bcheck) - continue; - for (bit = 0, bmask = 1; bit < 8; bit++, bmask <<= 1) { - if (!(*bcheck & bmask)) - continue; - leafnum = j * (sizeof(changed) << 3) + (k << 3) + bit; - UpdateMightsee(leafs + leafnum, myleaf); - } + while (changed) { + bit = ffsl(changed) - 1; + changed &= ~(1UL << bit); + leafnum = (j << LEAFSHIFT) + bit; + UpdateMightsee(leafs + leafnum, myleaf); } } } @@ -507,33 +500,31 @@ LeafThread(void *unused) CompressRow =============== */ -int -CompressRow(byte *vis, byte *dest) +static int +CompressRow(const byte *vis, byte *out) { - int j; - int rep; - int visrow; - byte *dest_p; + int i, rep, numbytes; + byte *dst; - dest_p = dest; - visrow = (portalleafs + 7) >> 3; + dst = out; + numbytes = (portalleafs + 7) >> 3; - for (j = 0; j < visrow; j++) { - *dest_p++ = vis[j]; - if (vis[j]) + for (i = 0; i < numbytes; i++) { + *dst++ = vis[i]; + if (vis[i]) continue; rep = 1; - for (j++; j < visrow; j++) - if (vis[j] || rep == 255) + for (i++; i < numbytes; i++) + if (vis[i] || rep == 255) break; else rep++; - *dest_p++ = rep; - j--; + *dst++ = rep; + i--; } - return dest_p - dest; + return dst - out; } @@ -551,11 +542,11 @@ LeafFlow(int leafnum) { leaf_t *leaf; byte *outbuffer; - byte compressed[MAX_MAP_LEAFS / 8]; - int i, j; + byte *compressed; + int i, j, shift; int numvis; byte *dest; - portal_t *p; + const portal_t *p; // // flow through all portals, collecting visible bits @@ -566,8 +557,11 @@ LeafFlow(int leafnum) p = leaf->portals[i]; if (p->status != pstat_done) Error("portal not done"); - for (j = 0; j < leafbytes; j++) - outbuffer[j] |= p->visbits[j]; + shift = 0; + for (j = 0; j < leafbytes; j++) { + outbuffer[j] |= (p->visbits->bits[j >> (LEAFSHIFT - 3)] >> shift) & 0xff; + shift = (shift + 8) & LEAFMASK; + } } if (outbuffer[leafnum >> 3] & (1 << (leafnum & 7))) @@ -587,12 +581,9 @@ LeafFlow(int leafnum) logprint("leaf %4i : %4i visible\n", leafnum, numvis); totalvis += numvis; -#if 0 - i = (portalleafs + 7) >> 3; - memcpy(compressed, outbuffer, i); -#else + /* Allocate for worst case where RLE might grow the data (unlikely) */ + compressed = malloc(portalleafs * 2 / 8); i = CompressRow(outbuffer, compressed); -#endif dest = vismap_p; vismap_p += i; @@ -603,6 +594,7 @@ LeafFlow(int leafnum) dleafs[leafnum + 1].visofs = dest - vismap; // leaf 0 is a common solid memcpy(dest, compressed, i); + free(compressed); }