mirror of
https://github.com/Awakenchan/LanternEngine.git
synced 2026-11-10 09:21:42 -10:00
388 lines
21 KiB
C++
388 lines
21 KiB
C++
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
#include "../gpu/shim/engine/graphics.h"
|
|
#include "../gpu/shim/bbport_platform.h"
|
|
#include "../gpu/shim/bbport_settings.h"
|
|
#include <array>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <vector>
|
|
#ifdef _WIN32
|
|
#include <windows.h>
|
|
#else
|
|
#include <sys/mman.h>
|
|
#include <signal.h>
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
#ifdef _WIN32
|
|
namespace BbPlatform {
|
|
bool ReadProcessMemory(const void* p, void* out, size_t n) {
|
|
if (!p) return false;
|
|
std::memcpy(out, p, n);
|
|
return true;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
namespace {
|
|
int failures = 0;
|
|
void Check(bool ok, const char* what) {
|
|
if (!ok) { std::printf("FAIL: %s\n", what); ++failures; }
|
|
}
|
|
void Stock(bool enabled) {
|
|
BbSettings::Get().graphics_local_shadow_resolution = enabled ? 0 : 2;
|
|
}
|
|
void Directional(bool enabled) {
|
|
BbSettings::Get().startup_effects[BbSettings::EffectPcss] = enabled;
|
|
}
|
|
}
|
|
|
|
#ifndef _WIN32
|
|
void WritableAgain(int, siginfo_t* info, void*) {
|
|
const auto page = reinterpret_cast<std::uintptr_t>(info->si_addr) & ~std::uintptr_t(4095);
|
|
if (mprotect(reinterpret_cast<void*>(page), 4096, PROT_READ | PROT_WRITE | PROT_EXEC)) _exit(2);
|
|
}
|
|
#endif
|
|
|
|
int main() {
|
|
#ifndef _WIN32
|
|
struct sigaction action{};
|
|
action.sa_sigaction = WritableAgain;
|
|
action.sa_flags = SA_SIGINFO;
|
|
sigaction(SIGSEGV, &action, nullptr);
|
|
#endif
|
|
std::setvbuf(stdout, nullptr, _IONBF, 0);
|
|
Stock(false);
|
|
constexpr std::size_t pool = 0x22440b0, size_at = 0x224443f, tier = 0x2244cb0;
|
|
constexpr std::uint8_t entry[] = {
|
|
0x55, 0x48, 0x89, 0xe5, 0x41, 0x57, 0x41, 0x56, 0x41, 0x55, 0x41, 0x54, 0x53,
|
|
0x48, 0x81, 0xe4, 0xe0, 0xff, 0xff, 0xff, 0x48, 0x81, 0xec, 0x20, 0x01, 0x00, 0x00};
|
|
constexpr std::uint8_t read[] = {
|
|
0x41, 0x8b, 0x44, 0x24, 0x14, 0x4d, 0x89, 0xe6, 0x4c, 0x89, 0x74, 0x24, 0x58,
|
|
0x89, 0x44, 0x24, 0x44};
|
|
constexpr std::uint8_t tiers[] = {0x41, 0xd1, 0xed, 0x48, 0xff, 0xc1, 0x48, 0x83, 0xf9, 0x04};
|
|
std::vector<std::uint8_t> image(tier + sizeof tiers, 0xcc);
|
|
std::memcpy(image.data() + pool, entry, sizeof entry);
|
|
std::memcpy(image.data() + size_at, read, sizeof read);
|
|
std::memcpy(image.data() + tier, tiers, sizeof tiers);
|
|
const auto original = image;
|
|
Stock(false);
|
|
Check(!BbEngine::Graphics::InstallLocalShadows(nullptr, image.size()), "null images are refused");
|
|
Check(!BbEngine::Graphics::InstallLocalShadows(image.data(), tier + sizeof tiers - 1),
|
|
"truncated images are refused");
|
|
Check(image == original, "a truncated image is not modified");
|
|
for (const auto at : {pool, size_at, size_at + sizeof read - 1, tier}) {
|
|
image[at] ^= 1;
|
|
const auto foreign = image;
|
|
Check(!BbEngine::Graphics::InstallLocalShadows(image.data(), image.size()),
|
|
"foreign pool, size-load and tier code are refused");
|
|
Check(image == foreign, "a refused patch changes no bytes");
|
|
image[at] ^= 1;
|
|
}
|
|
Stock(true);
|
|
Check(!BbEngine::Graphics::InstallLocalShadows(image.data(), image.size()), "stock opt-out is honored");
|
|
Check(image == original, "stock mode leaves the whole image unchanged");
|
|
Stock(false);
|
|
Check(BbEngine::Graphics::InstallLocalShadows(image.data(), image.size()), "1.09 pool code is accepted");
|
|
Check(image[size_at] == 0xb8, "the native point base load becomes mov eax,imm32");
|
|
std::uint32_t base = 0;
|
|
std::memcpy(&base, image.data() + size_at + 1, sizeof base);
|
|
Check(base == 2048, "the point base size is 2048");
|
|
const std::array<std::uint32_t, 4> expected{2048, 1024, 512, 256};
|
|
for (unsigned i = 0; i < expected.size(); ++i)
|
|
Check((base >> i) == expected[i], "native halving generates the requested tiers");
|
|
std::memcpy(image.data() + size_at, read, 5);
|
|
Check(image == original, "only the five-byte point-size load changed; counts and other pools stay native");
|
|
|
|
constexpr std::size_t spot_size = 0x22440ed, spot_tier = 0x224442a;
|
|
constexpr std::uint8_t spot_read[] = {
|
|
0x41, 0x8b, 0x04, 0x24, 0x89, 0x44, 0x24, 0x68, 0x48, 0x8d, 0x4b, 0x10,
|
|
0x48, 0x89, 0x4c, 0x24, 0x50, 0x49, 0x89, 0xdd, 0x45, 0x31, 0xff, 0x89, 0x44, 0x24, 0x60};
|
|
constexpr std::uint8_t spot_tiers[] = {
|
|
0xd1, 0x6c, 0x24, 0x68, 0xd1, 0x6c, 0x24, 0x60, 0x49, 0xff, 0xc7, 0x49, 0x83, 0xff, 0x04};
|
|
std::memcpy(image.data() + spot_size, spot_read, sizeof spot_read);
|
|
std::memcpy(image.data() + spot_tier, spot_tiers, sizeof spot_tiers);
|
|
const auto spot_original = image;
|
|
Stock(false);
|
|
Check(!BbEngine::Graphics::InstallSpotShadows(nullptr, image.size()), "null spotlight images are refused");
|
|
Check(!BbEngine::Graphics::InstallSpotShadows(image.data(), spot_tier + sizeof spot_tiers - 1),
|
|
"truncated spotlight images are refused");
|
|
Check(image == spot_original, "a truncated spotlight image is not modified");
|
|
for (const auto at : {pool, spot_size, spot_size + sizeof spot_read - 1, spot_tier}) {
|
|
image[at] ^= 1;
|
|
const auto foreign = image;
|
|
Check(!BbEngine::Graphics::InstallSpotShadows(image.data(), image.size()),
|
|
"foreign spotlight initialization and tier code are refused");
|
|
Check(image == foreign, "a refused spotlight patch changes no bytes");
|
|
image[at] ^= 1;
|
|
}
|
|
Stock(true);
|
|
Check(!BbEngine::Graphics::InstallSpotShadows(image.data(), image.size()), "spotlight opt-out is honored");
|
|
Check(image == spot_original, "stock spotlight mode leaves the whole image unchanged");
|
|
Stock(false);
|
|
Check(BbEngine::Graphics::InstallSpotShadows(image.data(), image.size()), "spotlight upgrade installs");
|
|
constexpr std::uint8_t spot_resolution[] = {0x31, 0xc0, 0xb4, 0x10};
|
|
Check(!std::memcmp(image.data() + spot_size, spot_resolution, sizeof spot_resolution),
|
|
"the spotlight base load sets EAX to 4096");
|
|
#ifdef _WIN32
|
|
auto* code = static_cast<std::uint8_t*>(
|
|
VirtualAlloc(nullptr, 4096, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE));
|
|
#else
|
|
void* memory = mmap(nullptr, 4096, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
|
auto* code = memory == MAP_FAILED ? nullptr : static_cast<std::uint8_t*>(memory);
|
|
#endif
|
|
Check(code != nullptr, "executable memory for spotlight instruction regression");
|
|
if (code) {
|
|
constexpr std::uint8_t incoming[] = {0x48, 0xc7, 0xc0, 0xff, 0xff, 0xff, 0xff};
|
|
std::memcpy(code, incoming, sizeof incoming);
|
|
std::memcpy(code + sizeof incoming, image.data() + spot_size, sizeof spot_resolution);
|
|
code[sizeof incoming + sizeof spot_resolution] = 0xc3;
|
|
using Size = std::uint64_t (__attribute__((sysv_abi)) *)();
|
|
const auto spot_base = reinterpret_cast<Size>(code)();
|
|
constexpr std::array<std::uint32_t, 4> spot_expected{4096, 2048, 1024, 512};
|
|
for (unsigned i = 0; i < spot_expected.size(); ++i)
|
|
Check((spot_base >> i) == spot_expected[i], "executed spotlight base generates all four tiers");
|
|
#ifdef _WIN32
|
|
VirtualFree(code, 0, MEM_RELEASE);
|
|
#else
|
|
munmap(code, 4096);
|
|
#endif
|
|
}
|
|
std::memcpy(image.data() + spot_size, spot_read, sizeof spot_resolution);
|
|
Check(image == spot_original, "only the four-byte spotlight load changed");
|
|
Check(BbEngine::Graphics::InstallLocalShadows(image.data(), image.size()) &&
|
|
BbEngine::Graphics::InstallSpotShadows(image.data(), image.size()),
|
|
"point and spotlight upgrades install together");
|
|
|
|
constexpr std::size_t point_radius = 0x4929c80, spot_radius = 0x4929c84;
|
|
constexpr std::size_t point_load = 0x22b7011, spot_load = 0x22b7220, spot_fallback = 0x22b7298;
|
|
constexpr std::uint8_t point_code[] = {0xc5, 0xfa, 0x10, 0x05, 0x67, 0x2c, 0x67, 0x02};
|
|
constexpr std::uint8_t spot_code[] = {0xc5, 0xfa, 0x10, 0x05, 0x5c, 0x2a, 0x67, 0x02};
|
|
constexpr std::uint8_t fallback_code[] = {0xc5, 0xfa, 0x10, 0x05, 0xe4, 0x29, 0x67, 0x02};
|
|
image.resize(spot_radius + sizeof(float), 0xcc);
|
|
std::memcpy(image.data() + point_load, point_code, sizeof point_code);
|
|
std::memcpy(image.data() + spot_load, spot_code, sizeof spot_code);
|
|
std::memcpy(image.data() + spot_fallback, fallback_code, sizeof fallback_code);
|
|
const auto reset_radii = [&] {
|
|
const float radius = 3.2f;
|
|
std::memcpy(image.data() + point_radius, &radius, sizeof radius);
|
|
std::memcpy(image.data() + spot_radius, &radius, sizeof radius);
|
|
};
|
|
const auto radius_at = [&](std::size_t at) {
|
|
float radius = 0;
|
|
std::memcpy(&radius, image.data() + at, sizeof radius);
|
|
return radius;
|
|
};
|
|
reset_radii();
|
|
Check(BbEngine::Graphics::InstallLocalShadowSoftness(image.data(), image.size(), false, false) &&
|
|
radius_at(point_radius) == 3.2f && radius_at(spot_radius) == 3.2f,
|
|
"stock allocation keeps stock softness for both light types");
|
|
Check(!BbEngine::Graphics::InstallLocalShadowSoftness(nullptr, image.size(), true, true),
|
|
"null filter images are refused");
|
|
Check(!BbEngine::Graphics::InstallLocalShadowSoftness(image.data(), image.size() - 1, true, true) &&
|
|
radius_at(point_radius) == 3.2f, "a truncated spotlight radius changes neither filter");
|
|
for (const auto at : {point_load, spot_load, spot_fallback, point_radius, spot_radius}) {
|
|
image[at] ^= 1;
|
|
const auto altered = image[at];
|
|
Check(!BbEngine::Graphics::InstallLocalShadowSoftness(image.data(), image.size(), true, true),
|
|
"foreign radius constants and all three load sites are refused");
|
|
Check(image[at] == altered, "filter refusal preserves foreign bytes");
|
|
image[at] ^= 1;
|
|
Check(radius_at(point_radius) == 3.2f && radius_at(spot_radius) == 3.2f,
|
|
"filter guard failure leaves both radii unchanged");
|
|
}
|
|
Check(BbEngine::Graphics::InstallLocalShadowSoftness(image.data(), image.size(), true, false) &&
|
|
radius_at(point_radius) == 6.4f && radius_at(spot_radius) == 3.2f,
|
|
"point-only resolution upgrade compensates only point softness");
|
|
reset_radii();
|
|
Check(BbEngine::Graphics::InstallLocalShadowSoftness(image.data(), image.size(), false, true) &&
|
|
radius_at(point_radius) == 3.2f && radius_at(spot_radius) == 6.4f,
|
|
"spotlight-only resolution upgrade compensates only spotlight softness");
|
|
reset_radii();
|
|
Check(BbEngine::Graphics::InstallLocalShadowSoftness(image.data(), image.size(), true, true),
|
|
"both upgraded light types accept softness compensation");
|
|
for (unsigned tier_index = 0; tier_index < 4; ++tier_index) {
|
|
Check(radius_at(point_radius) / float(2048u >> tier_index) == 0.25f * 3.2f / float(256u >> tier_index),
|
|
"point filter UV footprint is one quarter of stock at every tier");
|
|
Check(radius_at(spot_radius) / float(4096u >> tier_index) == 0.25f * 3.2f / float(512u >> tier_index),
|
|
"spotlight filter UV footprint is one quarter of stock at every tier");
|
|
}
|
|
constexpr std::size_t range = 0xeac540, tail = 0xeac657;
|
|
|
|
std::memcpy(image.data() + size_at, read, 5);
|
|
std::memcpy(image.data() + spot_size, spot_read, 4);
|
|
reset_radii();
|
|
const auto local_original = image;
|
|
for (int quality = 0; quality < 3; ++quality) {
|
|
BbSettings::Get().graphics_local_shadow_resolution = quality;
|
|
const bool point = BbEngine::Graphics::InstallLocalShadows(image.data(), image.size());
|
|
const bool spot = BbEngine::Graphics::InstallSpotShadows(image.data(), image.size());
|
|
Check(point == (quality != 0) && spot == (quality != 0),
|
|
"local dropdown enables both upgrades only for High and Very high");
|
|
Check(BbEngine::Graphics::InstallLocalShadowSoftness(image.data(), image.size(), point, spot),
|
|
"selected local quality accepts matching softness");
|
|
if (quality == 0) {
|
|
Check(image == local_original, "Default keeps native allocation instructions and filters byte-for-byte");
|
|
} else {
|
|
const unsigned point_base = quality == 1 ? 1024 : 2048;
|
|
const unsigned spot_base = point_base * 2;
|
|
std::uint32_t immediate = 0;
|
|
std::memcpy(&immediate, image.data() + size_at + 1, 4);
|
|
Check(immediate == point_base && image[size_at] == 0xb8, "selected point base immediate");
|
|
Check(image[spot_size] == 0x31 && image[spot_size + 1] == 0xc0 &&
|
|
image[spot_size + 2] == 0xb4 &&
|
|
unsigned(image[spot_size + 3]) * 256 == spot_base, "selected spotlight base instruction");
|
|
for (unsigned i = 0; i < 4; ++i) {
|
|
Check(radius_at(point_radius) / float(point_base >> i) == 0.25f * 3.2f / float(256u >> i),
|
|
"selected point tiers preserve quarter-stock normalized softness");
|
|
Check(radius_at(spot_radius) / float(spot_base >> i) == 0.25f * 3.2f / float(512u >> i),
|
|
"selected spotlight tiers preserve quarter-stock normalized softness");
|
|
}
|
|
}
|
|
std::memcpy(image.data() + size_at, read, 5);
|
|
std::memcpy(image.data() + spot_size, spot_read, 4);
|
|
reset_radii();
|
|
Check(image == local_original, "local dropdown changes only sizes and successful light-type radii");
|
|
}
|
|
BbSettings::Get().graphics_local_shadow_resolution = 2;
|
|
constexpr std::uint8_t range_entry[] = {
|
|
0xc5, 0xf8, 0x28, 0x02, 0xc5, 0xf8, 0x29, 0x06, 0xc5, 0xf8, 0x28, 0x42, 0x10,
|
|
0xc5, 0xf8, 0x29, 0x46, 0x10};
|
|
constexpr std::uint8_t range_stores[] = {
|
|
0xc5, 0xfa, 0x11, 0x46, 0x54, 0xc5, 0xf2, 0x5d, 0x42, 0x58, 0xc5, 0xfa, 0x11, 0x46, 0x58, 0xc3};
|
|
std::memcpy(image.data() + range, range_entry, sizeof range_entry);
|
|
std::memcpy(image.data() + tail, range_stores, sizeof range_stores);
|
|
Check(BbEngine::Graphics::DirectionalShadowBlend() == 0, "blending is off before native overlap");
|
|
Directional(true);
|
|
Check(!BbEngine::Graphics::InstallDirectionalShadows(nullptr, image.size()), "null cascade image refused");
|
|
Check(!BbEngine::Graphics::InstallDirectionalShadows(image.data(), tail + 14),
|
|
"truncated cascade stores refused");
|
|
for (const auto at : {range, tail, tail + 14}) {
|
|
image[at] ^= 1;
|
|
Check(!BbEngine::Graphics::InstallDirectionalShadows(image.data(), image.size()) &&
|
|
BbEngine::Graphics::DirectionalShadowBlend() == 0, "foreign cascade code cannot enable blending");
|
|
image[at] ^= 1;
|
|
}
|
|
Directional(false);
|
|
Check(!BbEngine::Graphics::InstallDirectionalShadows(image.data(), image.size()),
|
|
"overlap stays off unless an effect asks for it");
|
|
Directional(true);
|
|
Check(BbEngine::Graphics::InstallDirectionalShadows(image.data(), image.size()) &&
|
|
BbEngine::Graphics::DirectionalShadowBlend() == 0.1f, "guarded overlap enables matching blend band");
|
|
auto* tail_page = reinterpret_cast<void*>(
|
|
reinterpret_cast<std::uintptr_t>(image.data() + tail) & ~std::uintptr_t(4095));
|
|
#ifdef _WIN32
|
|
DWORD old_protection = 0;
|
|
const bool executable = VirtualProtect(tail_page, 4096, PAGE_EXECUTE_READWRITE, &old_protection) != 0;
|
|
#else
|
|
const bool executable = mprotect(tail_page, 4096, PROT_READ | PROT_WRITE | PROT_EXEC) == 0;
|
|
#endif
|
|
Check(executable, "cascade tail test is executable");
|
|
if (executable) {
|
|
alignas(16) std::array<std::uint8_t, 0x700> owner{};
|
|
alignas(16) std::array<float, 36> camera{}, output{};
|
|
const float split0 = 20, split1 = 40;
|
|
std::memcpy(owner.data() + 0x6dc, &split0, 4);
|
|
std::memcpy(owner.data() + 0x6e0, &split1, 4);
|
|
camera[0x54 / 4] = 0.05f;
|
|
camera[0x58 / 4] = 600;
|
|
using Tail = void (__attribute__((sysv_abi)) *)(void*, void*, void*, void*, unsigned, float, float);
|
|
const auto run = reinterpret_cast<Tail>(image.data() + tail);
|
|
const std::array<float, 4> starts{0.05f, 20, 40, 150};
|
|
const std::array<float, 4> expected_near{0.05f, 18, 38, 139};
|
|
for (unsigned c = 0; c < 4; ++c) {
|
|
run(owner.data(), output.data(), camera.data(), nullptr, c, starts[c], 800);
|
|
Check(output[0x54 / 4] == expected_near[c], "executed hook expands exactly the shader blend interval");
|
|
Check(output[0x58 / 4] == 600, "native far-camera clamp is preserved");
|
|
}
|
|
camera[0x54 / 4] = 19;
|
|
run(owner.data(), output.data(), camera.data(), nullptr, 1, 20, 40);
|
|
Check(output[0x54 / 4] == 19, "overlap cannot extend behind camera near plane");
|
|
#ifdef _WIN32
|
|
DWORD ignored = 0;
|
|
VirtualProtect(tail_page, 4096, old_protection, &ignored);
|
|
#else
|
|
mprotect(tail_page, 4096, PROT_READ | PROT_WRITE);
|
|
#endif
|
|
}
|
|
constexpr std::size_t table = 0x48a9668, selection = 0xeac238;
|
|
constexpr std::uint32_t native_sizes[] = {2048, 1024, 2048, 4096};
|
|
constexpr std::uint8_t select_code[] = {
|
|
0xb8, 0x00, 0x08, 0x00, 0x00, 0x48, 0x83, 0xf9, 0x03, 0x77, 0x0a,
|
|
0x48, 0x8d, 0x05, 0x1e, 0xd4, 0x9f, 0x03, 0x8b, 0x04, 0x88};
|
|
const auto reset_atlas = [&] {
|
|
std::memcpy(image.data() + table, native_sizes, sizeof native_sizes);
|
|
std::memcpy(image.data() + selection, select_code, sizeof select_code);
|
|
};
|
|
reset_atlas();
|
|
Check(!BbEngine::Graphics::InstallDirectionalShadowResolution(nullptr, image.size()),
|
|
"null atlas allocation image refused");
|
|
Check(!BbEngine::Graphics::InstallDirectionalShadowResolution(image.data(), table + sizeof native_sizes - 1),
|
|
"truncated atlas table refused");
|
|
for (const auto at : {table, table + sizeof native_sizes - 1, selection, selection + sizeof select_code - 1}) {
|
|
image[at] ^= 1;
|
|
const auto before = image;
|
|
Check(!BbEngine::Graphics::InstallDirectionalShadowResolution(image.data(), image.size()) &&
|
|
image == before, "foreign atlas table and selection code refused without writes");
|
|
image[at] ^= 1;
|
|
}
|
|
const auto atlas_original = image;
|
|
alignas(4096) std::array<std::uint8_t, 4096> selection_test{};
|
|
#ifdef _WIN32
|
|
DWORD selection_protection = 0;
|
|
const bool selection_executable = VirtualProtect(selection_test.data(), selection_test.size(),
|
|
PAGE_EXECUTE_READWRITE, &selection_protection) != 0;
|
|
#else
|
|
const bool selection_executable = mprotect(selection_test.data(), selection_test.size(),
|
|
PROT_READ | PROT_WRITE | PROT_EXEC) == 0;
|
|
#endif
|
|
Check(selection_executable, "atlas selection test is executable");
|
|
reset_atlas();
|
|
BbSettings::Get().graphics_shadow_resolution = 0;
|
|
Check(!BbEngine::Graphics::InstallDirectionalShadowResolution(image.data(), image.size()) &&
|
|
image == atlas_original, "the game's own atlas changes no bytes");
|
|
for (int quality = 1; quality < 3; ++quality) {
|
|
reset_atlas();
|
|
BbSettings::Get().graphics_shadow_resolution = quality;
|
|
Check(BbEngine::Graphics::InstallDirectionalShadowResolution(image.data(), image.size()),
|
|
"atlas quality accepted");
|
|
const std::uint32_t expected_atlas = 2048u << quality;
|
|
std::array<std::uint32_t, 4> actual{};
|
|
std::memcpy(actual.data(), image.data() + table, sizeof actual);
|
|
for (auto dimension : actual) Check(dimension == expected_atlas, "all map quality entries use requested atlas");
|
|
std::uint32_t fallback = 0;
|
|
std::memcpy(&fallback, image.data() + selection + 1, sizeof fallback);
|
|
Check(fallback == expected_atlas, "out-of-range native selector uses requested atlas too");
|
|
if (selection_executable) {
|
|
std::memcpy(selection_test.data(), image.data() + selection, sizeof select_code);
|
|
selection_test[sizeof select_code] = 0xc3;
|
|
std::memcpy(selection_test.data() + 256, actual.data(), sizeof actual);
|
|
|
|
const std::int32_t displacement = 256 - 18;
|
|
std::memcpy(selection_test.data() + 14, &displacement, sizeof displacement);
|
|
using Select = unsigned (__attribute__((sysv_abi)) *)(void*, void*, void*, std::int64_t);
|
|
const auto select = reinterpret_cast<Select>(selection_test.data());
|
|
for (std::int64_t profile : {-1, 0, 1, 2, 3, 4})
|
|
Check(select(nullptr, nullptr, nullptr, profile) == expected_atlas,
|
|
"executed native selection handles every map profile and fallback");
|
|
}
|
|
reset_atlas();
|
|
Check(image == atlas_original, "atlas upgrade changes only resolution table and fallback immediate");
|
|
}
|
|
#ifdef _WIN32
|
|
DWORD selection_ignored = 0;
|
|
if (selection_executable)
|
|
VirtualProtect(selection_test.data(), selection_test.size(), selection_protection, &selection_ignored);
|
|
#else
|
|
if (selection_executable)
|
|
mprotect(selection_test.data(), selection_test.size(), PROT_READ | PROT_WRITE);
|
|
#endif
|
|
if (failures) return 1;
|
|
std::puts("Native local shadows: PASS (point and spotlight code guards, independent opt-outs, "
|
|
"1024/2048 bases, four tiers, instruction execution, isolated writes, combined install, "
|
|
"guarded per-type softness and quarter-stock filter footprints, "
|
|
"directional cascade overlap and 2048/4096/8192 atlas selection)");
|
|
return 0;
|
|
}
|