mirror of
https://github.com/mitch030504/Wiicompiled_VR_Frame.git
synced 2026-10-06 09:00:28 +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
@@ -356,6 +356,14 @@ target_include_directories(mkw_vr_player_tests PRIVATE "${CMAKE_CURRENT_LIST_DIR
|
||||
target_compile_features(mkw_vr_player_tests PRIVATE cxx_std_17)
|
||||
add_test(NAME mkw_vr_player_tests COMMAND mkw_vr_player_tests)
|
||||
|
||||
add_executable(mkw_vr_policy_tests tests/vr_policy_tests.cpp src/vr/mkw_vr_policy.cpp)
|
||||
target_include_directories(mkw_vr_policy_tests PRIVATE "${CMAKE_CURRENT_LIST_DIR}/include")
|
||||
target_compile_features(mkw_vr_policy_tests PRIVATE cxx_std_17)
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
|
||||
target_compile_options(mkw_vr_policy_tests PRIVATE -ffast-math)
|
||||
endif()
|
||||
add_test(NAME mkw_vr_policy_tests COMMAND mkw_vr_policy_tests)
|
||||
|
||||
if(MKW_ENABLE_OPENXR AND MKW_PLATFORM_WINDOWS)
|
||||
add_executable(mkw_openxr_replay_tests
|
||||
tests/openxr_d3d12_replay_tests.cpp src/vr/openxr_d3d12.cpp)
|
||||
|
||||
@@ -147,8 +147,9 @@ extern "C" void GX__CopyTex_8016fd74(uint32_t da, uint32_t c) {
|
||||
// EFB exactly once, matching Dolphin's ConvertEFBRectangle path.
|
||||
GXSetTexCopySrc(rawSrcLeft, rawSrcTop, rawSrcWidth, rawSrcHeight);
|
||||
// EFB copies stay GPU-only except probe-sized ones (e.g. the 4x4 lens-flare depth probe),
|
||||
// which Aurora reads back asynchronously via efb_ram::schedule and land in guest RAM a frame
|
||||
// later. RISK: copies above the probe threshold, or on the offscreen list, are not
|
||||
// which Aurora reads back asynchronously and publishes during the next copy to that buffer.
|
||||
// GPU callbacks retain pixels in host memory so a scene restart cannot receive a late write
|
||||
// into a freed/reused allocation. RISK: copies above the probe threshold, or on the offscreen list, are not
|
||||
// auto-downloaded, so guest reads see stale RAM; call aurora_flush_efb_copies_to_ram if a
|
||||
// copy needs reading back.
|
||||
GXCopyTex(GuestToHostPtr(da), (GXBool)c);
|
||||
|
||||
@@ -615,8 +615,11 @@ void VI_HLE_PresentFrame(bool presentedXfb, bool paceToRetrace) {
|
||||
// asynchronous worker may ask for an XR packet after the guest has already
|
||||
// begun the next frame, so immersive replay is accepted only when both
|
||||
// tags match.
|
||||
const uint64_t vrContentTag = mkw::vr::MkwVRPolicyGetSnapshot().content_tag;
|
||||
aurora_end_frame_tagged(vrContentTag);
|
||||
const auto vrPolicy = mkw::vr::MkwVRPolicyGetSnapshot();
|
||||
aurora_set_stereo_local_player_count(
|
||||
vrPolicy.presentation == mkw::vr::VRPresentationMode::ImmersiveRace
|
||||
? vrPolicy.scene.local_player_count : 1);
|
||||
aurora_end_frame_tagged(vrPolicy.content_tag);
|
||||
if (paceThisFrame) {
|
||||
PaceToRetraceBoundary(paceDeadline);
|
||||
std::lock_guard<std::mutex> lock(g_viMutex);
|
||||
|
||||
@@ -168,7 +168,9 @@ extern "C" void MkwVRObserveTranslatedFunctionEntry(uint32_t address,
|
||||
case kRaceCameraUpdate: {
|
||||
const uint32_t camera_address = context != nullptr ? context->gpr[3] : 0;
|
||||
ObserveCamera(frame, camera_address);
|
||||
PublishObservedCamera(frame, camera_address);
|
||||
if (camera_address == FirstCamera(frame)) {
|
||||
PublishObservedCamera(frame, camera_address);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kScnMgrRaceDraw: {
|
||||
|
||||
@@ -86,12 +86,13 @@ VRPresentationMode SelectPresentation(const PolicyState& state) noexcept {
|
||||
return VRPresentationMode::Desktop;
|
||||
}
|
||||
|
||||
// A virtual screen is the fail-safe for menus, split-screen, and any
|
||||
// A virtual screen is the fail-safe for menus and any
|
||||
// incomplete instrumentation. It preserves the unmodified render path.
|
||||
if ((state.available_bindings & kMkwVRRequiredImmersiveBindings) !=
|
||||
kMkwVRRequiredImmersiveBindings ||
|
||||
!state.config.immersive_races || state.scene.mode != VRSceneMode::Race ||
|
||||
state.scene.local_player_count != 1 || !IsFiniteCamera(state.camera) ||
|
||||
(state.scene.local_player_count < 1 || state.scene.local_player_count > 4) ||
|
||||
!IsFiniteCamera(state.camera) ||
|
||||
!ObservationsAreCoherent(state.scene, state.camera)) {
|
||||
return VRPresentationMode::VirtualScreen;
|
||||
}
|
||||
@@ -111,7 +112,8 @@ VRPresentationMode SelectStablePresentation(const PolicyState& state) noexcept {
|
||||
if ((state.available_bindings & kMkwVRRequiredImmersiveBindings) !=
|
||||
kMkwVRRequiredImmersiveBindings ||
|
||||
!state.config.immersive_races || state.scene.mode != VRSceneMode::Race ||
|
||||
state.scene.local_player_count != 1 || !IsFiniteCamera(state.camera)) {
|
||||
(state.scene.local_player_count < 1 || state.scene.local_player_count > 4) ||
|
||||
!IsFiniteCamera(state.camera)) {
|
||||
return VRPresentationMode::VirtualScreen;
|
||||
}
|
||||
|
||||
@@ -211,6 +213,11 @@ void MkwVRPolicySetAvailableBindings(uint32_t bindings) noexcept {
|
||||
|
||||
void MkwVRPolicyPublishScene(const MkwVRSceneObservation& scene) noexcept {
|
||||
std::lock_guard<std::mutex> lock(g_policy_mutex);
|
||||
// A packet for a different split layout must not consume retained content,
|
||||
// even when both layouts use immersive presentation.
|
||||
if (scene.local_player_count != g_policy.scene.local_player_count) {
|
||||
AdvanceSafetyGeneration(g_policy);
|
||||
}
|
||||
ApplyPolicyMutation([&] {
|
||||
if (scene.mode != VRSceneMode::Race || g_policy.scene.mode != VRSceneMode::Race) {
|
||||
// Never carry a camera sample across a menu/replay-to-race transition.
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#include "vr/mkw_vr_policy.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
using namespace mkw::vr;
|
||||
|
||||
int main() {
|
||||
int failures = 0;
|
||||
const auto check = [&](bool condition, const char* message) {
|
||||
if (!condition) {
|
||||
std::cerr << message << '\n';
|
||||
++failures;
|
||||
}
|
||||
};
|
||||
MkwVRPolicyReset();
|
||||
MkwVRPolicyConfig config{};
|
||||
config.enabled = true;
|
||||
MkwVRPolicyConfigure(config);
|
||||
MkwVRPolicySetSessionActive(true);
|
||||
MkwVRPolicySetAvailableBindings(kMkwVRRequiredImmersiveBindings);
|
||||
MkwVRSceneObservation scene{VRSceneMode::Race, 1, 10};
|
||||
MkwVRCameraObservation camera{};
|
||||
camera.view_from_world = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0};
|
||||
camera.guest_camera_address = 0x81000000;
|
||||
camera.guest_frame_index = 10;
|
||||
camera.valid = true;
|
||||
MkwVRPolicyPublishScene(scene);
|
||||
MkwVRPolicyPublishRaceCamera(camera);
|
||||
uint64_t previous_tag = 0;
|
||||
for (uint32_t players : {1u, 2u, 3u, 4u, 2u, 1u}) {
|
||||
scene.local_player_count = players;
|
||||
MkwVRPolicyPublishScene(scene);
|
||||
const auto snapshot = MkwVRPolicyGetSnapshot();
|
||||
check(snapshot.presentation == VRPresentationMode::ImmersiveRace, "1-4 players should be immersive");
|
||||
check(snapshot.content_tag != previous_tag, "layout changes must invalidate retained packets");
|
||||
previous_tag = snapshot.content_tag;
|
||||
MkwVRPolicyPublishScene(scene);
|
||||
MkwVRPolicyPublishRaceCamera(camera);
|
||||
check(MkwVRPolicyGetSnapshot().content_tag == previous_tag, "steady frames must keep the same tag");
|
||||
}
|
||||
camera.guest_frame_index = 11;
|
||||
MkwVRPolicyPublishRaceCamera(camera);
|
||||
check(MkwVRPolicyGetSnapshot().presentation == VRPresentationMode::ImmersiveRace,
|
||||
"adjacent camera publication is coherent");
|
||||
camera.guest_frame_index = 12;
|
||||
MkwVRPolicyPublishRaceCamera(camera);
|
||||
check(MkwVRPolicyGetSnapshot().presentation == VRPresentationMode::VirtualScreen, "stale camera fails safe");
|
||||
camera.guest_frame_index = 10;
|
||||
MkwVRPolicyPublishRaceCamera(camera);
|
||||
for (uint32_t players : {0u, 5u, UINT32_MAX}) {
|
||||
scene.local_player_count = players;
|
||||
MkwVRPolicyPublishScene(scene);
|
||||
check(MkwVRPolicyGetSnapshot().presentation == VRPresentationMode::VirtualScreen, "invalid counts fail safe");
|
||||
}
|
||||
scene.local_player_count = 4;
|
||||
MkwVRPolicyPublishScene(scene);
|
||||
const uint32_t nan_bits = 0x7fc00000;
|
||||
std::memcpy(&camera.view_from_world[0], &nan_bits, sizeof(nan_bits));
|
||||
MkwVRPolicyPublishRaceCamera(camera);
|
||||
check(MkwVRPolicyGetSnapshot().presentation == VRPresentationMode::VirtualScreen, "NaN camera fails under fast math");
|
||||
camera.view_from_world[0] = 1;
|
||||
MkwVRPolicyPublishRaceCamera(camera);
|
||||
MkwVRPolicySetAvailableBindings(MkwVRBindingRaceCamera);
|
||||
check(MkwVRPolicyGetSnapshot().presentation == VRPresentationMode::VirtualScreen, "partial hooks fail safe");
|
||||
MkwVRPolicySetAvailableBindings(kMkwVRRequiredImmersiveBindings);
|
||||
scene.mode = VRSceneMode::FrontEnd;
|
||||
MkwVRPolicyPublishScene(scene);
|
||||
check(MkwVRPolicyGetSnapshot().presentation == VRPresentationMode::VirtualScreen, "menus use virtual screen");
|
||||
scene.mode = VRSceneMode::Race;
|
||||
MkwVRPolicyPublishScene(scene);
|
||||
check(MkwVRPolicyGetSnapshot().presentation == VRPresentationMode::VirtualScreen, "race entry needs fresh camera");
|
||||
MkwVRPolicyPublishRaceCamera(camera);
|
||||
check(MkwVRPolicyGetSnapshot().presentation == VRPresentationMode::ImmersiveRace, "race resumes with fresh camera");
|
||||
MkwVRPolicySetSessionActive(false);
|
||||
check(MkwVRPolicyGetSnapshot().presentation == VRPresentationMode::Desktop, "inactive session uses desktop");
|
||||
return failures == 0 ? 0 : 1;
|
||||
}
|
||||
Reference in new issue
Block a user