mirror of
https://github.com/Cesarus85/ringfall-mjolnir-vr.git
synced 2026-10-20 05:00:27 +02:00
The Silent Cartographer with 32x co-op enemies (484 actors) went from 53 to about 97 fps on the Linux PC, with the same game and the same picture: cluster list removals start where the reference was put, full data arrays are not walked again, object lighting keeps each cluster's drawn lights and passes over far ones without their distance, the per-texture profile timer only runs while something reads it, and the renderer binds streams once per draw, caches its texture, target and shader lookups, and no longer makes Mesa's GL thread wait on large uploads or visibility tests.
574 lines
13 KiB
C
574 lines
13 KiB
C
/*
|
|
DATA.C
|
|
|
|
symbols in this file:
|
|
001089A0 0020:
|
|
_data_allocation_size (0000)
|
|
001089C0 00d0:
|
|
_data_initialize (0000)
|
|
00108A90 00b0:
|
|
_datum_try_and_get (0000)
|
|
00108B40 00d0:
|
|
_datum_get (0000)
|
|
00108C10 00b0:
|
|
_data_verify (0000)
|
|
00108CC0 0030:
|
|
_datum_initialize (0000)
|
|
00108CF0 0050:
|
|
_data_new (0000)
|
|
00108D40 0030:
|
|
_data_dispose (0000)
|
|
00108D70 0020:
|
|
_data_make_invalid (0000)
|
|
00108D90 00a0:
|
|
_datum_new_at_index (0000)
|
|
00108E30 00c0:
|
|
_datum_new (0000)
|
|
00108EF0 0050:
|
|
_datum_delete (0000)
|
|
00108F40 0090:
|
|
_data_delete_all (0000)
|
|
00108FD0 0060:
|
|
_data_iterator_new (0000)
|
|
00109030 00e0:
|
|
_data_iterator_next (0000)
|
|
00109110 0090:
|
|
_data_next_index (0000)
|
|
001091A0 0090:
|
|
_data_prev_index (0000)
|
|
00109230 0110:
|
|
_data_compact (0000)
|
|
00109340 0020:
|
|
_data_make_valid (0000)
|
|
0027D310 0005:
|
|
??_C@_04MEMAJGDJ@name?$AA@ (0000)
|
|
0027D318 0010:
|
|
??_C@_0BA@HDDJANCC@maximum_count?$DO0?$AA@ (0000)
|
|
0027D328 001d:
|
|
??_C@_0BN@PKENIDAC@c?3?2halo?2SOURCE?2memory?2data?4c?$AA@ (0000)
|
|
0027D348 002d:
|
|
??_C@_0CN@EMICPANB@identifier?5?$HM?$HM?5?$CBdata?9?$DOidentifier_@ (0000)
|
|
0027D378 000c:
|
|
??_C@_0M@FOPPJIAE@data?9?$DOvalid?$AA@ (0000)
|
|
0027D384 0029:
|
|
??_C@_0CJ@PGGNIIAJ@?$CFs?5index?5?$CD?$CFd?5?$CI0x?$CFx?$CJ?5is?5unused?5or@ (0000)
|
|
0027D3B0 002a:
|
|
??_C@_0CK@PGJBLDEL@?$CFs?5data?5array?5?$EA?$CFp?5is?5bad?5or?5not?5@ (0000)
|
|
0027D3DC 0016:
|
|
??_C@_0BG@NCCMBKGF@iterator?9?$DOdata?9?$DOvalid?$AA@ (0000)
|
|
0027D3F4 0031:
|
|
??_C@_0DB@COCANJJJ@uninitialized?5iterator?5passed?5to@ (0000)
|
|
*/
|
|
|
|
/* ---------- headers */
|
|
|
|
#include "cseries.h"
|
|
#include "data.h"
|
|
|
|
/* ---------- constants */
|
|
|
|
/* ---------- macros */
|
|
|
|
/* ---------- structures */
|
|
|
|
/* ---------- prototypes */
|
|
|
|
static void datum_initialize(struct data_array *data, struct datum_header *header);
|
|
|
|
/* ---------- globals */
|
|
|
|
/* ---------- public code */
|
|
|
|
long data_allocation_size(
|
|
short maximum_count,
|
|
short size)
|
|
{
|
|
return maximum_count*size+sizeof(struct data_array);
|
|
}
|
|
|
|
void data_initialize(
|
|
struct data_array *data,
|
|
const char *name,
|
|
short maximum_count,
|
|
short size)
|
|
{
|
|
match_assert("c:\\halo\\SOURCE\\memory\\data.c", 64, maximum_count>0);
|
|
match_assert("c:\\halo\\SOURCE\\memory\\data.c", 65, size>0);
|
|
match_assert("c:\\halo\\SOURCE\\memory\\data.c", 66, name);
|
|
match_assert("c:\\halo\\SOURCE\\memory\\data.c", 67, data);
|
|
|
|
csmemset(data, 0, sizeof(*data));
|
|
csstrncpy(data->name, name, sizeof(data->name)-1);
|
|
data->maximum_count = maximum_count;
|
|
data->size = size;
|
|
data->signature = 'd@t@';
|
|
data->data = data+1;
|
|
data->valid = FALSE;
|
|
|
|
return;
|
|
}
|
|
|
|
void *datum_try_and_get(
|
|
struct data_array *data,
|
|
long index)
|
|
{
|
|
struct datum_header *header = NULL;
|
|
short identifier;
|
|
short absolute_index;
|
|
|
|
if (index!=NONE)
|
|
{
|
|
identifier = index>>16;
|
|
absolute_index = index;
|
|
|
|
match_assert("c:\\halo\\SOURCE\\memory\\data.c", 371, data->valid);
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\memory\\data.c",
|
|
372,
|
|
identifier || !data->identifier_zero_invalid);
|
|
|
|
if (absolute_index>=0 && absolute_index<data->maximum_count)
|
|
{
|
|
header = (struct datum_header *)((byte *)data->data+data->size*absolute_index);
|
|
if (!header->identifier || (identifier && header->identifier!=identifier))
|
|
{
|
|
header = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
return header;
|
|
}
|
|
|
|
void *datum_get(
|
|
struct data_array *data,
|
|
long index)
|
|
{
|
|
struct datum_header *header;
|
|
short identifier;
|
|
short absolute_index;
|
|
|
|
identifier = index>>16;
|
|
absolute_index = index;
|
|
match_assert("c:\\halo\\SOURCE\\memory\\data.c", 396, data->valid);
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\memory\\data.c",
|
|
397,
|
|
identifier || !data->identifier_zero_invalid);
|
|
|
|
if (absolute_index>=0 && absolute_index<data->count)
|
|
{
|
|
header = (struct datum_header *)((byte *)data->data+data->size*absolute_index);
|
|
if (header->identifier && (!identifier || identifier==header->identifier))
|
|
{
|
|
return header;
|
|
}
|
|
}
|
|
|
|
#ifdef HALO_RELEASE
|
|
/* port: a release build's message too, and where it was asked from
|
|
(debug.txt's reference address places it in the build): the caller
|
|
goes on with the NULL and crashes, with nothing else to say which
|
|
array and which caller it was */
|
|
{
|
|
char message[128];
|
|
|
|
csprintf(
|
|
message,
|
|
"%.32s index #%d (0x%x) is unused or changed (asked from %p)",
|
|
data->name,
|
|
index&0xFFFF,
|
|
index,
|
|
__builtin_return_address(0));
|
|
release_assert_failed(message, "c:\\halo\\SOURCE\\memory\\data.c", 412, TRUE);
|
|
}
|
|
#else
|
|
match_vassert(
|
|
"c:\\halo\\SOURCE\\memory\\data.c",
|
|
412,
|
|
FALSE,
|
|
csprintf(
|
|
temporary,
|
|
"%s index #%d (0x%x) is unused or changed",
|
|
data->name,
|
|
index&0xFFFF,
|
|
index));
|
|
#endif
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void data_verify(
|
|
struct data_array *data)
|
|
{
|
|
match_assert("c:\\halo\\SOURCE\\memory\\data.c", 457, data);
|
|
|
|
match_vassert(
|
|
"c:\\halo\\SOURCE\\memory\\data.c",
|
|
470,
|
|
data->data &&
|
|
data->signature=='d@t@' &&
|
|
data->maximum_count>=0 &&
|
|
data->count>=0 &&
|
|
data->count<=data->maximum_count &&
|
|
data->first_free_absolute_index>=0 &&
|
|
data->first_free_absolute_index<=data->maximum_count &&
|
|
data->actual_count>=0 &&
|
|
data->actual_count<=data->count,
|
|
csprintf(temporary, "%s data array @%p is bad or not allocated", data->name, data));
|
|
|
|
return;
|
|
}
|
|
|
|
struct data_array *data_new(
|
|
const char *name,
|
|
short maximum_count,
|
|
short size)
|
|
{
|
|
struct data_array *data = (struct data_array *)match_malloc(
|
|
"c:\\halo\\SOURCE\\memory\\data.c",
|
|
41,
|
|
data_allocation_size(maximum_count, size));
|
|
|
|
if (data)
|
|
{
|
|
data_initialize(data, name, maximum_count, size);
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
void data_dispose(
|
|
struct data_array *data)
|
|
{
|
|
data_verify(data);
|
|
csmemset(data, 0, sizeof(*data));
|
|
match_free("c:\\halo\\SOURCE\\memory\\data.c", 89, data);
|
|
|
|
return;
|
|
}
|
|
|
|
void data_make_invalid(
|
|
struct data_array *data)
|
|
{
|
|
data_verify(data);
|
|
data->valid = FALSE;
|
|
|
|
return;
|
|
}
|
|
|
|
long datum_new_at_index(
|
|
struct data_array *data,
|
|
long index)
|
|
{
|
|
struct datum_header *header;
|
|
short absolute_index = index;
|
|
short identifier = index>>16;
|
|
long result = NONE;
|
|
|
|
data_verify(data);
|
|
match_assert("c:\\halo\\SOURCE\\memory\\data.c", 123, data->valid);
|
|
|
|
if (absolute_index>=0 && absolute_index<data->maximum_count && identifier)
|
|
{
|
|
header = (struct datum_header *)((byte *)data->data+data->size*absolute_index);
|
|
if (!header->identifier)
|
|
{
|
|
data->actual_count++;
|
|
if (absolute_index>=data->count)
|
|
{
|
|
data->count = absolute_index+1;
|
|
}
|
|
|
|
datum_initialize(data, header);
|
|
header->identifier = identifier;
|
|
result = identifier<<16 | absolute_index;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
long datum_new(
|
|
struct data_array *data)
|
|
{
|
|
struct datum_header *header;
|
|
short absolute_index;
|
|
long size;
|
|
long result = NONE;
|
|
|
|
data_verify(data);
|
|
match_assert("c:\\halo\\SOURCE\\memory\\data.c", 163, data->valid);
|
|
|
|
absolute_index = data->first_free_absolute_index;
|
|
size = data->size;
|
|
header = (struct datum_header *)((byte *)data->data+size*absolute_index);
|
|
while (absolute_index<data->maximum_count)
|
|
{
|
|
if (!header->identifier)
|
|
{
|
|
datum_initialize(data, header);
|
|
data->actual_count++;
|
|
data->first_free_absolute_index = absolute_index+1;
|
|
if (data->count<=absolute_index)
|
|
{
|
|
data->count = absolute_index+1;
|
|
}
|
|
|
|
result = header->identifier<<16 | absolute_index;
|
|
break;
|
|
}
|
|
|
|
absolute_index++;
|
|
header = (struct datum_header *)((byte *)header+size);
|
|
}
|
|
/* port: none free from first_free_absolute_index on (and none before it
|
|
is, as ever): the next search starts at the end, until a datum is deleted
|
|
(datum_delete lowers it), rather than walking a full array again. A full
|
|
array (the AI's props, with many actors) was walked on every new datum. */
|
|
if (result == NONE)
|
|
data->first_free_absolute_index = data->maximum_count;
|
|
|
|
return result;
|
|
}
|
|
|
|
void data_make_valid(
|
|
struct data_array *data)
|
|
{
|
|
data_verify(data);
|
|
data->valid = TRUE;
|
|
data_delete_all(data);
|
|
|
|
return;
|
|
}
|
|
|
|
void datum_delete(
|
|
struct data_array *data,
|
|
long index)
|
|
{
|
|
struct datum_header *header = (struct datum_header *)datum_get(data, index);
|
|
header->identifier = 0;
|
|
|
|
if (((short)index)<data->first_free_absolute_index)
|
|
{
|
|
data->first_free_absolute_index = index;
|
|
}
|
|
|
|
if (((short)index)+1==data->count)
|
|
{
|
|
do
|
|
{
|
|
header =(struct datum_header *)((byte *)header-data->size);
|
|
data->count--;
|
|
}
|
|
while (data->count > 0 && !header->identifier);
|
|
}
|
|
data->actual_count--;
|
|
|
|
return;
|
|
}
|
|
|
|
void data_delete_all(
|
|
struct data_array *data)
|
|
{
|
|
short absolute_index;
|
|
|
|
data_verify(data);
|
|
match_assert("c:\\halo\\SOURCE\\memory\\data.c", 226, data->valid);
|
|
|
|
data->count = 0;
|
|
data->actual_count = 0;
|
|
data->first_free_absolute_index = 0;
|
|
csstrncpy((char *)&data->next_identifier, data->name, sizeof(data->next_identifier));
|
|
data->next_identifier |= 0x8000;
|
|
|
|
for (absolute_index = 0; absolute_index<data->maximum_count; absolute_index++)
|
|
{
|
|
((struct datum_header *)((byte *)data->data+data->size*absolute_index))->identifier = 0;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void data_iterator_new(
|
|
struct data_iterator *iterator,
|
|
struct data_array *data)
|
|
{
|
|
data_verify(data);
|
|
match_assert("c:\\halo\\SOURCE\\memory\\data.c", 249, data->valid);
|
|
|
|
iterator->data = data;
|
|
iterator->signature = (unsigned long)data^'iter';
|
|
iterator->absolute_index = 0;
|
|
iterator->datum_index = NONE;
|
|
|
|
return;
|
|
}
|
|
|
|
void *data_iterator_next(
|
|
struct data_iterator *iterator)
|
|
{
|
|
struct datum_header *header;
|
|
short absolute_index;
|
|
long datum_index;
|
|
long size;
|
|
void *result = NULL;
|
|
|
|
match_vassert(
|
|
"c:\\halo\\SOURCE\\memory\\data.c",
|
|
268,
|
|
iterator->signature==((unsigned long)iterator->data^'iter'),
|
|
"uninitialized iterator passed to iterator_next()");
|
|
data_verify(iterator->data);
|
|
match_assert("c:\\halo\\SOURCE\\memory\\data.c", 271, iterator->data->valid);
|
|
|
|
absolute_index = iterator->absolute_index;
|
|
size = iterator->data->size;
|
|
header = (struct datum_header *)((byte *)iterator->data->data+size*absolute_index);
|
|
while (absolute_index<iterator->data->count)
|
|
{
|
|
datum_index = header->identifier<<16 | absolute_index;
|
|
absolute_index++;
|
|
if (header->identifier)
|
|
{
|
|
iterator->datum_index = datum_index;
|
|
result = header;
|
|
break;
|
|
}
|
|
|
|
header = (struct datum_header *)((byte *)header+size);
|
|
}
|
|
iterator->absolute_index = absolute_index;
|
|
|
|
return result;
|
|
}
|
|
|
|
long data_next_index(
|
|
struct data_array *data,
|
|
long index)
|
|
{
|
|
struct datum_header *header;
|
|
long result = NONE;
|
|
short absolute_index = index+1;
|
|
|
|
data_verify(data);
|
|
match_assert("c:\\halo\\SOURCE\\memory\\data.c", 303, data->valid);
|
|
|
|
if (absolute_index>=0 && absolute_index<data->count)
|
|
{
|
|
header = (struct datum_header *)((byte *)data->data+data->size*absolute_index);
|
|
while (absolute_index<data->count)
|
|
{
|
|
if (header->identifier)
|
|
{
|
|
result = header->identifier<<16 | absolute_index;
|
|
break;
|
|
}
|
|
|
|
absolute_index++;
|
|
header = (struct datum_header *)((byte *)header+data->size);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
long data_prev_index(
|
|
struct data_array *data,
|
|
long index)
|
|
{
|
|
struct datum_header *header;
|
|
long result = NONE;
|
|
short absolute_index;
|
|
|
|
data_verify(data);
|
|
match_assert("c:\\halo\\SOURCE\\memory\\data.c", 335, data->valid);
|
|
|
|
absolute_index = index==NONE ? data->count-1 : index-1;
|
|
if (absolute_index>=0 && absolute_index<data->count)
|
|
{
|
|
header = (struct datum_header *)((byte *)data->data+data->size*absolute_index);
|
|
do
|
|
{
|
|
if (header->identifier)
|
|
{
|
|
result = header->identifier<<16 | absolute_index;
|
|
break;
|
|
}
|
|
|
|
header = (struct datum_header *)((byte *)header-data->size);
|
|
}
|
|
while (absolute_index-->=0);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void data_compact(
|
|
struct data_array *data)
|
|
{
|
|
void *compacted_data;
|
|
/* Keep the null sentinel distinct; VC7 coalesces it with compacted_count. */
|
|
void *empty = NULL;
|
|
struct datum_header *datum;
|
|
short compacted_count;
|
|
short absolute_index;
|
|
|
|
compacted_data = match_malloc(
|
|
"c:\\halo\\SOURCE\\memory\\data.c",
|
|
421,
|
|
data->maximum_count*data->size);
|
|
data_verify(data);
|
|
match_assert("c:\\halo\\SOURCE\\memory\\data.c", 424, data->valid);
|
|
|
|
if (compacted_data!=empty)
|
|
{
|
|
datum = data->data;
|
|
absolute_index = (long)empty;
|
|
compacted_count = (short)(long)empty;
|
|
while (absolute_index<data->count)
|
|
{
|
|
if (datum->identifier)
|
|
{
|
|
csmemcpy(
|
|
(byte *)compacted_data+compacted_count*data->size,
|
|
datum,
|
|
data->size);
|
|
compacted_count++;
|
|
}
|
|
|
|
absolute_index++;
|
|
datum = (struct datum_header *)((byte *)datum+data->size);
|
|
}
|
|
|
|
csmemcpy(data->data, compacted_data, compacted_count*data->size);
|
|
csmemset(
|
|
(byte *)data->data+compacted_count*data->size,
|
|
0,
|
|
(data->maximum_count-compacted_count)*data->size);
|
|
data->actual_count = compacted_count;
|
|
data->count = compacted_count;
|
|
data->first_free_absolute_index = compacted_count;
|
|
match_free("c:\\halo\\SOURCE\\memory\\data.c", 447, compacted_data);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/* ---------- private code */
|
|
|
|
static void datum_initialize(
|
|
struct data_array *data,
|
|
struct datum_header *header)
|
|
{
|
|
csmemset(header, 0, data->size);
|
|
header->identifier = data->next_identifier;
|
|
data->next_identifier++;
|
|
if (!data->next_identifier)
|
|
{
|
|
data->next_identifier = 0x8000;
|
|
}
|
|
|
|
return;
|
|
}
|