Files
AnyPS5/core/libs/prx/libSceAgcDriver/tests/DccKeySharing.cpp
T
Dean Galvin a431082abc perf(agc): keep a surface's storage image when another descriptor names uncompressed DCC keys
PPSA21564's galaxy map renders a 1920x1080 surface as a color target whose
CB names DCC keys at one address and then writes it from a compute shader
whose T# names keys at another. Both key ranges read uncompressed every
frame, but the storage cache remade the surface's image whenever a
descriptor named metadata other than the image's, so the image was
flushed, destroyed, created and uploaded twice a frame (1231 constructions
in a 56 s scene), with the views and draw recipes built on it thrown away
each time.

A descriptor naming other keys now keeps the image when the move is
unobservable: the image's own keys and the named keys both read
uncompressed, and its content was neither uploaded nor filled under a
clear code. That is exactly the content an image made under the named
keys would hold once this one's pending results were stored. Any other
case (a fast clear of either key range, a register clear, an image
holding a clear) still remakes the image as before, so clears of the new
keys reach it and pending results are stored first.

Every proof that stands in for a lookup checks the same rule: the sampled
view hit, the fast revalidation of views and storage elements (storage
elements now record their descriptor's keys), the own-object refresh, and
the draw recipe's resident targets. Named-key scans keep per-image proofs,
so a repeated check costs no scan while the key bytes are unstamped.

agc_dcc_key_sharing drives KeysServeSurface, the rule ServesKeysAt uses,
through a model of the storage cache.
2026-10-04 03:20:46 +13:00

151 lines
5.7 KiB
C++

#include "prx/libSceAgcDriver/Graphics/include/DccMetadata.hpp"
#include <cstdint>
#include <cstdio>
#include <map>
#include <optional>
using namespace AgcDriver::Graphics;
namespace {
int failures = 0;
void Expect(bool condition, const char* what) {
if (condition) return;
std::fprintf(stderr, "FAIL: %s\n", what);
++failures;
}
struct Keys {
std::map<std::uint64_t, DccKeys> ranges;
int reads = 0;
DccKeys Read(std::uint64_t address) {
++reads;
if (address == 0) return DccKeys::Uncompressed;
const auto it = ranges.find(address);
return it == ranges.end() ? DccKeys::Uncompressed : it->second;
}
};
struct Image {
std::uint64_t dcc = 0;
DccKeys uploaded = DccKeys::Uncompressed;
DccKeys filled = DccKeys::Uncompressed;
};
struct SurfaceCache {
Keys& keys;
bool shared = true;
std::optional<Image> image;
int made = 0;
int remade = 0;
int uploads = 0;
bool Serves(const Image& held, std::uint64_t named) {
if (!shared) return named == 0 || named == held.dcc;
return KeysServeSurface(held.dcc, held.uploaded, held.filled, named, [&] { return keys.Read(held.dcc); }, [&] { return keys.Read(named); });
}
const Image& Lookup(std::uint64_t named) {
if (image.has_value() && Serves(*image, named)) {
const auto current = keys.Read(image->dcc);
if (current != image->uploaded) {
image->uploaded = current;
++uploads;
}
return *image;
}
if (image.has_value()) ++remade;
else ++made;
image = Image{named, keys.Read(named), DccKeys::Uncompressed};
++uploads;
return *image;
}
};
constexpr std::uint64_t TargetKeys = 0x570526000;
constexpr std::uint64_t StorageKeys = 0x5705e0000;
void worldMapFrames() {
for (const bool shared : {true, false}) {
Keys keys;
SurfaceCache cache{keys, shared};
for (int frame = 0; frame < 100; ++frame) {
cache.Lookup(TargetKeys);
cache.Lookup(StorageKeys);
cache.Lookup(StorageKeys);
}
if (shared) {
Expect(cache.made == 1 && cache.remade == 0, "a surface whose two descriptors name uncompressed keys was remade");
Expect(cache.uploads == 1, "a shared surface was uploaded again with nothing changed");
Expect(cache.image->dcc == TargetKeys, "the shared image left the keys it follows");
} else {
Expect(cache.remade == 199, "the unshared model does not reproduce the map's two remakes a frame");
}
}
}
void namedClearRemakes() {
Keys keys;
SurfaceCache cache{keys};
cache.Lookup(TargetKeys);
keys.ranges[StorageKeys] = DccKeys::Clear0000;
const auto& image = cache.Lookup(StorageKeys);
Expect(cache.remade == 1 && image.dcc == StorageKeys && image.uploaded == DccKeys::Clear0000, "a fast clear of the named keys did not reach the surface's image");
const auto& own = cache.Lookup(StorageKeys);
Expect(cache.remade == 1 && own.uploaded == DccKeys::Clear0000, "the image of the cleared keys did not serve its own keys");
cache.Lookup(TargetKeys);
Expect(cache.remade == 2, "uncompressed keys shared an image holding a clear");
}
void followedClearRemakes() {
Keys keys;
SurfaceCache cache{keys};
cache.Lookup(TargetKeys);
keys.ranges[TargetKeys] = DccKeys::Clear1111;
const auto& image = cache.Lookup(StorageKeys);
Expect(cache.remade == 1 && image.dcc == StorageKeys && image.uploaded == DccKeys::Uncompressed, "a descriptor over uncompressed keys was served an image whose own keys are a clear");
}
void filledKeysRemake() {
Keys keys;
SurfaceCache cache{keys};
cache.Lookup(TargetKeys);
cache.image->filled = DccKeys::Clear0001;
cache.Lookup(StorageKeys);
Expect(cache.remade == 1, "an image holding a key fill served other keys");
}
void serveRules() {
Keys keys;
keys.ranges[TargetKeys] = DccKeys::Clear0000;
Expect(KeysServeSurface(TargetKeys, DccKeys::Clear0000, DccKeys::Uncompressed, 0, [&] { return keys.Read(TargetKeys); }, [&] { return keys.Read(0); }), "a descriptor without metadata was refused");
Expect(KeysServeSurface(TargetKeys, DccKeys::Clear0000, DccKeys::Uncompressed, TargetKeys, [&] { return keys.Read(TargetKeys); }, [&] { return keys.Read(TargetKeys); }), "the image's own keys were refused");
Expect(keys.reads == 0, "the own-keys and no-metadata answers scanned keys");
Expect(!KeysServeSurface(TargetKeys, DccKeys::Clear0000, DccKeys::Uncompressed, StorageKeys, [&] { return keys.Read(TargetKeys); }, [&] { return keys.Read(StorageKeys); }), "an image uploaded under a clear served other keys");
Expect(keys.reads == 0, "a refusal by the uploaded keys scanned keys");
keys.ranges[StorageKeys] = DccKeys::Mixed;
keys.ranges[TargetKeys] = DccKeys::Uncompressed;
Expect(!KeysServeSurface(TargetKeys, DccKeys::Uncompressed, DccKeys::Uncompressed, StorageKeys, [&] { return keys.Read(TargetKeys); }, [&] { return keys.Read(StorageKeys); }), "keys that do not read uncompressed were served");
int followedReads = 0;
Expect(KeysServeSurface(0, DccKeys::Uncompressed, DccKeys::Uncompressed, TargetKeys, [&] { ++followedReads; return DccKeys::Clear0000; }, [&] { return keys.Read(TargetKeys); }), "an image without metadata did not serve uncompressed keys");
Expect(followedReads == 0, "an image without metadata scanned keys of its own");
}
}
int main() {
worldMapFrames();
namedClearRemakes();
followedClearRemakes();
filledKeysRemake();
serveRules();
if (failures != 0) {
std::fprintf(stderr, "%d DCC key sharing checks failed\n", failures);
return 1;
}
std::printf("DCC key sharing tests passed\n");
return 0;
}