vis: add saving and resuming of vis state to/from disk
Inspired by the implementation of Benjt Jardrup, save the current state of the vis job to disc at regular intervals so that we can resume from that point in case the computer needs to be rebooted/shutdown or crash/power issues occur. Signed-off-by: Kevin Shanahan <kmshanah@disenchant.net>
This commit is contained in:
parent
fb3966eb02
commit
4161d10a68
1
Makefile
1
Makefile
|
|
@ -249,6 +249,7 @@ VIS_OBJS = \
|
|||
vis/flow.o \
|
||||
vis/vis.o \
|
||||
vis/soundpvs.o \
|
||||
vis/state.o \
|
||||
common/cmdlib.o \
|
||||
common/mathlib.o \
|
||||
common/bspfile.o \
|
||||
|
|
|
|||
|
|
@ -99,8 +99,6 @@ winding_t *AllocStackWinding(pstack_t *stack);
|
|||
void FreeStackWinding(winding_t *w, pstack_t *stack);
|
||||
winding_t *ClipStackWinding(winding_t *in, pstack_t *stack, plane_t *split);
|
||||
|
||||
int c_noclip;
|
||||
|
||||
typedef struct {
|
||||
leafbits_t *leafvis;
|
||||
portal_t *base;
|
||||
|
|
@ -113,6 +111,7 @@ extern int portalleafs;
|
|||
extern portal_t *portals;
|
||||
extern leaf_t *leafs;
|
||||
|
||||
extern int c_noclip;
|
||||
extern int c_portaltest, c_portalpass, c_portalcheck;
|
||||
extern int c_vistest, c_mighttest;
|
||||
extern unsigned long c_chains;
|
||||
|
|
@ -124,9 +123,19 @@ extern byte *uncompressed;
|
|||
extern int leafbytes;
|
||||
extern int leaflongs;
|
||||
|
||||
extern char sourcefile[1024];
|
||||
extern char portalfile[1024];
|
||||
extern char statefile[1024];
|
||||
extern char statetmpfile[1024];
|
||||
|
||||
void LeafFlow(int leafnum);
|
||||
void BasePortalVis(void);
|
||||
|
||||
void PortalFlow(portal_t * p);
|
||||
|
||||
void CalcAmbientSounds(void);
|
||||
|
||||
extern double starttime, endtime, statetime;
|
||||
|
||||
void SaveVisState(void);
|
||||
qboolean LoadVisState(void);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,281 @@
|
|||
/* Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <vis/vis.h>
|
||||
#include <common/cmdlib.h>
|
||||
|
||||
#define VIS_STATE_VERSION ('T' << 24 | 'Y' << 16 | 'R' << 8 | '1')
|
||||
|
||||
typedef struct {
|
||||
uint32_t version;
|
||||
uint32_t numportals;
|
||||
uint32_t numleafs;
|
||||
uint32_t testlevel;
|
||||
uint32_t time_elapsed;
|
||||
} dvisstate_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t status;
|
||||
uint32_t might;
|
||||
uint32_t vis;
|
||||
uint32_t nummightsee;
|
||||
uint32_t numcansee;
|
||||
} dportal_t;
|
||||
|
||||
static int
|
||||
CompressBits(uint8_t *out, const leafbits_t *in)
|
||||
{
|
||||
int i, rep, shift, numbytes;
|
||||
uint8_t val, repval, *dst;
|
||||
|
||||
dst = out;
|
||||
numbytes = (portalleafs + 7) >> 3;
|
||||
for (i = 0; i < numbytes && dst - out < numbytes; i++) {
|
||||
shift = (i << 3) & LEAFMASK;
|
||||
val = (in->bits[i >> (LEAFSHIFT - 3)] >> shift) & 0xff;
|
||||
*dst++ = val;
|
||||
if (val != 0 && val != 0xff)
|
||||
continue;
|
||||
if (dst - out >= numbytes)
|
||||
break;
|
||||
|
||||
rep = 1;
|
||||
for (i++; i < numbytes; i++) {
|
||||
shift = (i << 3) & LEAFMASK;
|
||||
repval = (in->bits[i >> (LEAFSHIFT - 3)] >> shift) & 0xff;
|
||||
if (repval != val || rep == 255)
|
||||
break;
|
||||
rep++;
|
||||
}
|
||||
*dst++ = rep;
|
||||
i--;
|
||||
}
|
||||
|
||||
if (dst - out < numbytes)
|
||||
return dst - out;
|
||||
|
||||
/* Compression ineffective, just copy the data */
|
||||
dst = out;
|
||||
for (i = 0; i < numbytes; i++) {
|
||||
shift = (i << 3) & LEAFMASK;
|
||||
*dst++ = (in->bits[i >> (LEAFSHIFT - 3)] >> shift) & 0xff;
|
||||
}
|
||||
return numbytes;
|
||||
}
|
||||
|
||||
static void
|
||||
DecompressBits(leafbits_t *dst, const uint8_t *src)
|
||||
{
|
||||
int i, rep, shift, numbytes;
|
||||
uint8_t val;
|
||||
|
||||
numbytes = (portalleafs + 7) >> 3;
|
||||
memset(dst->bits, 0, numbytes);
|
||||
dst->numleafs = portalleafs;
|
||||
|
||||
for (i = 0; i < numbytes; i++) {
|
||||
val = *src++;
|
||||
shift = (i << 3) & LEAFMASK;
|
||||
dst->bits[i >> (LEAFSHIFT - 3)] |= (leafblock_t)val << shift;
|
||||
if (val != 0 && val != 0xff)
|
||||
continue;
|
||||
|
||||
rep = *src++;
|
||||
if (i + rep > numbytes)
|
||||
Error("%s: overflow", __func__);
|
||||
|
||||
/* Already wrote the first byte, add (rep - 1) copies */
|
||||
while (--rep) {
|
||||
i++;
|
||||
shift = (i << 3) & LEAFMASK;
|
||||
dst->bits[i >> (LEAFSHIFT - 3)] |= (leafblock_t)val << shift;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
CopyLeafBits(leafbits_t *dst, const byte *src, int numleafs)
|
||||
{
|
||||
int i, shift;
|
||||
int numbytes;
|
||||
|
||||
numbytes = (numleafs + 7) >> 3;
|
||||
memset(dst->bits, 0, numbytes);
|
||||
dst->numleafs = numleafs;
|
||||
|
||||
for (i = 0; i < numbytes; i++) {
|
||||
shift = (i << 3) & LEAFMASK;
|
||||
dst->bits[i >> (LEAFSHIFT - 3)] |= (leafblock_t)(*src++) << shift;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SaveVisState(void)
|
||||
{
|
||||
int i, vis_len, might_len;
|
||||
const portal_t *p;
|
||||
dvisstate_t state;
|
||||
dportal_t pstate;
|
||||
uint8_t *vis;
|
||||
uint8_t *might;
|
||||
FILE *outfile;
|
||||
int err;
|
||||
|
||||
outfile = SafeOpenWrite(statetmpfile);
|
||||
|
||||
/* Write out a header */
|
||||
state.version = LittleLong(VIS_STATE_VERSION);
|
||||
state.numportals = LittleLong(numportals);
|
||||
state.numleafs = LittleLong(portalleafs);
|
||||
state.testlevel = LittleLong(testlevel);
|
||||
state.time_elapsed = LittleLong((uint32_t)(statetime - starttime));
|
||||
|
||||
SafeWrite(outfile, &state, sizeof(state));
|
||||
|
||||
/* Allocate memory for compressed bitstrings */
|
||||
might = malloc((portalleafs + 7) >> 3);
|
||||
vis = malloc((portalleafs + 7) >> 3);
|
||||
|
||||
for (i = 0, p = portals; i < numportals * 2; i++, p++ ) {
|
||||
might_len = CompressBits(might, p->mightsee);
|
||||
if (p->status == pstat_done)
|
||||
vis_len = CompressBits(vis, p->visbits);
|
||||
else
|
||||
vis_len = 0;
|
||||
|
||||
pstate.status = LittleLong(p->status);
|
||||
pstate.might = LittleLong(might_len);
|
||||
pstate.vis = LittleLong(vis_len);
|
||||
pstate.nummightsee = LittleLong(p->nummightsee);
|
||||
pstate.numcansee = LittleLong(p->numcansee);
|
||||
|
||||
SafeWrite(outfile, &pstate, sizeof(pstate));
|
||||
SafeWrite(outfile, might, might_len);
|
||||
if (vis_len)
|
||||
SafeWrite(outfile, vis, vis_len);
|
||||
}
|
||||
|
||||
err = fclose(outfile);
|
||||
if (err)
|
||||
Error("%s: error writing new state (%s)", __func__, strerror(errno));
|
||||
err = unlink(statefile);
|
||||
if (err && errno != ENOENT)
|
||||
Error("%s: error removing old state (%s)", __func__, strerror(errno));
|
||||
err = rename(statetmpfile, statefile);
|
||||
if (err)
|
||||
Error("%s: error renaming state file (%s)", __func__, strerror(errno));
|
||||
}
|
||||
|
||||
qboolean
|
||||
LoadVisState(void)
|
||||
{
|
||||
FILE *infile;
|
||||
int prt_time, state_time;
|
||||
int i, numbytes, err;
|
||||
portal_t *p;
|
||||
dvisstate_t state;
|
||||
dportal_t pstate;
|
||||
byte *compressed;
|
||||
|
||||
state_time = FileTime(statefile);
|
||||
if (state_time == -1) {
|
||||
/* No state file, maybe temp file is there? */
|
||||
state_time = FileTime(statetmpfile);
|
||||
if (state_time == -1)
|
||||
return false;
|
||||
err = rename(statetmpfile, statefile);
|
||||
if (err)
|
||||
return false;
|
||||
}
|
||||
|
||||
prt_time = FileTime(portalfile);
|
||||
if (prt_time > state_time) {
|
||||
logprint("State file is out of date, will be overwritten\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
infile = SafeOpenRead(statefile);
|
||||
|
||||
SafeRead(infile, &state, sizeof(state));
|
||||
state.version = LittleLong(state.version);
|
||||
state.numportals = LittleLong(state.numportals);
|
||||
state.numleafs = LittleLong(state.numleafs);
|
||||
state.testlevel = LittleLong(state.testlevel);
|
||||
state.time_elapsed = LittleLong(state.time_elapsed);
|
||||
|
||||
/* Sanity check the headers */
|
||||
if (state.version != VIS_STATE_VERSION) {
|
||||
fclose(infile);
|
||||
Error("%s: state file version does not match");
|
||||
}
|
||||
if (state.numportals != numportals || state.numleafs != portalleafs) {
|
||||
fclose(infile);
|
||||
Error("%s: state file %s does not match portal file %s", __func__,
|
||||
statefile, portalfile);
|
||||
}
|
||||
|
||||
/* Move back the start time to simulate already elapsed time */
|
||||
starttime -= state.time_elapsed;
|
||||
|
||||
numbytes = (portalleafs + 7) >> 3;
|
||||
compressed = malloc(numbytes);
|
||||
|
||||
/* Update the portal information */
|
||||
for (i = 0, p = portals; i < numportals * 2; i++, p++) {
|
||||
SafeRead(infile, &pstate, sizeof(pstate));
|
||||
pstate.status = LittleLong(pstate.status);
|
||||
pstate.might = LittleLong(pstate.might);
|
||||
pstate.vis = LittleLong(pstate.vis);
|
||||
pstate.nummightsee = LittleLong(pstate.nummightsee);
|
||||
pstate.numcansee = LittleLong(pstate.numcansee);
|
||||
|
||||
p->status = pstate.status;
|
||||
p->nummightsee = pstate.nummightsee;
|
||||
p->numcansee = pstate.numcansee;
|
||||
|
||||
SafeRead(infile, compressed, pstate.might);
|
||||
p->mightsee = malloc(LeafbitsSize(portalleafs));
|
||||
memset(p->mightsee, 0, LeafbitsSize(portalleafs));
|
||||
if (pstate.might < numbytes)
|
||||
DecompressBits(p->mightsee, compressed);
|
||||
else
|
||||
CopyLeafBits(p->mightsee, compressed, portalleafs);
|
||||
|
||||
p->visbits = malloc(LeafbitsSize(portalleafs));
|
||||
memset(p->visbits, 0, LeafbitsSize(portalleafs));
|
||||
if (pstate.vis) {
|
||||
SafeRead(infile, compressed, pstate.vis);
|
||||
if (pstate.vis < numbytes)
|
||||
DecompressBits(p->visbits, compressed);
|
||||
else
|
||||
CopyLeafBits(p->visbits, compressed, portalleafs);
|
||||
}
|
||||
|
||||
/* Portals that were in progress need to be started again */
|
||||
if (p->status == pstat_working)
|
||||
p->status = pstat_none;
|
||||
}
|
||||
|
||||
fclose(infile);
|
||||
|
||||
return true;
|
||||
}
|
||||
65
vis/vis.c
65
vis/vis.c
|
|
@ -463,6 +463,8 @@ PortalCompleted(portal_t *completed)
|
|||
ThreadUnlock();
|
||||
}
|
||||
|
||||
double starttime, endtime, statetime;
|
||||
static double stateinterval;
|
||||
|
||||
/*
|
||||
==============
|
||||
|
|
@ -472,9 +474,19 @@ PortalCompleted(portal_t *completed)
|
|||
void *
|
||||
LeafThread(void *unused)
|
||||
{
|
||||
double now;
|
||||
portal_t *p;
|
||||
|
||||
do {
|
||||
ThreadLock();
|
||||
/* Save state if sufficient time has elapsed */
|
||||
now = I_FloatTime();
|
||||
if (now > statetime + stateinterval) {
|
||||
statetime = now;
|
||||
SaveVisState();
|
||||
}
|
||||
ThreadUnlock();
|
||||
|
||||
p = GetNextPortal();
|
||||
if (!p)
|
||||
break;
|
||||
|
|
@ -602,7 +614,8 @@ LeafFlow(int leafnum)
|
|||
void
|
||||
CalcPortalVis(void)
|
||||
{
|
||||
int i;
|
||||
int i, startcount;
|
||||
portal_t *p;
|
||||
|
||||
// fastvis just uses mightsee for a very loose bound
|
||||
if (fastvis) {
|
||||
|
|
@ -613,7 +626,15 @@ CalcPortalVis(void)
|
|||
return;
|
||||
}
|
||||
|
||||
RunThreadsOn(0, numportals * 2, LeafThread);
|
||||
/*
|
||||
* Count the already completed portals in case we loaded previous state
|
||||
*/
|
||||
startcount = 0;
|
||||
for (i = 0, p = portals; i < numportals * 2; i++, p++) {
|
||||
if (p->status == pstat_done)
|
||||
startcount++;
|
||||
}
|
||||
RunThreadsOn(startcount, numportals * 2, LeafThread);
|
||||
|
||||
if (verbose) {
|
||||
logprint("portalcheck: %i portaltest: %i portalpass: %i\n",
|
||||
|
|
@ -634,8 +655,12 @@ CalcVis(void)
|
|||
{
|
||||
int i;
|
||||
|
||||
logprint("Calculating Base Vis:\n");
|
||||
BasePortalVis();
|
||||
if (LoadVisState()) {
|
||||
logprint("Loaded previous state. Resuming progress...\n");
|
||||
} else {
|
||||
logprint("Calculating Base Vis:\n");
|
||||
BasePortalVis();
|
||||
}
|
||||
|
||||
logprint("Calculating Full Vis:\n");
|
||||
CalcPortalVis();
|
||||
|
|
@ -994,6 +1019,10 @@ LoadPortals(char *name)
|
|||
fclose(f);
|
||||
}
|
||||
|
||||
char sourcefile[1024];
|
||||
char portalfile[1024];
|
||||
char statefile[1024];
|
||||
char statetmpfile[1024];
|
||||
|
||||
/*
|
||||
===========
|
||||
|
|
@ -1003,10 +1032,7 @@ LoadPortals(char *name)
|
|||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
char portalfile[1024];
|
||||
char source[1024];
|
||||
int i, bsp_version;
|
||||
double start, end;
|
||||
qboolean credits = false;
|
||||
|
||||
init_log("vis.log");
|
||||
|
|
@ -1057,13 +1083,14 @@ main(int argc, char **argv)
|
|||
|
||||
logprint("running with %d threads\n", numthreads);
|
||||
|
||||
start = I_FloatTime();
|
||||
stateinterval = 300; /* 5 minutes */
|
||||
starttime = statetime = I_FloatTime();
|
||||
|
||||
strcpy(source, argv[i]);
|
||||
StripExtension(source);
|
||||
DefaultExtension(source, ".bsp");
|
||||
strcpy(sourcefile, argv[i]);
|
||||
StripExtension(sourcefile);
|
||||
DefaultExtension(sourcefile, ".bsp");
|
||||
|
||||
bsp_version = LoadBSPFile(source);
|
||||
bsp_version = LoadBSPFile(sourcefile);
|
||||
|
||||
strcpy(portalfile, argv[i]);
|
||||
StripExtension(portalfile);
|
||||
|
|
@ -1071,6 +1098,14 @@ main(int argc, char **argv)
|
|||
|
||||
LoadPortals(portalfile);
|
||||
|
||||
strcpy(statefile, sourcefile);
|
||||
StripExtension(statefile);
|
||||
DefaultExtension(statefile, ".vis");
|
||||
|
||||
strcpy(statetmpfile, sourcefile);
|
||||
StripExtension(statetmpfile);
|
||||
DefaultExtension(statetmpfile, ".vi0");
|
||||
|
||||
uncompressed = malloc(leafbytes * portalleafs);
|
||||
memset(uncompressed, 0, leafbytes * portalleafs);
|
||||
|
||||
|
|
@ -1087,12 +1122,12 @@ main(int argc, char **argv)
|
|||
|
||||
CalcAmbientSounds();
|
||||
|
||||
WriteBSPFile(source, bsp_version);
|
||||
WriteBSPFile(sourcefile, bsp_version);
|
||||
|
||||
// unlink (portalfile);
|
||||
|
||||
end = I_FloatTime();
|
||||
logprint("%5.1f seconds elapsed\n", end - start);
|
||||
endtime = I_FloatTime();
|
||||
logprint("%5.1f seconds elapsed\n", endtime - starttime);
|
||||
|
||||
close_log();
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue