mirror of
https://github.com/mitch030504/Wiicompiled_VR_Frame.git
synced 2026-10-06 06:00:25 +02:00
Added Support for Multiplayer Player 1 Immersive View
This commit is contained in:
1 parent
9e37bb6447
commit
3e8bdcfd7b
22 files changed
+1013
-38
No files matched your search
@@ -0,0 +1,146 @@
|
||||
// Opt-in GPU regression for a depth-probe allocation reused during a scene
|
||||
// restart. A late map callback must not overwrite the new camera allocation.
|
||||
#include <aurora/aurora.h>
|
||||
#include <dolphin/gx.h>
|
||||
#include "gfx/efb_ram_copy.hpp"
|
||||
#include "gfx/efb_ram_encoder.hpp"
|
||||
#include "webgpu/gpu.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <cstdio>
|
||||
#include <filesystem>
|
||||
#include <thread>
|
||||
|
||||
using namespace aurora;
|
||||
namespace {
|
||||
constexpr uint8_t kCameraByte = 0x35;
|
||||
std::array<uint8_t, 256> guest;
|
||||
|
||||
gfx::TextureHandle MakeTexture(uint32_t width, uint32_t height, std::array<uint8_t, 4> pixel) {
|
||||
auto texture = gfx::new_render_texture(width, height, GX_TF_RGBA8, "Probe lifetime test");
|
||||
if (texture->format == wgpu::TextureFormat::BGRA8Unorm)
|
||||
std::swap(pixel[0], pixel[2]);
|
||||
std::array<uint8_t, 256> pixels;
|
||||
for (size_t i = 0; i < width * height; ++i)
|
||||
std::copy(pixel.begin(), pixel.end(), pixels.begin() + i * 4);
|
||||
const wgpu::TexelCopyTextureInfo destination{.texture = texture->texture};
|
||||
const wgpu::TexelCopyBufferLayout layout{.bytesPerRow = width * 4, .rowsPerImage = height};
|
||||
webgpu::g_queue.WriteTexture(&destination, pixels.data(), width * height * 4, &layout, &texture->size);
|
||||
return texture;
|
||||
}
|
||||
|
||||
void SubmitProbe(const gfx::TextureHandle& texture, GXTexFmt format, uint32_t width, uint32_t height) {
|
||||
gfx::efb_ram::schedule(guest.data(), width, height, format, texture);
|
||||
gfx::efb_ram::seal_async_downloads();
|
||||
auto encoder = webgpu::g_device.CreateCommandEncoder();
|
||||
gfx::efb_ram::encode_async_downloads(encoder);
|
||||
auto commands = encoder.Finish();
|
||||
webgpu::g_queue.Submit(1, &commands);
|
||||
// The guest frees the probe and constructs a camera at the same address,
|
||||
// before the readback callback is registered.
|
||||
guest.fill(kCameraByte);
|
||||
gfx::efb_ram::after_submit();
|
||||
}
|
||||
|
||||
bool CameraIntact() {
|
||||
return std::all_of(guest.begin(), guest.end(), [](uint8_t byte) { return byte == kCameraByte; });
|
||||
}
|
||||
|
||||
bool AwaitProbe(const gfx::TextureHandle& texture, GXTexFmt format, uint32_t width, uint32_t height,
|
||||
const std::array<uint8_t, 4>& pixel) {
|
||||
const size_t size = gfx::efb_ram::encoded_size(format, width, height);
|
||||
std::array<uint8_t, 256> pixels{}, expected{};
|
||||
for (size_t i = 0; i < width * height; ++i)
|
||||
std::copy(pixel.begin(), pixel.end(), pixels.begin() + i * 4);
|
||||
if (!gfx::efb_ram::encode(expected.data(), size, format, width, height, pixels.data(), width, height, width * 4,
|
||||
gfx::efb_ram::HostPixelOrder::RGBA))
|
||||
return false;
|
||||
|
||||
const auto deadline = std::chrono::steady_clock::now() + std::chrono::seconds(5);
|
||||
do {
|
||||
// Give the real GPU completion callback a chance to run while the old
|
||||
// destination belongs to the camera, then verify it remains untouched.
|
||||
webgpu::g_instance.ProcessEvents();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
if (!CameraIntact()) {
|
||||
std::fprintf(stderr, "Late GPU readback overwrote the reused camera allocation\n");
|
||||
return false;
|
||||
}
|
||||
// This explicit copy owns the destination again and may receive the result.
|
||||
gfx::efb_ram::schedule(guest.data(), width, height, format, texture);
|
||||
const bool arrived = std::equal(expected.begin(), expected.begin() + size, guest.begin());
|
||||
const bool canary =
|
||||
std::all_of(guest.begin() + size, guest.end(), [](uint8_t byte) { return byte == kCameraByte; });
|
||||
gfx::efb_ram::cancel();
|
||||
guest.fill(kCameraByte);
|
||||
if (!canary)
|
||||
return false;
|
||||
if (arrived)
|
||||
return true;
|
||||
} while (std::chrono::steady_clock::now() < deadline);
|
||||
std::fprintf(stderr, "Completed probe was not delivered by the next compatible copy\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Run() {
|
||||
const std::array<uint8_t, 4> pixel{0xff, 0xfa, 0xb6, 0xff};
|
||||
auto large = MakeTexture(8, 8, pixel);
|
||||
auto small = MakeTexture(4, 4, pixel);
|
||||
SubmitProbe(large, GX_TF_Z24X8, 8, 8);
|
||||
if (!AwaitProbe(large, GX_TF_Z24X8, 8, 8, pixel))
|
||||
return false;
|
||||
std::puts("Reused camera allocation survives late 256-byte probe: PASS");
|
||||
|
||||
// Same address, smaller allocation and different encoding: the retained
|
||||
// 256-byte result must not escape the new 32-byte destination.
|
||||
gfx::efb_ram::schedule(guest.data(), 4, 4, GX_TF_Z16, small);
|
||||
const bool fallback = std::all_of(guest.begin(), guest.begin() + 32, [](uint8_t b) { return b == 0xff; });
|
||||
const bool canary = std::all_of(guest.begin() + 32, guest.end(), [](uint8_t b) { return b == kCameraByte; });
|
||||
gfx::efb_ram::cancel();
|
||||
if (!fallback || !canary)
|
||||
return false;
|
||||
std::puts("Reused address rejects incompatible retained format and size: PASS");
|
||||
|
||||
SubmitProbe(small, GX_TF_Z24X8, 4, 4);
|
||||
if (!AwaitProbe(small, GX_TF_Z24X8, 4, 4, pixel))
|
||||
return false;
|
||||
std::puts("Crash-dump 64-byte depth pattern delivered only during a new copy: PASS");
|
||||
SubmitProbe(small, GX_TF_Z16, 4, 4);
|
||||
if (!AwaitProbe(small, GX_TF_Z16, 4, 4, pixel))
|
||||
return false;
|
||||
std::puts("Changed probe format delivers compatible pixels without touching canaries: PASS");
|
||||
return true;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
std::setvbuf(stdout, nullptr, _IONBF, 0);
|
||||
std::filesystem::create_directories("efb-lifetime-cache");
|
||||
AuroraConfig config{};
|
||||
config.appName = "Aurora EFB lifetime validation";
|
||||
config.userPath = ".";
|
||||
config.cachePath = "efb-lifetime-cache";
|
||||
config.desiredBackend = BACKEND_D3D12;
|
||||
config.windowWidth = 160;
|
||||
config.windowHeight = 120;
|
||||
config.hasWindowPosition = true;
|
||||
config.windowPosX = config.windowPosY = -30000;
|
||||
config.xrInterop = true;
|
||||
config.logLevel = LOG_WARNING;
|
||||
config.logCallback = [](AuroraLogLevel, const char* module, const char* message, unsigned length) {
|
||||
std::fprintf(stderr, "%s: %.*s\n", module, int(length), message);
|
||||
};
|
||||
aurora_initialize(argc, argv, &config);
|
||||
std::puts("GPU initialized");
|
||||
aurora_begin_frame();
|
||||
GXInit(nullptr, 0);
|
||||
std::puts("Starting readback lifetime checks");
|
||||
const bool passed = Run();
|
||||
std::puts("Readback lifetime checks finished");
|
||||
aurora_end_frame();
|
||||
aurora_quiesce_frame_worker();
|
||||
aurora_shutdown();
|
||||
return passed ? 0 : 1;
|
||||
}
|
||||
Reference in new issue
Block a user