Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions gpu/vk/vk_bank.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ std::vector<TexReg> tex_regs;
std::vector<SampReg> samp_regs;
std::unordered_map<uint64_t, std::vector<int>> regs_by_serial;
std::atomic<uint64_t> reg_gen{1}; // (bumped by every texture registration: resolved handles go stale)
std::atomic<uint64_t> samp_gen{1}; // (bumped when a sampler registration's contents change: sampler_for's cache, vk_draw.cpp)
// (and a version a slot: caches of what a slot resolves to check theirs, not every registration's)
constexpr int kSlotVersions = 1 << 20;
std::unique_ptr<std::atomic<uint32_t>[]> slot_versions{new std::atomic<uint32_t>[kSlotVersions]()};
Expand Down Expand Up @@ -179,8 +180,14 @@ void register_sampler_copy(int id, const nvn_samp_par& par) {
const nvn_samp_par* p = &par;
std::lock_guard lk(reg_mu);
if ((size_t)id >= samp_regs.size()) samp_regs.resize((size_t)id + 256);
// (sampler_for's cache goes stale only when a registration's contents change, not at each rewrite of the same)
const bool same = samp_regs[id].ok && !std::memcmp(&samp_regs[id].p, p, sizeof *p);
samp_regs[id].p = *p;
samp_regs[id].ok = true;
if (!same) samp_gen.fetch_add(1, std::memory_order_acq_rel);
}
uint64_t sampler_registrations_generation() {
return samp_gen.load(std::memory_order_acquire);
}
void texture_released(uint64_t serial) {
std::lock_guard lk(reg_mu);
Expand Down
17 changes: 17 additions & 0 deletions gpu/vk/vk_draw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ namespace mkwvk {
struct PointerEntry { uint64_t addr, size; };
const PointerEntry* pointer_table(const NvnState& s, int stage);
uint32_t stage_cbuf_word(const NvnState& s, const Stage& st, uint32_t index, uint32_t offset); // (vk_shader.cpp)
uint64_t sampler_registrations_generation(); // (vk_bank.cpp: sampler_for's cache)
namespace {

// ---- (hookshot) RX_VK_PROF_FINE=1: where a draw's time goes, finer than the frame line's phases, and what each draw does ----
Expand Down Expand Up @@ -1272,7 +1273,23 @@ uint32_t aniso_override() {
return n;
}
/// compare: the shader reads depth with a reference (a sampler without one cannot compare)
VkSampler sampler_make(int id, bool compare);
// (each texture of each draw found its sampler through reg_mu, a copy of the registration, a hash of it and a map lookup:
// ~48000 times a frame at 3000 draws. Now a thread's table by id and compare, good while no sampler registration's contents
// changed (sampler_registrations_generation). RX_VK_SAMPLER_CACHE=0: off)
VkSampler sampler_for(int id, bool compare) {
static const bool on = !getenv("RX_VK_SAMPLER_CACHE") || atoi(getenv("RX_VK_SAMPLER_CACHE")) != 0;
if (!on || id < 0 || id >= 4096) return sampler_make(id, compare);
struct Entry { uint64_t gen; VkSampler s; };
static thread_local Entry table[2][4096]; // (gen 0: never filled; the generation starts at 1)
const uint64_t gen = sampler_registrations_generation(); // (read first: a registration after it makes the next call miss)
Entry& e = table[compare ? 1 : 0][id];
if (e.gen == gen) return e.s;
const VkSampler made = sampler_make(id, compare);
e = {gen, made};
return made;
}
VkSampler sampler_make(int id, bool compare) {
nvn_samp_par p{};
if (!sampler_of(id, &p)) p.minf = NVN_MIN_FILTER_LINEAR, p.magf = NVN_MAG_FILTER_LINEAR, p.lod_max = 1000.0f;
uint64_t key = mix(compare ? 0xC0 : 0xAB, aniso_override());
Expand Down
Loading