rename all 'buckets' -> 'bins'
This commit is contained in:
parent
50da5f1bc6
commit
a6d103f391
@ -29,8 +29,8 @@
|
|||||||
|
|
||||||
#define IMAGE_PIXELS_PER_UNIT 256.0
|
#define IMAGE_PIXELS_PER_UNIT 256.0
|
||||||
|
|
||||||
/* 256^2 = 65536 buckets */
|
/* 64^2 = 4096 bins */
|
||||||
#define SPACE_CELL_BUCKETS_SQRT (256)
|
#define SPACE_CELL_BINS_SQRT (64)
|
||||||
#define SPACE_CELL_SIZE 1.0f
|
#define SPACE_CELL_SIZE 1.0f
|
||||||
|
|
||||||
#define SIM_TICKS_PER_SECOND 50
|
#define SIM_TICKS_PER_SECOND 50
|
||||||
|
|||||||
62
src/host.c
62
src/host.c
@ -26,8 +26,8 @@
|
|||||||
#define PACKET_MSG_CHUNK_MAX_LEN 1024
|
#define PACKET_MSG_CHUNK_MAX_LEN 1024
|
||||||
#define PACKET_DATA_MAX_LEN 1280 /* Give enough space for msg chunk + header */
|
#define PACKET_DATA_MAX_LEN 1280 /* Give enough space for msg chunk + header */
|
||||||
|
|
||||||
#define NUM_CHANNEL_LOOKUP_BUCKETS 512
|
#define NUM_CHANNEL_LOOKUP_BINS 512
|
||||||
#define NUM_MSG_ASSEMBLER_LOOKUP_BUCKETS 16384
|
#define NUM_MSG_ASSEMBLER_LOOKUP_BINS 16384
|
||||||
|
|
||||||
enum host_packet_kind {
|
enum host_packet_kind {
|
||||||
HOST_PACKET_KIND_NONE,
|
HOST_PACKET_KIND_NONE,
|
||||||
@ -91,7 +91,7 @@ struct host_channel_list {
|
|||||||
struct host_channel_node *last;
|
struct host_channel_node *last;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct host_channel_lookup_bucket {
|
struct host_channel_lookup_bin {
|
||||||
struct host_channel *first;
|
struct host_channel *first;
|
||||||
struct host_channel *last;
|
struct host_channel *last;
|
||||||
};
|
};
|
||||||
@ -143,7 +143,7 @@ struct host_msg_assembler {
|
|||||||
u8 *chunk_data;
|
u8 *chunk_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct host_msg_assembler_lookup_bucket {
|
struct host_msg_assembler_lookup_bin {
|
||||||
struct host_msg_assembler *first;
|
struct host_msg_assembler *first;
|
||||||
struct host_msg_assembler *last;
|
struct host_msg_assembler *last;
|
||||||
};
|
};
|
||||||
@ -189,11 +189,11 @@ struct host *host_alloc(u16 listen_port)
|
|||||||
|
|
||||||
host->channels = arena_dry_push(&host->channel_arena, struct host_channel);
|
host->channels = arena_dry_push(&host->channel_arena, struct host_channel);
|
||||||
|
|
||||||
host->num_channel_lookup_buckets = NUM_CHANNEL_LOOKUP_BUCKETS;
|
host->num_channel_lookup_bins = NUM_CHANNEL_LOOKUP_BINS;
|
||||||
host->channel_lookup_buckets = arena_push_array_zero(&host->arena, struct host_channel_lookup_bucket, host->num_channel_lookup_buckets);
|
host->channel_lookup_bins = arena_push_array_zero(&host->arena, struct host_channel_lookup_bin, host->num_channel_lookup_bins);
|
||||||
|
|
||||||
host->num_msg_assembler_lookup_buckets = NUM_MSG_ASSEMBLER_LOOKUP_BUCKETS;
|
host->num_msg_assembler_lookup_bins = NUM_MSG_ASSEMBLER_LOOKUP_BINS;
|
||||||
host->msg_assembler_lookup_buckets = arena_push_array_zero(&host->arena, struct host_msg_assembler_lookup_bucket, host->num_msg_assembler_lookup_buckets);
|
host->msg_assembler_lookup_bins = arena_push_array_zero(&host->arena, struct host_msg_assembler_lookup_bin, host->num_msg_assembler_lookup_bins);
|
||||||
|
|
||||||
host->sock = sock_alloc(listen_port, MEGABYTE(2), MEGABYTE(2));
|
host->sock = sock_alloc(listen_port, MEGABYTE(2), MEGABYTE(2));
|
||||||
|
|
||||||
@ -234,8 +234,8 @@ INTERNAL u64 hash_from_address(struct sock_address address)
|
|||||||
INTERNAL struct host_channel *host_channel_from_address(struct host *host, struct sock_address address)
|
INTERNAL struct host_channel *host_channel_from_address(struct host *host, struct sock_address address)
|
||||||
{
|
{
|
||||||
u64 hash = hash_from_address(address);
|
u64 hash = hash_from_address(address);
|
||||||
struct host_channel_lookup_bucket *bucket = &host->channel_lookup_buckets[hash % host->num_channel_lookup_buckets];
|
struct host_channel_lookup_bin *bin = &host->channel_lookup_bins[hash % host->num_channel_lookup_bins];
|
||||||
for (struct host_channel *channel = bucket->first; channel; channel = channel->next_address_hash) {
|
for (struct host_channel *channel = bin->first; channel; channel = channel->next_address_hash) {
|
||||||
if (channel->address_hash == hash && sock_address_eq(channel->address, address)) {
|
if (channel->address_hash == hash && sock_address_eq(channel->address, address)) {
|
||||||
return channel;
|
return channel;
|
||||||
}
|
}
|
||||||
@ -307,15 +307,15 @@ INTERNAL struct host_channel *host_channel_alloc(struct host *host, struct sock_
|
|||||||
u64 address_hash = hash_from_address(address);
|
u64 address_hash = hash_from_address(address);
|
||||||
channel->address_hash = address_hash;
|
channel->address_hash = address_hash;
|
||||||
|
|
||||||
u64 bucket_index = address_hash % host->num_channel_lookup_buckets;
|
u64 bin_index = address_hash % host->num_channel_lookup_bins;
|
||||||
struct host_channel_lookup_bucket *bucket = &host->channel_lookup_buckets[bucket_index];
|
struct host_channel_lookup_bin *bin = &host->channel_lookup_bins[bin_index];
|
||||||
if (bucket->last) {
|
if (bin->last) {
|
||||||
channel->prev_address_hash = bucket->last;
|
channel->prev_address_hash = bin->last;
|
||||||
bucket->last->next_address_hash = channel;
|
bin->last->next_address_hash = channel;
|
||||||
} else {
|
} else {
|
||||||
bucket->first = channel;
|
bin->first = channel;
|
||||||
}
|
}
|
||||||
bucket->last = channel;
|
bin->last = channel;
|
||||||
|
|
||||||
return channel;
|
return channel;
|
||||||
}
|
}
|
||||||
@ -326,18 +326,18 @@ INTERNAL void host_channel_release(struct host_channel *channel)
|
|||||||
|
|
||||||
/* Release from lookup table */
|
/* Release from lookup table */
|
||||||
{
|
{
|
||||||
struct host_channel_lookup_bucket *bucket = &host->channel_lookup_buckets[channel->address_hash % host->num_channel_lookup_buckets];
|
struct host_channel_lookup_bin *bin = &host->channel_lookup_bins[channel->address_hash % host->num_channel_lookup_bins];
|
||||||
struct host_channel *prev = channel->prev_address_hash;
|
struct host_channel *prev = channel->prev_address_hash;
|
||||||
struct host_channel *next = channel->next_address_hash;
|
struct host_channel *next = channel->next_address_hash;
|
||||||
if (prev) {
|
if (prev) {
|
||||||
prev->next_address_hash = next;
|
prev->next_address_hash = next;
|
||||||
} else {
|
} else {
|
||||||
bucket->first = next;
|
bin->first = next;
|
||||||
}
|
}
|
||||||
if (next) {
|
if (next) {
|
||||||
next->prev_address_hash = prev;
|
next->prev_address_hash = prev;
|
||||||
} else {
|
} else {
|
||||||
bucket->last = prev;
|
bin->last = prev;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -379,8 +379,8 @@ INTERNAL u64 hash_from_channel_msg(struct host_channel_id channel_id, u64 msg_id
|
|||||||
INTERNAL struct host_msg_assembler *host_get_msg_assembler(struct host *host, struct host_channel_id channel_id, u64 msg_id)
|
INTERNAL struct host_msg_assembler *host_get_msg_assembler(struct host *host, struct host_channel_id channel_id, u64 msg_id)
|
||||||
{
|
{
|
||||||
u64 hash = hash_from_channel_msg(channel_id, msg_id);
|
u64 hash = hash_from_channel_msg(channel_id, msg_id);
|
||||||
struct host_msg_assembler_lookup_bucket *bucket = &host->msg_assembler_lookup_buckets[hash % host->num_msg_assembler_lookup_buckets];
|
struct host_msg_assembler_lookup_bin *bin = &host->msg_assembler_lookup_bins[hash % host->num_msg_assembler_lookup_bins];
|
||||||
for (struct host_msg_assembler *ma = bucket->first; ma; ma = ma->next_hash) {
|
for (struct host_msg_assembler *ma = bin->first; ma; ma = ma->next_hash) {
|
||||||
if (ma->hash == hash && host_channel_id_eq(ma->channel->id, channel_id) && ma->msg_id == msg_id) {
|
if (ma->hash == hash && host_channel_id_eq(ma->channel->id, channel_id) && ma->msg_id == msg_id) {
|
||||||
return ma;
|
return ma;
|
||||||
}
|
}
|
||||||
@ -435,14 +435,14 @@ INTERNAL struct host_msg_assembler *host_msg_assembler_alloc(struct host_channel
|
|||||||
/* Insert into lookup table */
|
/* Insert into lookup table */
|
||||||
u64 hash = hash_from_channel_msg(channel->id, msg_id);
|
u64 hash = hash_from_channel_msg(channel->id, msg_id);
|
||||||
ma->hash = hash;
|
ma->hash = hash;
|
||||||
struct host_msg_assembler_lookup_bucket *bucket = &host->msg_assembler_lookup_buckets[hash % host->num_msg_assembler_lookup_buckets];
|
struct host_msg_assembler_lookup_bin *bin = &host->msg_assembler_lookup_bins[hash % host->num_msg_assembler_lookup_bins];
|
||||||
if (bucket->last) {
|
if (bin->last) {
|
||||||
bucket->last->next_hash = ma;
|
bin->last->next_hash = ma;
|
||||||
ma->prev_hash = bucket->last;
|
ma->prev_hash = bin->last;
|
||||||
} else {
|
} else {
|
||||||
bucket->first = ma;
|
bin->first = ma;
|
||||||
}
|
}
|
||||||
bucket->last = ma;
|
bin->last = ma;
|
||||||
|
|
||||||
return ma;
|
return ma;
|
||||||
}
|
}
|
||||||
@ -470,19 +470,19 @@ INTERNAL void host_msg_assembler_release(struct host_msg_assembler *ma)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Release from lookup table */
|
/* Release from lookup table */
|
||||||
struct host_msg_assembler_lookup_bucket *bucket = &host->msg_assembler_lookup_buckets[ma->hash % host->num_msg_assembler_lookup_buckets];
|
struct host_msg_assembler_lookup_bin *bin = &host->msg_assembler_lookup_bins[ma->hash % host->num_msg_assembler_lookup_bins];
|
||||||
{
|
{
|
||||||
struct host_msg_assembler *prev = ma->prev_hash;
|
struct host_msg_assembler *prev = ma->prev_hash;
|
||||||
struct host_msg_assembler *next = ma->next_hash;
|
struct host_msg_assembler *next = ma->next_hash;
|
||||||
if (prev) {
|
if (prev) {
|
||||||
prev->next_hash = next;
|
prev->next_hash = next;
|
||||||
} else {
|
} else {
|
||||||
bucket->first = next;
|
bin->first = next;
|
||||||
}
|
}
|
||||||
if (next) {
|
if (next) {
|
||||||
next->prev_hash = prev;
|
next->prev_hash = prev;
|
||||||
} else {
|
} else {
|
||||||
bucket->last = prev;
|
bin->last = prev;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
10
src/host.h
10
src/host.h
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
struct buddy_ctx;
|
struct buddy_ctx;
|
||||||
struct host_snd_packet;
|
struct host_snd_packet;
|
||||||
struct host_channel_lookup_bucket;
|
struct host_channel_lookup_bin;
|
||||||
struct host_rcv_buffer;
|
struct host_rcv_buffer;
|
||||||
|
|
||||||
enum host_cmd_kind {
|
enum host_cmd_kind {
|
||||||
@ -81,11 +81,11 @@ struct host {
|
|||||||
struct host_snd_packet *first_free_packet; /* Allocated in `arena` */
|
struct host_snd_packet *first_free_packet; /* Allocated in `arena` */
|
||||||
struct host_msg_assembler *first_free_msg_assembler; /* Allocated in `arena` */
|
struct host_msg_assembler *first_free_msg_assembler; /* Allocated in `arena` */
|
||||||
|
|
||||||
struct host_channel_lookup_bucket *channel_lookup_buckets; /* Allocated in `arena` */
|
struct host_channel_lookup_bin *channel_lookup_bins; /* Allocated in `arena` */
|
||||||
u64 num_channel_lookup_buckets;
|
u64 num_channel_lookup_bins;
|
||||||
|
|
||||||
struct host_msg_assembler_lookup_bucket *msg_assembler_lookup_buckets; /* Allocated in `arena` */
|
struct host_msg_assembler_lookup_bin *msg_assembler_lookup_bins; /* Allocated in `arena` */
|
||||||
u64 num_msg_assembler_lookup_buckets;
|
u64 num_msg_assembler_lookup_bins;
|
||||||
|
|
||||||
/* Double buffer for incoming data */
|
/* Double buffer for incoming data */
|
||||||
struct sys_mutex rcv_buffer_write_mutex;
|
struct sys_mutex rcv_buffer_write_mutex;
|
||||||
|
|||||||
156
src/sim.c
156
src/sim.c
@ -23,9 +23,9 @@
|
|||||||
* An ent is the smallest unit of simulation state.
|
* An ent is the smallest unit of simulation state.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define CLIENT_LOOKUP_BUCKETS 127
|
#define CLIENT_LOOKUP_BINS 127
|
||||||
#define TICK_LOOKUP_BUCKETS 127
|
#define TICK_LOOKUP_BINS 127
|
||||||
#define ID_LOOKUP_BUCKETS 4096
|
#define ID_LOOKUP_BINS 4096
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Startup
|
* Startup
|
||||||
@ -102,8 +102,8 @@ struct sim_client_store *sim_client_store_alloc(void)
|
|||||||
store->arena = arena;
|
store->arena = arena;
|
||||||
}
|
}
|
||||||
store->valid = true;
|
store->valid = true;
|
||||||
store->num_client_lookup_buckets = CLIENT_LOOKUP_BUCKETS;
|
store->num_client_lookup_bins = CLIENT_LOOKUP_BINS;
|
||||||
store->client_lookup_buckets = arena_push_array_zero(&store->arena, struct sim_client_lookup_bucket, store->num_client_lookup_buckets);
|
store->client_lookup_bins = arena_push_array_zero(&store->arena, struct sim_client_lookup_bin, store->num_client_lookup_bins);
|
||||||
store->clients_arena = arena_alloc(GIGABYTE(64));
|
store->clients_arena = arena_alloc(GIGABYTE(64));
|
||||||
store->clients = arena_dry_push(&store->clients_arena, struct sim_client);
|
store->clients = arena_dry_push(&store->clients_arena, struct sim_client);
|
||||||
return store;
|
return store;
|
||||||
@ -148,8 +148,8 @@ struct sim_client *sim_client_alloc(struct sim_client_store *store)
|
|||||||
client->handle = handle;
|
client->handle = handle;
|
||||||
|
|
||||||
client->snapshots_arena = arena_alloc(GIGABYTE(8));
|
client->snapshots_arena = arena_alloc(GIGABYTE(8));
|
||||||
client->num_snapshot_lookup_buckets = TICK_LOOKUP_BUCKETS;
|
client->num_snapshot_lookup_bins = TICK_LOOKUP_BINS;
|
||||||
client->snapshot_lookup_buckets = arena_push_array_zero(&client->snapshots_arena, struct sim_snapshot_lookup_bucket, client->num_snapshot_lookup_buckets);
|
client->snapshot_lookup_bins = arena_push_array_zero(&client->snapshots_arena, struct sim_snapshot_lookup_bin, client->num_snapshot_lookup_bins);
|
||||||
|
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
@ -157,11 +157,11 @@ struct sim_client *sim_client_alloc(struct sim_client_store *store)
|
|||||||
void sim_client_release(struct sim_client *client)
|
void sim_client_release(struct sim_client *client)
|
||||||
{
|
{
|
||||||
/* Release internal snapshot memory */
|
/* Release internal snapshot memory */
|
||||||
for (u64 i = 0; i < client->num_snapshot_lookup_buckets; ++i) {
|
for (u64 i = 0; i < client->num_snapshot_lookup_bins; ++i) {
|
||||||
struct sim_snapshot_lookup_bucket *bucket = &client->snapshot_lookup_buckets[i];
|
struct sim_snapshot_lookup_bin *bin = &client->snapshot_lookup_bins[i];
|
||||||
struct sim_snapshot *ss = bucket->first;
|
struct sim_snapshot *ss = bin->first;
|
||||||
while (ss) {
|
while (ss) {
|
||||||
struct sim_snapshot *next = ss->next_in_bucket;
|
struct sim_snapshot *next = ss->next_in_bin;
|
||||||
arena_release(&ss->ents_arena);
|
arena_release(&ss->ents_arena);
|
||||||
arena_release(&ss->arena);
|
arena_release(&ss->arena);
|
||||||
ss = next;
|
ss = next;
|
||||||
@ -197,19 +197,19 @@ void sim_client_set_channel_id(struct sim_client *client, struct host_channel_id
|
|||||||
|
|
||||||
/* Remove old channel id from channel lookup */
|
/* Remove old channel id from channel lookup */
|
||||||
if (!host_channel_id_is_nil(old_channel_id)) {
|
if (!host_channel_id_is_nil(old_channel_id)) {
|
||||||
u64 bucket_index = client->channel_hash % store->num_client_lookup_buckets;
|
u64 bin_index = client->channel_hash % store->num_client_lookup_bins;
|
||||||
struct sim_client_lookup_bucket *bucket = &store->client_lookup_buckets[bucket_index];
|
struct sim_client_lookup_bin *bin = &store->client_lookup_bins[bin_index];
|
||||||
struct sim_client *prev = sim_client_from_handle(store, client->prev_in_bucket);
|
struct sim_client *prev = sim_client_from_handle(store, client->prev_in_bin);
|
||||||
struct sim_client *next = sim_client_from_handle(store, client->next_in_bucket);
|
struct sim_client *next = sim_client_from_handle(store, client->next_in_bin);
|
||||||
if (prev->valid) {
|
if (prev->valid) {
|
||||||
prev->next_in_bucket = next->handle;
|
prev->next_in_bin = next->handle;
|
||||||
} else {
|
} else {
|
||||||
bucket->first = next->handle;
|
bin->first = next->handle;
|
||||||
}
|
}
|
||||||
if (next->valid) {
|
if (next->valid) {
|
||||||
next->prev_in_bucket = prev->handle;
|
next->prev_in_bin = prev->handle;
|
||||||
} else {
|
} else {
|
||||||
bucket->last = prev->handle;
|
bin->last = prev->handle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,17 +219,17 @@ void sim_client_set_channel_id(struct sim_client *client, struct host_channel_id
|
|||||||
client->channel_id = channel_id;
|
client->channel_id = channel_id;
|
||||||
client->channel_hash = channel_hash;
|
client->channel_hash = channel_hash;
|
||||||
if (!host_channel_id_is_nil(channel_id)) {
|
if (!host_channel_id_is_nil(channel_id)) {
|
||||||
u64 bucket_index = channel_hash % store->num_client_lookup_buckets;
|
u64 bin_index = channel_hash % store->num_client_lookup_bins;
|
||||||
struct sim_client_lookup_bucket *bucket = &store->client_lookup_buckets[bucket_index];
|
struct sim_client_lookup_bin *bin = &store->client_lookup_bins[bin_index];
|
||||||
{
|
{
|
||||||
struct sim_client *prev_in_bucket = sim_client_from_handle(store, bucket->last);
|
struct sim_client *prev_in_bin = sim_client_from_handle(store, bin->last);
|
||||||
if (prev_in_bucket->valid) {
|
if (prev_in_bin->valid) {
|
||||||
prev_in_bucket->next_in_bucket = client->handle;
|
prev_in_bin->next_in_bin = client->handle;
|
||||||
client->prev_in_bucket = prev_in_bucket->handle;
|
client->prev_in_bin = prev_in_bin->handle;
|
||||||
} else {
|
} else {
|
||||||
bucket->first = client->handle;
|
bin->first = client->handle;
|
||||||
}
|
}
|
||||||
bucket->last = client->handle;
|
bin->last = client->handle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -238,9 +238,9 @@ struct sim_client *sim_client_from_channel_id(struct sim_client_store *store, st
|
|||||||
{
|
{
|
||||||
struct sim_client *res = sim_client_nil();
|
struct sim_client *res = sim_client_nil();
|
||||||
u64 channel_hash = hash_from_channel_id(channel_id);
|
u64 channel_hash = hash_from_channel_id(channel_id);
|
||||||
u64 bucket_index = channel_hash % store->num_client_lookup_buckets;
|
u64 bin_index = channel_hash % store->num_client_lookup_bins;
|
||||||
struct sim_client_lookup_bucket *bucket = &store->client_lookup_buckets[bucket_index];
|
struct sim_client_lookup_bin *bin = &store->client_lookup_bins[bin_index];
|
||||||
for (struct sim_client *client = sim_client_from_handle(store, bucket->first); client->valid; client = sim_client_from_handle(store, client->next_in_bucket)) {
|
for (struct sim_client *client = sim_client_from_handle(store, bin->first); client->valid; client = sim_client_from_handle(store, client->next_in_bin)) {
|
||||||
if (client->channel_hash == channel_hash) {
|
if (client->channel_hash == channel_hash) {
|
||||||
res = client;
|
res = client;
|
||||||
break;
|
break;
|
||||||
@ -308,15 +308,15 @@ struct sim_snapshot *sim_snapshot_alloc(struct sim_client *client, struct sim_sn
|
|||||||
ss->local_client_ent = src->local_client_ent;
|
ss->local_client_ent = src->local_client_ent;
|
||||||
ss->phys_iteration = src->phys_iteration;
|
ss->phys_iteration = src->phys_iteration;
|
||||||
|
|
||||||
/* Copy id lookup buckets */
|
/* Copy id lookup bins */
|
||||||
ss->num_id_buckets = src->num_id_buckets > 0 ? src->num_id_buckets : ID_LOOKUP_BUCKETS;
|
ss->num_id_bins = src->num_id_bins > 0 ? src->num_id_bins : ID_LOOKUP_BINS;
|
||||||
ss->id_buckets = arena_push_array(&ss->arena, struct sim_ent_bucket, ss->num_id_buckets);
|
ss->id_bins = arena_push_array(&ss->arena, struct sim_ent_bin, ss->num_id_bins);
|
||||||
if (src->num_id_buckets > 0) {
|
if (src->num_id_bins > 0) {
|
||||||
for (u64 i = 0; i < src->num_id_buckets; ++i) {
|
for (u64 i = 0; i < src->num_id_bins; ++i) {
|
||||||
ss->id_buckets[i] = src->id_buckets[i];
|
ss->id_bins[i] = src->id_bins[i];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
MEMZERO(ss->id_buckets, sizeof(*ss->id_buckets) * ss->num_id_buckets);
|
MEMZERO(ss->id_bins, sizeof(*ss->id_bins) * ss->num_id_bins);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Copy entities */
|
/* Copy entities */
|
||||||
@ -398,15 +398,15 @@ struct sim_snapshot *sim_snapshot_alloc(struct sim_client *client, struct sim_sn
|
|||||||
|
|
||||||
/* Insert into lookup */
|
/* Insert into lookup */
|
||||||
{
|
{
|
||||||
u64 bucket_index = tick % client->num_snapshot_lookup_buckets;
|
u64 bin_index = tick % client->num_snapshot_lookup_bins;
|
||||||
struct sim_snapshot_lookup_bucket *bucket = &client->snapshot_lookup_buckets[bucket_index];
|
struct sim_snapshot_lookup_bin *bin = &client->snapshot_lookup_bins[bin_index];
|
||||||
if (bucket->last) {
|
if (bin->last) {
|
||||||
bucket->last->next_in_bucket = ss;
|
bin->last->next_in_bin = ss;
|
||||||
ss->prev_in_bucket = bucket->last;
|
ss->prev_in_bin = bin->last;
|
||||||
} else {
|
} else {
|
||||||
bucket->first = ss;
|
bin->first = ss;
|
||||||
}
|
}
|
||||||
bucket->last = ss;
|
bin->last = ss;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ss;
|
return ss;
|
||||||
@ -418,19 +418,19 @@ void sim_snapshot_release(struct sim_snapshot *ss)
|
|||||||
|
|
||||||
/* Remove from lookup */
|
/* Remove from lookup */
|
||||||
{
|
{
|
||||||
u64 bucket_index = ss->tick % client->num_snapshot_lookup_buckets;
|
u64 bin_index = ss->tick % client->num_snapshot_lookup_bins;
|
||||||
struct sim_snapshot_lookup_bucket *bucket = &client->snapshot_lookup_buckets[bucket_index];
|
struct sim_snapshot_lookup_bin *bin = &client->snapshot_lookup_bins[bin_index];
|
||||||
struct sim_snapshot *prev = ss->prev_in_bucket;
|
struct sim_snapshot *prev = ss->prev_in_bin;
|
||||||
struct sim_snapshot *next = ss->next_in_bucket;
|
struct sim_snapshot *next = ss->next_in_bin;
|
||||||
if (prev) {
|
if (prev) {
|
||||||
prev->next_in_bucket = next;
|
prev->next_in_bin = next;
|
||||||
} else {
|
} else {
|
||||||
bucket->first = next;
|
bin->first = next;
|
||||||
}
|
}
|
||||||
if (next) {
|
if (next) {
|
||||||
next->prev_in_bucket = prev;
|
next->prev_in_bin = prev;
|
||||||
} else {
|
} else {
|
||||||
bucket->last = prev;
|
bin->last = prev;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -488,9 +488,9 @@ struct sim_snapshot *sim_snapshot_from_tick(struct sim_client *client, u64 tick)
|
|||||||
{
|
{
|
||||||
struct sim_snapshot *ss = sim_snapshot_nil();
|
struct sim_snapshot *ss = sim_snapshot_nil();
|
||||||
if (tick > 0) {
|
if (tick > 0) {
|
||||||
u64 bucket_index = tick % client->num_snapshot_lookup_buckets;
|
u64 bin_index = tick % client->num_snapshot_lookup_bins;
|
||||||
struct sim_snapshot_lookup_bucket *bucket = &client->snapshot_lookup_buckets[bucket_index];
|
struct sim_snapshot_lookup_bin *bin = &client->snapshot_lookup_bins[bin_index];
|
||||||
for (struct sim_snapshot *search = bucket->first; search; search = search->next_in_bucket) {
|
for (struct sim_snapshot *search = bin->first; search; search = search->next_in_bin) {
|
||||||
if (search->tick == tick) {
|
if (search->tick == tick) {
|
||||||
ss = search;
|
ss = search;
|
||||||
break;
|
break;
|
||||||
@ -652,33 +652,33 @@ void sim_snapshot_encode(struct bitbuff_writer *bw, struct sim_client *receiver,
|
|||||||
|
|
||||||
bw_write_uid(bw, receiver->ent_id.uid);
|
bw_write_uid(bw, receiver->ent_id.uid);
|
||||||
|
|
||||||
/* Id buckets */
|
/* Id bins */
|
||||||
/* TODO: Don't encode these */
|
/* TODO: Don't encode these */
|
||||||
for (u64 i = 0; i < ss1->num_id_buckets; ++i) {
|
for (u64 i = 0; i < ss1->num_id_bins; ++i) {
|
||||||
u32 old_first = 0;
|
u32 old_first = 0;
|
||||||
u32 old_last = 0;
|
u32 old_last = 0;
|
||||||
if (i < ss0->num_id_buckets) {
|
if (i < ss0->num_id_bins) {
|
||||||
struct sim_ent_bucket *old_bucket = &ss0->id_buckets[i];
|
struct sim_ent_bin *old_bin = &ss0->id_bins[i];
|
||||||
old_first = old_bucket->first;
|
old_first = old_bin->first;
|
||||||
old_last = old_bucket->last;
|
old_last = old_bin->last;
|
||||||
}
|
}
|
||||||
struct sim_ent_bucket *bucket = &ss1->id_buckets[i];
|
struct sim_ent_bin *bin = &ss1->id_bins[i];
|
||||||
u32 new_first = bucket->first;
|
u32 new_first = bin->first;
|
||||||
u32 new_last = bucket->last;
|
u32 new_last = bin->last;
|
||||||
if (new_first != old_first || new_last != old_last) {
|
if (new_first != old_first || new_last != old_last) {
|
||||||
bw_write_bit(bw, 1);
|
bw_write_bit(bw, 1);
|
||||||
bw_write_uv(bw, i);
|
bw_write_uv(bw, i);
|
||||||
if (old_first == bucket->first) {
|
if (old_first == bin->first) {
|
||||||
bw_write_bit(bw, 0);
|
bw_write_bit(bw, 0);
|
||||||
} else {
|
} else {
|
||||||
bw_write_bit(bw, 1);
|
bw_write_bit(bw, 1);
|
||||||
bw_write_uv(bw, bucket->first);
|
bw_write_uv(bw, bin->first);
|
||||||
}
|
}
|
||||||
if (old_last == bucket->last) {
|
if (old_last == bin->last) {
|
||||||
bw_write_bit(bw, 0);
|
bw_write_bit(bw, 0);
|
||||||
} else {
|
} else {
|
||||||
bw_write_bit(bw, 1);
|
bw_write_bit(bw, 1);
|
||||||
bw_write_uv(bw, bucket->last);
|
bw_write_uv(bw, bin->last);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -723,26 +723,26 @@ void sim_snapshot_decode(struct bitbuff_reader *br, struct sim_snapshot *ss)
|
|||||||
|
|
||||||
ss->local_client_ent = (struct sim_ent_id) { .uid = br_read_uid(br) };
|
ss->local_client_ent = (struct sim_ent_id) { .uid = br_read_uid(br) };
|
||||||
|
|
||||||
/* Id buckets */
|
/* Id bins */
|
||||||
/* TODO: Don't decode these, determine them implicitly from decoded ents */
|
/* TODO: Don't decode these, determine them implicitly from decoded ents */
|
||||||
{
|
{
|
||||||
b32 bucket_changed = br_read_bit(br);
|
b32 bin_changed = br_read_bit(br);
|
||||||
while (bucket_changed) {
|
while (bin_changed) {
|
||||||
u32 bucket_index = br_read_uv(br);
|
u32 bin_index = br_read_uv(br);
|
||||||
if (bucket_index < ss->num_id_buckets) {
|
if (bin_index < ss->num_id_bins) {
|
||||||
struct sim_ent_bucket *bucket = &ss->id_buckets[bucket_index];
|
struct sim_ent_bin *bin = &ss->id_bins[bin_index];
|
||||||
if (br_read_bit(br)) {
|
if (br_read_bit(br)) {
|
||||||
bucket->first = br_read_uv(br);
|
bin->first = br_read_uv(br);
|
||||||
}
|
}
|
||||||
if (br_read_bit(br)) {
|
if (br_read_bit(br)) {
|
||||||
bucket->last = br_read_uv(br);
|
bin->last = br_read_uv(br);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Invalid bucket index */
|
/* Invalid bin index */
|
||||||
ASSERT(false);
|
ASSERT(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
bucket_changed = br_read_bit(br);
|
bin_changed = br_read_bit(br);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
26
src/sim.h
26
src/sim.h
@ -24,7 +24,7 @@ struct sim_startup_receipt sim_startup(void);
|
|||||||
* Client store
|
* Client store
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
struct sim_client_lookup_bucket {
|
struct sim_client_lookup_bin {
|
||||||
struct sim_client_handle first;
|
struct sim_client_handle first;
|
||||||
struct sim_client_handle last;
|
struct sim_client_handle last;
|
||||||
};
|
};
|
||||||
@ -34,8 +34,8 @@ struct sim_client_store {
|
|||||||
struct arena arena;
|
struct arena arena;
|
||||||
|
|
||||||
/* Client lookup */
|
/* Client lookup */
|
||||||
struct sim_client_lookup_bucket *client_lookup_buckets;
|
struct sim_client_lookup_bin *client_lookup_bins;
|
||||||
u64 num_client_lookup_buckets;
|
u64 num_client_lookup_bins;
|
||||||
|
|
||||||
/* Clients */
|
/* Clients */
|
||||||
struct arena clients_arena;
|
struct arena clients_arena;
|
||||||
@ -60,7 +60,7 @@ void sim_client_store_release(struct sim_client_store *store);
|
|||||||
|
|
||||||
struct sim_snapshot;
|
struct sim_snapshot;
|
||||||
|
|
||||||
struct sim_snapshot_lookup_bucket {
|
struct sim_snapshot_lookup_bin {
|
||||||
struct sim_snapshot *first;
|
struct sim_snapshot *first;
|
||||||
struct sim_snapshot *last;
|
struct sim_snapshot *last;
|
||||||
};
|
};
|
||||||
@ -76,8 +76,8 @@ struct sim_client {
|
|||||||
u64 channel_hash;
|
u64 channel_hash;
|
||||||
|
|
||||||
struct sim_client_handle next_free;
|
struct sim_client_handle next_free;
|
||||||
struct sim_client_handle next_in_bucket;
|
struct sim_client_handle next_in_bin;
|
||||||
struct sim_client_handle prev_in_bucket;
|
struct sim_client_handle prev_in_bin;
|
||||||
|
|
||||||
/* The client entity's id in the master sim (if relevant) */
|
/* The client entity's id in the master sim (if relevant) */
|
||||||
struct sim_ent_id ent_id;
|
struct sim_ent_id ent_id;
|
||||||
@ -100,8 +100,8 @@ struct sim_client {
|
|||||||
struct sim_snapshot *first_free_snapshot;
|
struct sim_snapshot *first_free_snapshot;
|
||||||
|
|
||||||
/* Tick -> snapshot lookup */
|
/* Tick -> snapshot lookup */
|
||||||
u64 num_snapshot_lookup_buckets;
|
u64 num_snapshot_lookup_bins;
|
||||||
struct sim_snapshot_lookup_bucket *snapshot_lookup_buckets;
|
struct sim_snapshot_lookup_bin *snapshot_lookup_bins;
|
||||||
};
|
};
|
||||||
|
|
||||||
INLINE struct sim_client *sim_client_nil(void)
|
INLINE struct sim_client *sim_client_nil(void)
|
||||||
@ -143,15 +143,15 @@ struct sim_control {
|
|||||||
u32 flags;
|
u32 flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sim_ent_bucket;
|
struct sim_ent_bin;
|
||||||
|
|
||||||
struct sim_snapshot {
|
struct sim_snapshot {
|
||||||
b32 valid;
|
b32 valid;
|
||||||
u64 tick;
|
u64 tick;
|
||||||
struct sim_client *client;
|
struct sim_client *client;
|
||||||
struct sim_snapshot *next_free;
|
struct sim_snapshot *next_free;
|
||||||
struct sim_snapshot *next_in_bucket;
|
struct sim_snapshot *next_in_bin;
|
||||||
struct sim_snapshot *prev_in_bucket;
|
struct sim_snapshot *prev_in_bin;
|
||||||
u64 prev_tick;
|
u64 prev_tick;
|
||||||
u64 next_tick;
|
u64 next_tick;
|
||||||
|
|
||||||
@ -174,8 +174,8 @@ struct sim_snapshot {
|
|||||||
struct sim_ent_id local_client_ent; /* The id of the receiver's client ent */
|
struct sim_ent_id local_client_ent; /* The id of the receiver's client ent */
|
||||||
|
|
||||||
/* Id lookup */
|
/* Id lookup */
|
||||||
struct sim_ent_bucket *id_buckets;
|
struct sim_ent_bin *id_bins;
|
||||||
u64 num_id_buckets;
|
u64 num_id_bins;
|
||||||
|
|
||||||
/* Entities */
|
/* Entities */
|
||||||
struct arena ents_arena;
|
struct arena ents_arena;
|
||||||
|
|||||||
@ -174,9 +174,9 @@ void sim_ent_activate(struct sim_ent *ent, u64 current_tick)
|
|||||||
* Ent id
|
* Ent id
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
INTERNAL struct sim_ent_bucket *bucket_from_id(struct sim_snapshot *ss, struct sim_ent_id id)
|
INTERNAL struct sim_ent_bin *bin_from_id(struct sim_snapshot *ss, struct sim_ent_id id)
|
||||||
{
|
{
|
||||||
return &ss->id_buckets[id.uid.lo % ss->num_id_buckets];
|
return &ss->id_bins[id.uid.lo % ss->num_id_bins];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NOTE: This should only really happen during ent allocation (it doesn't make sense for an allocated ent's id to change) */
|
/* NOTE: This should only really happen during ent allocation (it doesn't make sense for an allocated ent's id to change) */
|
||||||
@ -187,15 +187,15 @@ void sim_ent_set_id(struct sim_ent *ent, struct sim_ent_id id)
|
|||||||
if (!sim_ent_id_eq(old_id, id)) {
|
if (!sim_ent_id_eq(old_id, id)) {
|
||||||
/* Release old from lookup */
|
/* Release old from lookup */
|
||||||
if (!sim_ent_id_eq(old_id, SIM_ENT_NIL_ID)) {
|
if (!sim_ent_id_eq(old_id, SIM_ENT_NIL_ID)) {
|
||||||
struct sim_ent_bucket *bucket = bucket_from_id(ss, old_id);
|
struct sim_ent_bin *bin = bin_from_id(ss, old_id);
|
||||||
u32 prev_index = 0;
|
u32 prev_index = 0;
|
||||||
u32 next_index = 0;
|
u32 next_index = 0;
|
||||||
u32 search_index = bucket->first;
|
u32 search_index = bin->first;
|
||||||
struct sim_ent *prev = sim_ent_nil();
|
struct sim_ent *prev = sim_ent_nil();
|
||||||
struct sim_ent *next = sim_ent_nil();
|
struct sim_ent *next = sim_ent_nil();
|
||||||
struct sim_ent *search = ent_from_index(ss, search_index);
|
struct sim_ent *search = ent_from_index(ss, search_index);
|
||||||
while (search->valid) {
|
while (search->valid) {
|
||||||
next_index = search->next_in_id_bucket;
|
next_index = search->next_in_id_bin;
|
||||||
next = ent_from_index(ss, next_index);
|
next = ent_from_index(ss, next_index);
|
||||||
if (sim_ent_id_eq(search->id, old_id)) {
|
if (sim_ent_id_eq(search->id, old_id)) {
|
||||||
break;
|
break;
|
||||||
@ -206,35 +206,35 @@ void sim_ent_set_id(struct sim_ent *ent, struct sim_ent_id id)
|
|||||||
search = next;
|
search = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Old id not in bucket, this should be impossible. */
|
/* Old id not in bin, this should be impossible. */
|
||||||
ASSERT(search->valid);
|
ASSERT(search->valid);
|
||||||
|
|
||||||
if (prev->valid) {
|
if (prev->valid) {
|
||||||
prev->next_in_id_bucket = next_index;
|
prev->next_in_id_bin = next_index;
|
||||||
} else {
|
} else {
|
||||||
bucket->first = next_index;
|
bin->first = next_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (next->valid) {
|
if (next->valid) {
|
||||||
next->prev_in_id_bucket = prev_index;
|
next->prev_in_id_bin = prev_index;
|
||||||
} else {
|
} else {
|
||||||
bucket->last = prev_index;
|
bin->last = prev_index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Insert new id into lookup */
|
/* Insert new id into lookup */
|
||||||
if (!sim_ent_id_eq(id, SIM_ENT_NIL_ID)) {
|
if (!sim_ent_id_eq(id, SIM_ENT_NIL_ID)) {
|
||||||
struct sim_ent_bucket *bucket = bucket_from_id(ss, id);
|
struct sim_ent_bin *bin = bin_from_id(ss, id);
|
||||||
u32 ent_index = index_from_ent(ss, ent);
|
u32 ent_index = index_from_ent(ss, ent);
|
||||||
struct sim_ent *last = ent_from_index(ss, bucket->last);
|
struct sim_ent *last = ent_from_index(ss, bin->last);
|
||||||
if (last->valid) {
|
if (last->valid) {
|
||||||
last->next_in_id_bucket = ent_index;
|
last->next_in_id_bin = ent_index;
|
||||||
ent->prev_in_id_bucket = bucket->last;
|
ent->prev_in_id_bin = bin->last;
|
||||||
} else {
|
} else {
|
||||||
bucket->first = ent_index;
|
bin->first = ent_index;
|
||||||
ent->prev_in_id_bucket = 0;
|
ent->prev_in_id_bin = 0;
|
||||||
}
|
}
|
||||||
bucket->last = ent_index;
|
bin->last = ent_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
ent->id = id;
|
ent->id = id;
|
||||||
@ -246,8 +246,8 @@ struct sim_ent *sim_ent_from_id(struct sim_snapshot *ss, struct sim_ent_id id)
|
|||||||
{
|
{
|
||||||
struct sim_ent *res = sim_ent_nil();
|
struct sim_ent *res = sim_ent_nil();
|
||||||
if (!sim_ent_id_eq(id, SIM_ENT_NIL_ID) && ss->valid) {
|
if (!sim_ent_id_eq(id, SIM_ENT_NIL_ID) && ss->valid) {
|
||||||
struct sim_ent_bucket *bucket = bucket_from_id(ss, id);
|
struct sim_ent_bin *bin = bin_from_id(ss, id);
|
||||||
for (struct sim_ent *e = ent_from_index(ss, bucket->first); e->valid; e = ent_from_index(ss, e->next_in_id_bucket)) {
|
for (struct sim_ent *e = ent_from_index(ss, bin->first); e->valid; e = ent_from_index(ss, e->next_in_id_bin)) {
|
||||||
if (sim_ent_id_eq(e->id, id)) {
|
if (sim_ent_id_eq(e->id, id)) {
|
||||||
res = e;
|
res = e;
|
||||||
break;
|
break;
|
||||||
@ -591,8 +591,8 @@ void sim_ent_sync(struct sim_ent *local, struct sim_ent *remote)
|
|||||||
local->top = old.top;
|
local->top = old.top;
|
||||||
|
|
||||||
/* Keep indices */
|
/* Keep indices */
|
||||||
local->next_in_id_bucket = old.next_in_id_bucket;
|
local->next_in_id_bin = old.next_in_id_bin;
|
||||||
local->prev_in_id_bucket = old.prev_in_id_bucket;
|
local->prev_in_id_bin = old.prev_in_id_bin;
|
||||||
local->next_free = old.next_free;
|
local->next_free = old.next_free;
|
||||||
|
|
||||||
sim_ent_disable_prop(local, SIM_ENT_PROP_SYNC_SRC);
|
sim_ent_disable_prop(local, SIM_ENT_PROP_SYNC_SRC);
|
||||||
|
|||||||
@ -87,8 +87,8 @@ struct sim_ent {
|
|||||||
struct sim_ent_id last;
|
struct sim_ent_id last;
|
||||||
|
|
||||||
/* Lists keyed by index in snapshot ent array */
|
/* Lists keyed by index in snapshot ent array */
|
||||||
u32 next_in_id_bucket;
|
u32 next_in_id_bin;
|
||||||
u32 prev_in_id_bucket;
|
u32 prev_in_id_bin;
|
||||||
u32 next_free;
|
u32 next_free;
|
||||||
|
|
||||||
/* ====================================================================== */
|
/* ====================================================================== */
|
||||||
@ -331,7 +331,7 @@ struct sim_ent_prop_array {
|
|||||||
u64 count;
|
u64 count;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sim_ent_bucket {
|
struct sim_ent_bin {
|
||||||
u32 first;
|
u32 first;
|
||||||
u32 last;
|
u32 last;
|
||||||
};
|
};
|
||||||
|
|||||||
68
src/space.c
68
src/space.c
@ -18,9 +18,9 @@ READONLY struct space _g_space_nil = { .valid = false };
|
|||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
/* NOTE:
|
/* NOTE:
|
||||||
* The number of buckets determines how often tiles will collide in the spatial hash.
|
* The number of bins determines how often tiles will collide in the spatial hash.
|
||||||
* For example, at `num_buckets_sqrt` = 256 (65536 buckets), tiles <1, 1>, <1, 257>, and <257, 257> will collide. */
|
* For example, at `num_bins_sqrt` = 256 (65536 bins), tiles <1, 1>, <1, 257>, and <257, 257> will collide. */
|
||||||
struct space *space_alloc(f32 cell_size, u32 num_buckets_sqrt)
|
struct space *space_alloc(f32 cell_size, u32 num_bins_sqrt)
|
||||||
{
|
{
|
||||||
struct space *space;
|
struct space *space;
|
||||||
{
|
{
|
||||||
@ -34,9 +34,9 @@ struct space *space_alloc(f32 cell_size, u32 num_buckets_sqrt)
|
|||||||
|
|
||||||
space->cell_arena = arena_alloc(GIGABYTE(64));
|
space->cell_arena = arena_alloc(GIGABYTE(64));
|
||||||
space->cell_size = cell_size;
|
space->cell_size = cell_size;
|
||||||
space->num_buckets = num_buckets_sqrt * num_buckets_sqrt;
|
space->num_bins = num_bins_sqrt * num_bins_sqrt;
|
||||||
space->num_buckets_sqrt = num_buckets_sqrt;
|
space->num_bins_sqrt = num_bins_sqrt;
|
||||||
space->buckets = arena_push_array_zero(&space->cell_arena, struct space_cell_bucket, space->num_buckets);
|
space->bins = arena_push_array_zero(&space->cell_arena, struct space_cell_bin, space->num_bins);
|
||||||
|
|
||||||
return space;
|
return space;
|
||||||
}
|
}
|
||||||
@ -51,7 +51,7 @@ void space_reset(struct space *space)
|
|||||||
{
|
{
|
||||||
arena_pop_to(&space->entry_arena, (u64)space->entries - (u64)space->entry_arena.base);
|
arena_pop_to(&space->entry_arena, (u64)space->entries - (u64)space->entry_arena.base);
|
||||||
arena_reset(&space->cell_arena);
|
arena_reset(&space->cell_arena);
|
||||||
space->buckets = arena_push_array_zero(&space->cell_arena, struct space_cell_bucket, space->num_buckets);;
|
space->bins = arena_push_array_zero(&space->cell_arena, struct space_cell_bin, space->num_bins);;
|
||||||
space->num_entries_reserved = 0;
|
space->num_entries_reserved = 0;
|
||||||
space->first_free_cell = NULL;
|
space->first_free_cell = NULL;
|
||||||
space->first_free_cell_node = NULL;
|
space->first_free_cell_node = NULL;
|
||||||
@ -83,9 +83,9 @@ INTERNAL struct v2i32 world_to_cell_coords(f32 cell_size, struct v2 world_pos)
|
|||||||
return V2I32((i32)x, (i32)y);
|
return V2I32((i32)x, (i32)y);
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERNAL i32 cell_coords_to_bucket_index(struct space *space, struct v2i32 cell_pos)
|
INTERNAL i32 cell_coords_to_bin_index(struct space *space, struct v2i32 cell_pos)
|
||||||
{
|
{
|
||||||
i32 num_buckets_sqrt = space->num_buckets_sqrt;
|
i32 num_bins_sqrt = space->num_bins_sqrt;
|
||||||
|
|
||||||
/* Cell pos of 0 is not valid and will be converted to -1 */
|
/* Cell pos of 0 is not valid and will be converted to -1 */
|
||||||
ASSERT(cell_pos.x != 0 && cell_pos.y != 0);
|
ASSERT(cell_pos.x != 0 && cell_pos.y != 0);
|
||||||
@ -96,21 +96,21 @@ INTERNAL i32 cell_coords_to_bucket_index(struct space *space, struct v2i32 cell_
|
|||||||
index_x -= (index_x >= 0);
|
index_x -= (index_x >= 0);
|
||||||
index_y -= (index_y >= 0);
|
index_y -= (index_y >= 0);
|
||||||
/* Un-mirror coords to prevent collisions between cells near the axes. (e.g. <3, 1> & <3, -1> should not collide) */
|
/* Un-mirror coords to prevent collisions between cells near the axes. (e.g. <3, 1> & <3, -1> should not collide) */
|
||||||
index_x += (index_x < 0) * (num_buckets_sqrt * ((index_x / -num_buckets_sqrt) + 1));
|
index_x += (index_x < 0) * (num_bins_sqrt * ((index_x / -num_bins_sqrt) + 1));
|
||||||
index_y += (index_y < 0) * (num_buckets_sqrt * ((index_y / -num_buckets_sqrt) + 1));
|
index_y += (index_y < 0) * (num_bins_sqrt * ((index_y / -num_bins_sqrt) + 1));
|
||||||
|
|
||||||
i32 bucket_index = (index_x % num_buckets_sqrt) + (index_y % num_buckets_sqrt) * num_buckets_sqrt;
|
i32 bin_index = (index_x % num_bins_sqrt) + (index_y % num_bins_sqrt) * num_bins_sqrt;
|
||||||
ASSERT(bucket_index >= 0 && bucket_index < (i32)space->num_buckets);
|
ASSERT(bin_index >= 0 && bin_index < (i32)space->num_bins);
|
||||||
|
|
||||||
return bucket_index;
|
return bin_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct space_cell *space_get_cell(struct space *space, struct v2i32 cell_pos)
|
struct space_cell *space_get_cell(struct space *space, struct v2i32 cell_pos)
|
||||||
{
|
{
|
||||||
i32 bucket_index = cell_coords_to_bucket_index(space, cell_pos);
|
i32 bin_index = cell_coords_to_bin_index(space, cell_pos);
|
||||||
struct space_cell_bucket *bucket = &space->buckets[bucket_index];
|
struct space_cell_bin *bin = &space->bins[bin_index];
|
||||||
struct space_cell *res = space_cell_nil();
|
struct space_cell *res = space_cell_nil();
|
||||||
for (struct space_cell *n = bucket->first_cell; n; n = n->next_in_bucket) {
|
for (struct space_cell *n = bin->first_cell; n; n = n->next_in_bin) {
|
||||||
if (v2i32_eq(n->pos, cell_pos)) {
|
if (v2i32_eq(n->pos, cell_pos)) {
|
||||||
res = n;
|
res = n;
|
||||||
break;
|
break;
|
||||||
@ -122,12 +122,12 @@ struct space_cell *space_get_cell(struct space *space, struct v2i32 cell_pos)
|
|||||||
INTERNAL void space_cell_node_alloc(struct v2i32 cell_pos, struct space_entry *entry)
|
INTERNAL void space_cell_node_alloc(struct v2i32 cell_pos, struct space_entry *entry)
|
||||||
{
|
{
|
||||||
struct space *space = space_from_entry(entry);
|
struct space *space = space_from_entry(entry);
|
||||||
i32 bucket_index = cell_coords_to_bucket_index(space, cell_pos);
|
i32 bin_index = cell_coords_to_bin_index(space, cell_pos);
|
||||||
struct space_cell_bucket *bucket = &space->buckets[bucket_index];
|
struct space_cell_bin *bin = &space->bins[bin_index];
|
||||||
|
|
||||||
/* Find existing cell */
|
/* Find existing cell */
|
||||||
struct space_cell *cell = NULL;
|
struct space_cell *cell = NULL;
|
||||||
for (struct space_cell *n = bucket->first_cell; n; n = n->next_in_bucket) {
|
for (struct space_cell *n = bin->first_cell; n; n = n->next_in_bin) {
|
||||||
if (v2i32_eq(n->pos, cell_pos)) {
|
if (v2i32_eq(n->pos, cell_pos)) {
|
||||||
cell = n;
|
cell = n;
|
||||||
break;
|
break;
|
||||||
@ -143,15 +143,15 @@ INTERNAL void space_cell_node_alloc(struct v2i32 cell_pos, struct space_entry *e
|
|||||||
cell = arena_push(&space->cell_arena, struct space_cell);
|
cell = arena_push(&space->cell_arena, struct space_cell);
|
||||||
}
|
}
|
||||||
MEMZERO_STRUCT(cell);
|
MEMZERO_STRUCT(cell);
|
||||||
if (bucket->last_cell) {
|
if (bin->last_cell) {
|
||||||
bucket->last_cell->next_in_bucket = cell;
|
bin->last_cell->next_in_bin = cell;
|
||||||
cell->prev_in_bucket = bucket->last_cell;
|
cell->prev_in_bin = bin->last_cell;
|
||||||
} else {
|
} else {
|
||||||
bucket->first_cell = cell;
|
bin->first_cell = cell;
|
||||||
}
|
}
|
||||||
bucket->last_cell = cell;
|
bin->last_cell = cell;
|
||||||
cell->pos = cell_pos;
|
cell->pos = cell_pos;
|
||||||
cell->bucket = bucket;
|
cell->bin = bin;
|
||||||
cell->valid = true;
|
cell->valid = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,7 +193,7 @@ INTERNAL void space_cell_node_release(struct space_cell_node *n)
|
|||||||
struct space_cell *cell = n->cell;
|
struct space_cell *cell = n->cell;
|
||||||
struct space_entry *entry = n->entry;
|
struct space_entry *entry = n->entry;
|
||||||
struct space *space = space_from_entry(entry);
|
struct space *space = space_from_entry(entry);
|
||||||
struct space_cell_bucket *bucket = cell->bucket;
|
struct space_cell_bin *bin = cell->bin;
|
||||||
|
|
||||||
/* Remove from entry list */
|
/* Remove from entry list */
|
||||||
{
|
{
|
||||||
@ -229,18 +229,18 @@ INTERNAL void space_cell_node_release(struct space_cell_node *n)
|
|||||||
|
|
||||||
/* If cell is now empty, release it */
|
/* If cell is now empty, release it */
|
||||||
if (!cell->first_node && !cell->last_node) {
|
if (!cell->first_node && !cell->last_node) {
|
||||||
/* Remove from bucket */
|
/* Remove from bin */
|
||||||
struct space_cell *prev = cell->prev_in_bucket;
|
struct space_cell *prev = cell->prev_in_bin;
|
||||||
struct space_cell *next = cell->next_in_bucket;
|
struct space_cell *next = cell->next_in_bin;
|
||||||
if (prev) {
|
if (prev) {
|
||||||
prev->next_in_bucket = next;
|
prev->next_in_bin = next;
|
||||||
} else {
|
} else {
|
||||||
bucket->first_cell = next;
|
bin->first_cell = next;
|
||||||
}
|
}
|
||||||
if (next) {
|
if (next) {
|
||||||
next->prev_in_bucket = prev;
|
next->prev_in_bin = prev;
|
||||||
} else {
|
} else {
|
||||||
bucket->last_cell = prev;
|
bin->last_cell = prev;
|
||||||
}
|
}
|
||||||
cell->valid = false;
|
cell->valid = false;
|
||||||
|
|
||||||
|
|||||||
18
src/space.h
18
src/space.h
@ -1,7 +1,7 @@
|
|||||||
#ifndef SPACE_H
|
#ifndef SPACE_H
|
||||||
#define SPACE_H
|
#define SPACE_H
|
||||||
|
|
||||||
struct space_cell_bucket;
|
struct space_cell_bin;
|
||||||
|
|
||||||
struct space_entry {
|
struct space_entry {
|
||||||
b32 valid;
|
b32 valid;
|
||||||
@ -40,14 +40,14 @@ struct space_cell {
|
|||||||
struct space_cell_node *first_node;
|
struct space_cell_node *first_node;
|
||||||
struct space_cell_node *last_node;
|
struct space_cell_node *last_node;
|
||||||
|
|
||||||
struct space_cell_bucket *bucket;
|
struct space_cell_bin *bin;
|
||||||
struct space_cell *prev_in_bucket;
|
struct space_cell *prev_in_bin;
|
||||||
struct space_cell *next_in_bucket;
|
struct space_cell *next_in_bin;
|
||||||
|
|
||||||
struct space_cell *next_free;
|
struct space_cell *next_free;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct space_cell_bucket {
|
struct space_cell_bin {
|
||||||
struct space_cell *first_cell;
|
struct space_cell *first_cell;
|
||||||
struct space_cell *last_cell;
|
struct space_cell *last_cell;
|
||||||
};
|
};
|
||||||
@ -57,9 +57,9 @@ struct space {
|
|||||||
f32 cell_size;
|
f32 cell_size;
|
||||||
|
|
||||||
struct arena cell_arena;
|
struct arena cell_arena;
|
||||||
struct space_cell_bucket *buckets;
|
struct space_cell_bin *bins;
|
||||||
i32 num_buckets;
|
i32 num_bins;
|
||||||
i32 num_buckets_sqrt;
|
i32 num_bins_sqrt;
|
||||||
struct space_cell *first_free_cell;
|
struct space_cell *first_free_cell;
|
||||||
struct space_cell_node *first_free_cell_node;
|
struct space_cell_node *first_free_cell_node;
|
||||||
|
|
||||||
@ -104,7 +104,7 @@ INLINE struct space *space_nil(void)
|
|||||||
* Space
|
* Space
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
struct space *space_alloc(f32 cell_size, u32 num_buckets_sqrt);
|
struct space *space_alloc(f32 cell_size, u32 num_bins_sqrt);
|
||||||
void space_release(struct space *space);
|
void space_release(struct space *space);
|
||||||
void space_reset(struct space *space);
|
void space_reset(struct space *space);
|
||||||
|
|
||||||
|
|||||||
76
src/sprite.c
76
src/sprite.c
@ -14,7 +14,7 @@
|
|||||||
#include "math.h"
|
#include "math.h"
|
||||||
|
|
||||||
#define CACHE_MEMORY_BUDGET (MEGABYTE(256))
|
#define CACHE_MEMORY_BUDGET (MEGABYTE(256))
|
||||||
#define CACHE_BUCKETS_COUNT 1024
|
#define CACHE_BINS_COUNT 1024
|
||||||
|
|
||||||
#define MAX_LOADER_THREADS 4
|
#define MAX_LOADER_THREADS 4
|
||||||
|
|
||||||
@ -30,8 +30,8 @@
|
|||||||
#define TEXTURE_ARENA_RESERVE MEGABYTE(1)
|
#define TEXTURE_ARENA_RESERVE MEGABYTE(1)
|
||||||
|
|
||||||
#define SHEET_ARENA_RESERVE MEGABYTE(64)
|
#define SHEET_ARENA_RESERVE MEGABYTE(64)
|
||||||
#define SHEET_SPAN_LOOKUP_TABLE_BUCKET_RATIO 2.0
|
#define SHEET_SPAN_LOOKUP_TABLE_BIN_RATIO 2.0
|
||||||
#define SHEET_SLICE_LOOKUP_TABLE_BUCKET_RATIO 2.0
|
#define SHEET_SLICE_LOOKUP_TABLE_BIN_RATIO 2.0
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Loader cmd structs
|
* Loader cmd structs
|
||||||
@ -96,7 +96,7 @@ struct cache_node {
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct cache_bucket {
|
struct cache_bin {
|
||||||
struct sys_mutex mutex;
|
struct sys_mutex mutex;
|
||||||
struct cache_node *first;
|
struct cache_node *first;
|
||||||
};
|
};
|
||||||
@ -104,7 +104,7 @@ struct cache_bucket {
|
|||||||
struct cache {
|
struct cache {
|
||||||
struct atomic_u64 memory_usage;
|
struct atomic_u64 memory_usage;
|
||||||
struct arena arena;
|
struct arena arena;
|
||||||
struct cache_bucket *buckets;
|
struct cache_bin *bins;
|
||||||
struct sys_mutex node_pool_mutex;
|
struct sys_mutex node_pool_mutex;
|
||||||
struct cache_node *node_pool_first_free;
|
struct cache_node *node_pool_first_free;
|
||||||
};
|
};
|
||||||
@ -248,9 +248,9 @@ struct sprite_startup_receipt sprite_startup(struct renderer_startup_receipt *re
|
|||||||
|
|
||||||
G.cache.node_pool_mutex = sys_mutex_alloc();
|
G.cache.node_pool_mutex = sys_mutex_alloc();
|
||||||
G.cache.arena = arena_alloc(GIGABYTE(64));
|
G.cache.arena = arena_alloc(GIGABYTE(64));
|
||||||
G.cache.buckets = arena_push_array_zero(&G.cache.arena, struct cache_bucket, CACHE_BUCKETS_COUNT);
|
G.cache.bins = arena_push_array_zero(&G.cache.arena, struct cache_bin, CACHE_BINS_COUNT);
|
||||||
for (u64 i = 0; i < CACHE_BUCKETS_COUNT; ++i) {
|
for (u64 i = 0; i < CACHE_BINS_COUNT; ++i) {
|
||||||
G.cache.buckets[i].mutex = sys_mutex_alloc();
|
G.cache.bins[i].mutex = sys_mutex_alloc();
|
||||||
}
|
}
|
||||||
|
|
||||||
G.load_cmds_arena = arena_alloc(GIGABYTE(64));
|
G.load_cmds_arena = arena_alloc(GIGABYTE(64));
|
||||||
@ -430,7 +430,7 @@ INTERNAL struct sprite_sheet init_sheet_from_ase_result(struct arena *arena, str
|
|||||||
if (ase.num_spans > 0) {
|
if (ase.num_spans > 0) {
|
||||||
__profscope(init_spans);
|
__profscope(init_spans);
|
||||||
sheet.spans = arena_push_array_zero(arena, struct sprite_sheet_span, sheet.spans_count);
|
sheet.spans = arena_push_array_zero(arena, struct sprite_sheet_span, sheet.spans_count);
|
||||||
sheet.spans_dict = fixed_dict_init(arena, (u64)(ase.num_spans * SHEET_SPAN_LOOKUP_TABLE_BUCKET_RATIO));
|
sheet.spans_dict = fixed_dict_init(arena, (u64)(ase.num_spans * SHEET_SPAN_LOOKUP_TABLE_BIN_RATIO));
|
||||||
u64 index = 0;
|
u64 index = 0;
|
||||||
for (struct ase_span *ase_span = ase.span_head; ase_span; ase_span = ase_span->next) {
|
for (struct ase_span *ase_span = ase.span_head; ase_span; ase_span = ase_span->next) {
|
||||||
struct string name = string_copy(arena, ase_span->name);
|
struct string name = string_copy(arena, ase_span->name);
|
||||||
@ -498,7 +498,7 @@ INTERNAL struct sprite_sheet init_sheet_from_ase_result(struct arena *arena, str
|
|||||||
/* Allocate slice groups & fill originals in 2d array */
|
/* Allocate slice groups & fill originals in 2d array */
|
||||||
sheet.slice_groups_count = num_temp_slice_group_nodes;
|
sheet.slice_groups_count = num_temp_slice_group_nodes;
|
||||||
sheet.slice_groups = arena_push_array_zero(arena, struct sprite_sheet_slice_group, sheet.slice_groups_count);
|
sheet.slice_groups = arena_push_array_zero(arena, struct sprite_sheet_slice_group, sheet.slice_groups_count);
|
||||||
sheet.slice_groups_dict = fixed_dict_init(arena, (u64)(num_temp_slice_group_nodes * SHEET_SLICE_LOOKUP_TABLE_BUCKET_RATIO));
|
sheet.slice_groups_dict = fixed_dict_init(arena, (u64)(num_temp_slice_group_nodes * SHEET_SLICE_LOOKUP_TABLE_BIN_RATIO));
|
||||||
|
|
||||||
u64 index = 0;
|
u64 index = 0;
|
||||||
for (struct temp_slice_group_node *temp_slice_group_node = temp_slice_group_head; temp_slice_group_node; temp_slice_group_node = temp_slice_group_node->next) {
|
for (struct temp_slice_group_node *temp_slice_group_node = temp_slice_group_head; temp_slice_group_node; temp_slice_group_node = temp_slice_group_node->next) {
|
||||||
@ -700,10 +700,10 @@ INTERNAL void cache_node_load_sheet(struct cache_node *n, struct sprite_tag tag)
|
|||||||
* Scope
|
* Scope
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
INTERNAL void scope_ensure_reference(struct sprite_scope *scope, struct cache_node *cache_node, u64 cache_bucket_index)
|
INTERNAL void scope_ensure_reference(struct sprite_scope *scope, struct cache_node *cache_node, u64 cache_bin_index)
|
||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
struct sprite_scope_reference **ref_next = &scope->reference_buckets[cache_bucket_index];
|
struct sprite_scope_reference **ref_next = &scope->reference_bins[cache_bin_index];
|
||||||
struct sprite_scope_reference *ref = *ref_next;
|
struct sprite_scope_reference *ref = *ref_next;
|
||||||
while (ref) {
|
while (ref) {
|
||||||
if (ref->cache_node == cache_node) {
|
if (ref->cache_node == cache_node) {
|
||||||
@ -740,13 +740,13 @@ struct sprite_scope *sprite_scope_begin(void)
|
|||||||
if (tctx->first_free_scope) {
|
if (tctx->first_free_scope) {
|
||||||
res = tctx->first_free_scope;
|
res = tctx->first_free_scope;
|
||||||
tctx->first_free_scope = res->next_free;
|
tctx->first_free_scope = res->next_free;
|
||||||
MEMZERO(res->reference_buckets, sizeof(*res->reference_buckets) * CACHE_BUCKETS_COUNT);
|
MEMZERO(res->reference_bins, sizeof(*res->reference_bins) * CACHE_BINS_COUNT);
|
||||||
*res = (struct sprite_scope) {
|
*res = (struct sprite_scope) {
|
||||||
.reference_buckets = res->reference_buckets
|
.reference_bins = res->reference_bins
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
res = arena_push_zero(&tctx->arena, struct sprite_scope);
|
res = arena_push_zero(&tctx->arena, struct sprite_scope);
|
||||||
res->reference_buckets = arena_push_array_zero(&tctx->arena, struct sprite_scope_reference *, CACHE_BUCKETS_COUNT);
|
res->reference_bins = arena_push_array_zero(&tctx->arena, struct sprite_scope_reference *, CACHE_BINS_COUNT);
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
@ -755,8 +755,8 @@ struct sprite_scope *sprite_scope_begin(void)
|
|||||||
void sprite_scope_end(struct sprite_scope *scope)
|
void sprite_scope_end(struct sprite_scope *scope)
|
||||||
{
|
{
|
||||||
struct sprite_tctx *tctx = thread_local_var_eval(&tl_sprite_tctx);
|
struct sprite_tctx *tctx = thread_local_var_eval(&tl_sprite_tctx);
|
||||||
for (u64 i = 0; i < CACHE_BUCKETS_COUNT; ++i) {
|
for (u64 i = 0; i < CACHE_BINS_COUNT; ++i) {
|
||||||
struct sprite_scope_reference *ref = scope->reference_buckets[i];
|
struct sprite_scope_reference *ref = scope->reference_bins[i];
|
||||||
while (ref) {
|
while (ref) {
|
||||||
/* Decrement refcount */
|
/* Decrement refcount */
|
||||||
node_refcount_add(ref->cache_node, -1);
|
node_refcount_add(ref->cache_node, -1);
|
||||||
@ -783,18 +783,18 @@ INTERNAL struct cache_node *node_lookup_touch(struct sprite_scope *scope, struct
|
|||||||
struct cache_node **nonmatching_next = NULL;
|
struct cache_node **nonmatching_next = NULL;
|
||||||
|
|
||||||
struct cache_node_hash hash = cache_node_hash_from_tag_hash(tag.hash, kind);
|
struct cache_node_hash hash = cache_node_hash_from_tag_hash(tag.hash, kind);
|
||||||
u64 cache_bucket_index = hash.v % CACHE_BUCKETS_COUNT;
|
u64 cache_bin_index = hash.v % CACHE_BINS_COUNT;
|
||||||
struct cache_bucket *bucket = &G.cache.buckets[cache_bucket_index];
|
struct cache_bin *bin = &G.cache.bins[cache_bin_index];
|
||||||
|
|
||||||
/* Lookup */
|
/* Lookup */
|
||||||
/* TODO: Spinlock */
|
/* TODO: Spinlock */
|
||||||
{
|
{
|
||||||
struct sys_lock lock = sys_mutex_lock_s(&bucket->mutex);
|
struct sys_lock lock = sys_mutex_lock_s(&bin->mutex);
|
||||||
nonmatching_next = &bucket->first;
|
nonmatching_next = &bin->first;
|
||||||
n = *nonmatching_next;
|
n = *nonmatching_next;
|
||||||
while (n) {
|
while (n) {
|
||||||
if (n->hash.v == hash.v) {
|
if (n->hash.v == hash.v) {
|
||||||
scope_ensure_reference(scope, n, cache_bucket_index);
|
scope_ensure_reference(scope, n, cache_bin_index);
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
nonmatching = n;
|
nonmatching = n;
|
||||||
@ -808,7 +808,7 @@ INTERNAL struct cache_node *node_lookup_touch(struct sprite_scope *scope, struct
|
|||||||
/* Allocate new node if necessary */
|
/* Allocate new node if necessary */
|
||||||
if (!n) {
|
if (!n) {
|
||||||
__profscope(node_lookup_allocate);
|
__profscope(node_lookup_allocate);
|
||||||
struct sys_lock bucket_lock = sys_mutex_lock_e(&bucket->mutex);
|
struct sys_lock bin_lock = sys_mutex_lock_e(&bin->mutex);
|
||||||
{
|
{
|
||||||
/* Alloc node */
|
/* Alloc node */
|
||||||
{
|
{
|
||||||
@ -822,8 +822,8 @@ INTERNAL struct cache_node *node_lookup_touch(struct sprite_scope *scope, struct
|
|||||||
}
|
}
|
||||||
sys_mutex_unlock(&pool_lock);
|
sys_mutex_unlock(&pool_lock);
|
||||||
}
|
}
|
||||||
/* Init node and add to bucket */
|
/* Init node and add to bin */
|
||||||
scope_ensure_reference(scope, n, cache_bucket_index);
|
scope_ensure_reference(scope, n, cache_bin_index);
|
||||||
*nonmatching_next = n;
|
*nonmatching_next = n;
|
||||||
if (nonmatching) {
|
if (nonmatching) {
|
||||||
nonmatching->next_hash = n;
|
nonmatching->next_hash = n;
|
||||||
@ -834,7 +834,7 @@ INTERNAL struct cache_node *node_lookup_touch(struct sprite_scope *scope, struct
|
|||||||
n->texture = G.nil_texture;
|
n->texture = G.nil_texture;
|
||||||
n->sheet = G.nil_sheet;
|
n->sheet = G.nil_sheet;
|
||||||
}
|
}
|
||||||
sys_mutex_unlock(&bucket_lock);
|
sys_mutex_unlock(&bin_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
return n;
|
return n;
|
||||||
@ -1039,7 +1039,7 @@ struct evict_node {
|
|||||||
b32 force_evict;
|
b32 force_evict;
|
||||||
struct cache_node_refcount refcount;
|
struct cache_node_refcount refcount;
|
||||||
struct cache_node *cache_node;
|
struct cache_node *cache_node;
|
||||||
struct cache_bucket *cache_bucket;
|
struct cache_bin *cache_bin;
|
||||||
struct evict_node *next_consider;
|
struct evict_node *next_consider;
|
||||||
struct evict_node *next_consider_lru;
|
struct evict_node *next_consider_lru;
|
||||||
struct evict_node *next_evicted;
|
struct evict_node *next_evicted;
|
||||||
@ -1063,11 +1063,11 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sprite_evictor_thread_entry_point, arg)
|
|||||||
b32 cache_over_budget = atomic_u64_eval(&G.cache.memory_usage) > CACHE_MEMORY_BUDGET;
|
b32 cache_over_budget = atomic_u64_eval(&G.cache.memory_usage) > CACHE_MEMORY_BUDGET;
|
||||||
if (cache_over_budget || RESOURCE_RELOADING) {
|
if (cache_over_budget || RESOURCE_RELOADING) {
|
||||||
__profscope(eviction_scan);
|
__profscope(eviction_scan);
|
||||||
for (u64 i = 0; i < CACHE_BUCKETS_COUNT; ++i) {
|
for (u64 i = 0; i < CACHE_BINS_COUNT; ++i) {
|
||||||
struct cache_bucket *bucket = &G.cache.buckets[i];
|
struct cache_bin *bin = &G.cache.bins[i];
|
||||||
struct sys_lock bucket_lock = sys_mutex_lock_s(&bucket->mutex);
|
struct sys_lock bin_lock = sys_mutex_lock_s(&bin->mutex);
|
||||||
{
|
{
|
||||||
struct cache_node *n = bucket->first;
|
struct cache_node *n = bin->first;
|
||||||
while (n) {
|
while (n) {
|
||||||
b32 consider_for_eviction = false;
|
b32 consider_for_eviction = false;
|
||||||
b32 force_evict = false;
|
b32 force_evict = false;
|
||||||
@ -1122,7 +1122,7 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sprite_evictor_thread_entry_point, arg)
|
|||||||
if (consider_for_eviction) {
|
if (consider_for_eviction) {
|
||||||
struct evict_node *evict_node = arena_push_zero(scratch.arena, struct evict_node);
|
struct evict_node *evict_node = arena_push_zero(scratch.arena, struct evict_node);
|
||||||
evict_node->cache_node = n;
|
evict_node->cache_node = n;
|
||||||
evict_node->cache_bucket = bucket;
|
evict_node->cache_bin = bin;
|
||||||
evict_node->refcount = refcount;
|
evict_node->refcount = refcount;
|
||||||
evict_node->force_evict = force_evict;
|
evict_node->force_evict = force_evict;
|
||||||
evict_node->next_consider = head_consider;
|
evict_node->next_consider = head_consider;
|
||||||
@ -1132,7 +1132,7 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sprite_evictor_thread_entry_point, arg)
|
|||||||
n = n->next_hash;
|
n = n->next_hash;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sys_mutex_unlock(&bucket_lock);
|
sys_mutex_unlock(&bin_lock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1162,19 +1162,19 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sprite_evictor_thread_entry_point, arg)
|
|||||||
__profscope(eviction_cache_removal);
|
__profscope(eviction_cache_removal);
|
||||||
b32 stop_evicting = false;
|
b32 stop_evicting = false;
|
||||||
for (struct evict_node *en = head_consider_lru; en && !stop_evicting; en = en->next_consider_lru) {
|
for (struct evict_node *en = head_consider_lru; en && !stop_evicting; en = en->next_consider_lru) {
|
||||||
struct cache_bucket *bucket = en->cache_bucket;
|
struct cache_bin *bin = en->cache_bin;
|
||||||
struct cache_node *n = en->cache_node;
|
struct cache_node *n = en->cache_node;
|
||||||
struct sys_lock bucket_lock = sys_mutex_lock_e(&bucket->mutex);
|
struct sys_lock bin_lock = sys_mutex_lock_e(&bin->mutex);
|
||||||
{
|
{
|
||||||
struct cache_node_refcount refcount = *(struct cache_node_refcount *)atomic_u64_raw(&n->refcount_struct);
|
struct cache_node_refcount refcount = *(struct cache_node_refcount *)atomic_u64_raw(&n->refcount_struct);
|
||||||
if (refcount.count > 0 || ((refcount.last_modified_cycle != en->refcount.last_modified_cycle) && !en->force_evict)) {
|
if (refcount.count > 0 || ((refcount.last_modified_cycle != en->refcount.last_modified_cycle) && !en->force_evict)) {
|
||||||
/* Cache node has been referenced since scan, skip eviction. */
|
/* Cache node has been referenced since scan, skip eviction. */
|
||||||
} else if (en->force_evict || atomic_u64_eval(&G.cache.memory_usage) > CACHE_MEMORY_BUDGET) {
|
} else if (en->force_evict || atomic_u64_eval(&G.cache.memory_usage) > CACHE_MEMORY_BUDGET) {
|
||||||
/* Remove from cache bucket */
|
/* Remove from cache bin */
|
||||||
if (n->prev_hash) {
|
if (n->prev_hash) {
|
||||||
n->prev_hash->next_hash = n->next_hash;
|
n->prev_hash->next_hash = n->next_hash;
|
||||||
} else {
|
} else {
|
||||||
bucket->first = n->next_hash;
|
bin->first = n->next_hash;
|
||||||
}
|
}
|
||||||
if (n->next_hash) {
|
if (n->next_hash) {
|
||||||
n->next_hash->prev_hash = n->prev_hash;
|
n->next_hash->prev_hash = n->prev_hash;
|
||||||
@ -1188,7 +1188,7 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sprite_evictor_thread_entry_point, arg)
|
|||||||
stop_evicting = true;
|
stop_evicting = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sys_mutex_unlock(&bucket_lock);
|
sys_mutex_unlock(&bin_lock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -32,7 +32,7 @@ b32 sprite_tag_eq(struct sprite_tag t1, struct sprite_tag t2);
|
|||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
struct sprite_scope {
|
struct sprite_scope {
|
||||||
struct sprite_scope_reference **reference_buckets;
|
struct sprite_scope_reference **reference_bins;
|
||||||
struct sprite_scope *next_free;
|
struct sprite_scope *next_free;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
32
src/util.h
32
src/util.h
@ -119,7 +119,7 @@ INLINE void merge_sort(void *items, u64 item_count, u64 item_size, sort_compare_
|
|||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Fixed Dict
|
* Fixed Dict
|
||||||
*
|
*
|
||||||
* Simple fixed bucket-count string->value chaining dict for generic use
|
* Simple fixed bin-count string->value chaining dict for generic use
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
struct fixed_dict_entry {
|
struct fixed_dict_entry {
|
||||||
@ -129,22 +129,22 @@ struct fixed_dict_entry {
|
|||||||
struct fixed_dict_entry *next;
|
struct fixed_dict_entry *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fixed_dict_bucket {
|
struct fixed_dict_bin {
|
||||||
struct fixed_dict_entry *entry_head;
|
struct fixed_dict_entry *entry_head;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fixed_dict {
|
struct fixed_dict {
|
||||||
u64 buckets_count;
|
u64 bins_count;
|
||||||
struct fixed_dict_bucket *buckets;
|
struct fixed_dict_bin *bins;
|
||||||
};
|
};
|
||||||
|
|
||||||
INLINE struct fixed_dict fixed_dict_init(struct arena *arena, u64 buckets_count)
|
INLINE struct fixed_dict fixed_dict_init(struct arena *arena, u64 bins_count)
|
||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
struct fixed_dict dict = ZI;
|
struct fixed_dict dict = ZI;
|
||||||
buckets_count = max_u64(buckets_count, 1); /* Ensure at least 1 bucket */
|
bins_count = max_u64(bins_count, 1); /* Ensure at least 1 bin */
|
||||||
dict.buckets_count = buckets_count;
|
dict.bins_count = bins_count;
|
||||||
dict.buckets = arena_push_array_zero(arena, struct fixed_dict_bucket, buckets_count);
|
dict.bins = arena_push_array_zero(arena, struct fixed_dict_bin, bins_count);
|
||||||
return dict;
|
return dict;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,10 +154,10 @@ INLINE void fixed_dict_set(struct arena *arena, struct fixed_dict *dict, struct
|
|||||||
__prof;
|
__prof;
|
||||||
|
|
||||||
u64 hash = hash_fnv64(HASH_FNV64_BASIS, key);
|
u64 hash = hash_fnv64(HASH_FNV64_BASIS, key);
|
||||||
u64 index = hash % dict->buckets_count;
|
u64 index = hash % dict->bins_count;
|
||||||
struct fixed_dict_bucket *bucket = &dict->buckets[index];
|
struct fixed_dict_bin *bin = &dict->bins[index];
|
||||||
|
|
||||||
struct fixed_dict_entry *entry = bucket->entry_head;
|
struct fixed_dict_entry *entry = bin->entry_head;
|
||||||
while (entry) {
|
while (entry) {
|
||||||
if (hash == entry->hash) {
|
if (hash == entry->hash) {
|
||||||
/* Existing match found, replace its contents */
|
/* Existing match found, replace its contents */
|
||||||
@ -173,9 +173,9 @@ INLINE void fixed_dict_set(struct arena *arena, struct fixed_dict *dict, struct
|
|||||||
entry->key = key;
|
entry->key = key;
|
||||||
entry->value = value;
|
entry->value = value;
|
||||||
entry->hash = hash;
|
entry->hash = hash;
|
||||||
entry->next = bucket->entry_head;
|
entry->next = bin->entry_head;
|
||||||
|
|
||||||
bucket->entry_head = entry;
|
bin->entry_head = entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
INLINE void *fixed_dict_get(const struct fixed_dict *dict, struct string key)
|
INLINE void *fixed_dict_get(const struct fixed_dict *dict, struct string key)
|
||||||
@ -183,10 +183,10 @@ INLINE void *fixed_dict_get(const struct fixed_dict *dict, struct string key)
|
|||||||
__prof;
|
__prof;
|
||||||
|
|
||||||
u64 hash = hash_fnv64(HASH_FNV64_BASIS, key);
|
u64 hash = hash_fnv64(HASH_FNV64_BASIS, key);
|
||||||
u64 index = hash % dict->buckets_count;
|
u64 index = hash % dict->bins_count;
|
||||||
struct fixed_dict_bucket *bucket = &dict->buckets[index];
|
struct fixed_dict_bin *bin = &dict->bins[index];
|
||||||
|
|
||||||
for (struct fixed_dict_entry *entry = bucket->entry_head; entry; entry = entry->next) {
|
for (struct fixed_dict_entry *entry = bin->entry_head; entry; entry = entry->next) {
|
||||||
if (hash == entry->hash) {
|
if (hash == entry->hash) {
|
||||||
/* Match found */
|
/* Match found */
|
||||||
return entry->value;
|
return entry->value;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user