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 <kmshanah@disenchant.net>
This commit is contained in:
Kevin Shanahan 2013-01-19 12:12:47 +10:30
parent 498286faa1
commit 815fd70265
4 changed files with 140 additions and 76 deletions

69
include/vis/leafbits.h Normal file
View File

@ -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 <stdlib.h>
#include <string.h>
/* 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 */

View File

@ -22,6 +22,7 @@
#include <common/cmdlib.h>
#include <common/mathlib.h>
#include <common/bspfile.h>
#include <vis/leafbits.h>
#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;

View File

@ -1,5 +1,6 @@
#include <common/threads.h>
#include <vis/vis.h>
#include <vis/leafbits.h>
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);

View File

@ -3,6 +3,7 @@
#include <limits.h>
#include <stddef.h>
#include <vis/leafbits.h>
#include <vis/vis.h>
#include <common/log.h>
#include <common/threads.h>
@ -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);
}