mirror of
https://github.com/Dingo-Shenanigans/ReSkate.git
synced 2026-10-27 04:57:09 +01:00
Shaders: of two usable custom graphs under an alias-only winner, the higher-priority pack's is kept
The promotion loop went through the edits in the order they were absorbed, lowest priority first, and kept the first usable graph, so a lower pack's graph won and the higher pack's private rows were dropped. It now looks from the highest priority down. The archive test covers two custom packs with their own bytecode and different second programs (it runs with a game root, as the other archive checks do).
This commit is contained in:
1 parent
ee830586b7
commit
2ef8b7b397
2 files changed
+23
-6
No files matched your search
@@ -1029,10 +1029,12 @@ void catalog_checks_native_cooperation_again_when_the_variant_changes() {
|
||||
"two private contributors reusing a GUID are both refused in either priority order");
|
||||
}
|
||||
}
|
||||
// `second_custom`: a higher-priority custom pack too, with its own bytecode, so both custom graphs can
|
||||
// be kept; the higher one's must be.
|
||||
void shader_selection_checks_the_winner(bool delivered, bool changed_heap, bool alias_first, bool overwritten = false,
|
||||
bool encoder_available = true) {
|
||||
bool encoder_available = true, bool second_custom = false) {
|
||||
Fixture fixture("shader-selection-" + std::to_string(delivered) + std::to_string(changed_heap) +
|
||||
std::to_string(alias_first) + std::to_string(overwritten));
|
||||
std::to_string(alias_first) + std::to_string(overwritten) + std::to_string(second_custom));
|
||||
const auto table = [](bool extended) {
|
||||
Resource resource{"test/program_lookup", Bytes(extended ? 544 : 208)};
|
||||
const std::uint32_t count = extended ? 2 : 1;
|
||||
@@ -1055,7 +1057,10 @@ void shader_selection_checks_the_winner(bool delivered, bool changed_heap, bool
|
||||
auto aliases = rows(table(false), {{1, 0}, {2, 0}});
|
||||
auto custom = rows(table(true), {{1, 0}, {2, 0}, {5, 0}, {9, 1}, {99, 2}});
|
||||
if (changed_heap) custom.payload[192] = std::byte{8};
|
||||
const auto write_layer = [&](const fs::path& root, bool patch, const Resource& programs, bool code, unsigned code_version) {
|
||||
auto higher = rows(table(true), {{1, 0}, {2, 0}, {11, 1}});
|
||||
higher.payload[400] = std::byte{3}; // its own second program: another graph than the lower pack's
|
||||
const auto write_layer = [&](const fs::path& root, bool patch, const Resource& programs, bool code, unsigned code_version,
|
||||
const char* code_name = "shaders/bytecode/test", std::uint32_t code_id = 43) {
|
||||
fs::create_directories(root / "Win32" / "pkg");
|
||||
write(root / "layout.toc", layout_toc());
|
||||
fb::BinaryBundle manifest;
|
||||
@@ -1069,7 +1074,7 @@ void shader_selection_checks_the_winner(bool delivered, bool changed_heap, bool
|
||||
manifest.resources.push_back(asset);
|
||||
const Bytes bytecode{static_cast<std::byte>(code_version)};
|
||||
if (code) {
|
||||
asset.name = "shaders/bytecode/test"; asset.resourceId = 43; asset.resourceType = fb::shader::bytecodeType;
|
||||
asset.name = code_name; asset.resourceId = code_id; asset.resourceType = fb::shader::bytecodeType;
|
||||
asset.sha1 = mods::detail::sha1_of(bytecode); asset.originalSize = bytecode.size(); asset.resourceMeta.assign(16, std::byte{0});
|
||||
manifest.resources.push_back(asset);
|
||||
}
|
||||
@@ -1089,7 +1094,11 @@ void shader_selection_checks_the_winner(bool delivered, bool changed_heap, bool
|
||||
write_layer(fixture.catalog.data_root / "Data", false, stock, false, 0);
|
||||
write_layer(fixture.catalog.root / "custom", true, custom, delivered, 1);
|
||||
write_layer(fixture.catalog.root / "aliases", true, aliases, overwritten, 2);
|
||||
for (const auto* name : alias_first ? std::vector<const char*>{"aliases", "custom"} : std::vector<const char*>{"custom", "aliases"}) {
|
||||
if (second_custom) write_layer(fixture.catalog.root / "higher", true, higher, true, 3, "shaders/bytecode/higher", 44);
|
||||
// The first mod listed has the highest priority.
|
||||
auto order = alias_first ? std::vector<const char*>{"aliases", "custom"} : std::vector<const char*>{"custom", "aliases"};
|
||||
if (second_custom) order = {"aliases", "higher", "custom"};
|
||||
for (const auto* name : order) {
|
||||
mods::Mod mod; mod.name = name; mod.directory = fixture.catalog.root / name; mod.provides_layout = true;
|
||||
fixture.catalog.mods.push_back(std::move(mod));
|
||||
}
|
||||
@@ -1139,6 +1148,11 @@ void shader_selection_checks_the_winner(bool delivered, bool changed_heap, bool
|
||||
expect(index < count, "native output rows stay in the retained graph's range");
|
||||
}
|
||||
}
|
||||
if (second_custom) {
|
||||
expect(count == 2 && keys.contains(11) && !keys.contains(9),
|
||||
"of two usable custom graphs under an alias-only winner, the higher-priority one is kept");
|
||||
return;
|
||||
}
|
||||
expect(keys.contains(2) && !keys.contains(99), "safe stock aliases survive and invalid winning rows are actually written out");
|
||||
expect(keys.contains(9) == private_graph, "unproved graphs cannot leak private program indices into stock");
|
||||
expect(keys.contains(5) == !changed_heap, "a non-retained custom contributor still contributes a proven stock alias");
|
||||
@@ -1155,6 +1169,7 @@ int main(int argc, char** argv) try {
|
||||
shader_selection_checks_the_winner(false, false, false);
|
||||
shader_selection_checks_the_winner(true, true, false);
|
||||
shader_selection_checks_the_winner(true, false, true, true);
|
||||
shader_selection_checks_the_winner(true, false, true, false, true, true);
|
||||
} else {
|
||||
shader_selection_checks_the_winner(true, false, true, false, false);
|
||||
std::cout << "Successful shader archive selection checks require a local game root; skipped\n";
|
||||
|
||||
@@ -1224,7 +1224,9 @@ fb::TocDocument combine(const fs::path& baseToc, const fs::path& baseRoot,
|
||||
retainedBytes = baseBytes;
|
||||
}
|
||||
if (fb::shader::only_stock_aliases({retainedBytes, retained->resourceMeta}, stockTable)) {
|
||||
for (std::size_t i = 0; i < edits.size(); ++i) {
|
||||
// `edits` is lowest priority first, as the copies were absorbed: the
|
||||
// highest-priority usable graph is the one kept.
|
||||
for (std::size_t i = edits.size(); i-- > 0;) {
|
||||
const fb::shader::Table candidate{editBytes[i], edits[i]->resourceMeta};
|
||||
if (fb::shader::same_program_graph(candidate, stockTable) || !usable(candidate, edits[i])) continue;
|
||||
retained = edits[i];
|
||||
|
||||
Reference in new issue
Block a user