Files
LibretroAdmin 591480dbb7 Granite: look up the device caches without a lock
Shaders, programs and their pipelines, pipeline layouts, descriptor set
allocators, render passes and immutable samplers now live in an
insert-only map of pointers: a slot is claimed with one CAS, a lookup
is acquire loads that never wait, and a full segment is sealed and a
larger one put in front of it - nothing is copied, moved or freed before
the device goes. The read-only cache lock, its promotion and the lock
every command buffer held for its lifetime are gone.

tests/pgscache races inserts and lookups on the map while it grows.
2026-10-28 08:21:48 +01:00

69 lines
1.3 KiB
C++

/* The device caches' map, Util::InsertOnlyHashMap, behind a C interface
* for main.c: nodes that count themselves, so a duplicate an insert made
* and threw away shows in the count. */
#include "insert_only_hash_map.hpp"
#include "intrusive_hash_map.hpp"
#include <stdint.h>
namespace
{
retro_atomic_int_t live;
struct Node : Util::IntrusiveHashMapEnabled<Node>
{
explicit Node(uint64_t key_)
: key(key_)
{
retro_atomic_fetch_add_int(&live, 1);
}
~Node()
{
retro_atomic_fetch_sub_int(&live, 1);
}
uint64_t key;
};
typedef Util::InsertOnlyHashMap<Node> Map;
}
extern "C" {
void *pgscache_new(unsigned capacity)
{
return new Map(capacity);
}
void pgscache_delete(void *map)
{
delete static_cast<Map *>(map);
}
void *pgscache_insert(void *map, uint64_t hash, uint64_t key)
{
Map *m = static_cast<Map *>(map);
Node *n = m->find(hash);
return n ? n : m->emplace_yield(hash, key);
}
void *pgscache_find(void *map, uint64_t hash)
{
return static_cast<Map *>(map)->find(hash);
}
uint64_t pgscache_key(const void *node)
{
return static_cast<const Node *>(node)->key;
}
unsigned long pgscache_count(void *map)
{
unsigned long n = 0;
static_cast<Map *>(map)->for_each([&n](Node &) { n++; });
return n;
}
long pgscache_live(void)
{
return retro_atomic_load_acquire_int(&live);
}
}