Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/mods/VR.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1160,6 +1160,9 @@ void VR::on_draw_ui() {
m_openxr->resolution_scale = m_resolution_scale->value();
}
m_use_async_aer->draw("Use Async AER");
if (ImGui::IsItemDeactivatedAfterEdit()) {
get_runtime()->async_aer = m_use_async_aer->value();
}

m_flat_screen_distance->draw("Flat Screen Distance");
if (ImGui::IsItemDeactivatedAfterEdit())
Expand Down Expand Up @@ -1306,6 +1309,7 @@ void VR::on_config_load(const utility::Config& cfg, bool set_defaults) {
get_runtime()->m_vertical_fov_scale = m_vertical_fov_scale->value();
get_runtime()->m_extended_fov_range = m_extended_fov_rage->value();
get_runtime()->m_flat_screen_distance = m_flat_screen_distance->value();
get_runtime()->async_aer = m_use_async_aer->value();
}
m_overlay_component.on_config_load(cfg, set_defaults);

Expand Down
2 changes: 1 addition & 1 deletion src/mods/VR.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ class VR : public Mod {
// int32_t get_game_frame_count() const;

bool is_using_async_aer() const {
return m_runtime->is_openxr() && m_use_async_aer->value();
return m_runtime->async_aer;
}

bool is_gui_enabled() const {
Expand Down
62 changes: 55 additions & 7 deletions src/mods/vr/D3D11Component.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -302,21 +302,46 @@ vr::EVRCompositorError D3D11Component::on_frame(VR* vr) {
}

if (runtime->is_openvr()) {
// Calculate which frame each eye was actually rendered at (matching OpenXR's AFR logic)
auto l_frame = vr->m_presenter_frame_count % 2 == vr->m_left_eye_interval
? vr->m_presenter_frame_count
: vr->m_presenter_frame_count - 1;
auto r_frame = vr->m_presenter_frame_count % 2 == vr->m_left_eye_interval
? vr->m_presenter_frame_count - 1
: vr->m_presenter_frame_count;

// Submit newly rendered left eye with its pose
vr::VRTextureWithPose_t left_eye{};
left_eye.handle = (void*)m_left_eye_tex.Get();
left_eye.eType = vr::TextureType_DirectX;
left_eye.eColorSpace = vr::ColorSpace_Auto;
left_eye.mDeviceToAbsoluteTracking = GlobalPool::get_openvr_pose(vr->m_presenter_frame_count);
left_eye.mDeviceToAbsoluteTracking = GlobalPool::get_openvr_pose(l_frame);

auto e = vr::VRCompositor()->Submit(vr::Eye_Left, (vr::Texture_t*)&left_eye, &vr->m_left_bounds, vr::Submit_TextureWithPose);

bool submitted = true;

if (e != vr::VRCompositorError_None) {
spdlog::error("[VR] VRCompositor failed to submit left eye: {}", (int)e);
vr->m_submitted = false;
return e;
}

// Resubmit previous right eye frame with its original pose for runtime reprojection
// Skip on first frame when there's no previous frame to resubmit
if (vr->m_presenter_frame_count > 0) {
vr::VRTextureWithPose_t right_eye{};
right_eye.handle = (void*)m_right_eye_tex.Get();
right_eye.eType = vr::TextureType_DirectX;
right_eye.eColorSpace = vr::ColorSpace_Auto;
right_eye.mDeviceToAbsoluteTracking = GlobalPool::get_openvr_pose(r_frame);

e = vr::VRCompositor()->Submit(vr::Eye_Right, (vr::Texture_t*)&right_eye, &vr->m_right_bounds, vr::Submit_TextureWithPose);

if (e != vr::VRCompositorError_None) {
spdlog::error("[VR] VRCompositor failed to submit right eye (resubmit): {}", (int)e);
}
}

vr->m_submitted = true;
}
} else {
auto copy_from_tex = backbufferIs8Bit ? backbuffer : m_right_eye_rt.tex;
Expand Down Expand Up @@ -394,23 +419,46 @@ vr::EVRCompositorError D3D11Component::on_frame(VR* vr) {
if (backbufferIs8Bit) {
context->CopyResource(m_right_eye_tex.Get(), backbuffer.Get());
}


// Calculate which frame each eye was actually rendered at (matching OpenXR's AFR logic)
auto l_frame = vr->m_presenter_frame_count % 2 == vr->m_left_eye_interval
? vr->m_presenter_frame_count
: vr->m_presenter_frame_count - 1;
auto r_frame = vr->m_presenter_frame_count % 2 == vr->m_left_eye_interval
? vr->m_presenter_frame_count - 1
: vr->m_presenter_frame_count;

// Submit newly rendered right eye with its pose
vr::VRTextureWithPose_t right_eye{};
right_eye.handle = (void*)m_right_eye_tex.Get();
right_eye.eType = vr::TextureType_DirectX;
right_eye.eColorSpace = vr::ColorSpace_Auto;
right_eye.mDeviceToAbsoluteTracking = GlobalPool::get_openvr_pose(vr->m_presenter_frame_count);
right_eye.mDeviceToAbsoluteTracking = GlobalPool::get_openvr_pose(r_frame);

auto e = vr::VRCompositor()->Submit(vr::Eye_Right, (vr::Texture_t*)&right_eye, &vr->m_right_bounds, vr::Submit_TextureWithPose);

bool submitted = true;

if (e != vr::VRCompositorError_None) {
spdlog::error("[VR] VRCompositor failed to submit right eye: {}", (int)e);
vr->m_submitted = false;
return e;
}

// Resubmit previous left eye frame with its original pose for runtime reprojection
// Skip on first frame when there's no previous frame to resubmit
if (vr->m_presenter_frame_count > 0) {
vr::VRTextureWithPose_t left_eye{};
left_eye.handle = (void*)m_left_eye_tex.Get();
left_eye.eType = vr::TextureType_DirectX;
left_eye.eColorSpace = vr::ColorSpace_Auto;
left_eye.mDeviceToAbsoluteTracking = GlobalPool::get_openvr_pose(l_frame);

e = vr::VRCompositor()->Submit(vr::Eye_Left, (vr::Texture_t*)&left_eye, &vr->m_left_bounds, vr::Submit_TextureWithPose);

if (e != vr::VRCompositorError_None) {
spdlog::error("[VR] VRCompositor failed to submit left eye (resubmit): {}", (int)e);
}
}

vr->m_submitted = true;
}

Expand Down
75 changes: 71 additions & 4 deletions src/mods/vr/D3D12Component.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,17 +97,26 @@ vr::EVRCompositorError D3D12Component::on_frame(VR* vr) {
if (runtime->is_openvr()) {
m_openvr.copy_left(eye_texture.Get());

// Calculate which frame each eye was actually rendered at (matching OpenXR's AFR logic)
auto l_frame = vr->m_presenter_frame_count % 2 == vr->m_left_eye_interval
? vr->m_presenter_frame_count
: vr->m_presenter_frame_count - 1;
auto r_frame = vr->m_presenter_frame_count % 2 == vr->m_left_eye_interval
? vr->m_presenter_frame_count - 1
: vr->m_presenter_frame_count;

vr::D3D12TextureData_t left_tex {
m_openvr.get_left().texture.Get(),
command_queue,
0
};

// Submit newly rendered left eye with its pose
vr::VRTextureWithPose_t left_eye{};
left_eye.handle = (void*)&left_tex;
left_eye.eType = vr::TextureType_DirectX12;
left_eye.eColorSpace = vr::ColorSpace_Auto;
left_eye.mDeviceToAbsoluteTracking = GlobalPool::get_openvr_pose(vr->m_presenter_frame_count);
left_eye.mDeviceToAbsoluteTracking = GlobalPool::get_openvr_pose(l_frame);

const auto left_bounds = vr::VRTextureBounds_t{runtime->view_bounds[0][0], runtime->view_bounds[0][2],
runtime->view_bounds[0][1], runtime->view_bounds[0][3]};
Expand All @@ -117,6 +126,32 @@ vr::EVRCompositorError D3D12Component::on_frame(VR* vr) {
spdlog::error("[VR] VRCompositor failed to submit left eye: {}", (int)e);
return e;
}

// Resubmit previous right eye frame with its original pose for runtime reprojection
// Skip on first frame when there's no previous frame to resubmit
if (vr->m_presenter_frame_count > 0) {
vr::D3D12TextureData_t right_tex {
m_openvr.get_right().texture.Get(),
command_queue,
0
};

vr::VRTextureWithPose_t right_eye{};
right_eye.handle = (void*)&right_tex;
right_eye.eType = vr::TextureType_DirectX12;
right_eye.eColorSpace = vr::ColorSpace_Auto;
right_eye.mDeviceToAbsoluteTracking = GlobalPool::get_openvr_pose(r_frame);

const auto right_bounds = vr::VRTextureBounds_t{runtime->view_bounds[1][0], runtime->view_bounds[1][2],
runtime->view_bounds[1][1], runtime->view_bounds[1][3]};
e = vr::VRCompositor()->Submit(vr::Eye_Right, (vr::Texture_t*)&right_eye, &right_bounds, vr::Submit_TextureWithPose);

if (e != vr::VRCompositorError_None) {
spdlog::error("[VR] VRCompositor failed to submit right eye (resubmit): {}", (int)e);
}
}

vr->m_submitted = true;
}
} else {
// OpenXR texture
Expand All @@ -140,17 +175,26 @@ vr::EVRCompositorError D3D12Component::on_frame(VR* vr) {
if (runtime->is_openvr()) {
m_openvr.copy_right(eye_texture.Get());

// Calculate which frame each eye was actually rendered at (matching OpenXR's AFR logic)
auto l_frame = vr->m_presenter_frame_count % 2 == vr->m_left_eye_interval
? vr->m_presenter_frame_count
: vr->m_presenter_frame_count - 1;
auto r_frame = vr->m_presenter_frame_count % 2 == vr->m_left_eye_interval
? vr->m_presenter_frame_count - 1
: vr->m_presenter_frame_count;

vr::D3D12TextureData_t right_tex {
m_openvr.get_right().texture.Get(),
command_queue,
0
};

// Submit newly rendered right eye with its pose
vr::VRTextureWithPose_t right_eye{};
right_eye.handle = (void*)&right_tex;
right_eye.eType = vr::TextureType_DirectX12;
right_eye.eColorSpace = vr::ColorSpace_Auto;
right_eye.mDeviceToAbsoluteTracking = GlobalPool::get_openvr_pose(vr->m_presenter_frame_count);
right_eye.mDeviceToAbsoluteTracking = GlobalPool::get_openvr_pose(r_frame);

const auto right_bounds = vr::VRTextureBounds_t{runtime->view_bounds[1][0], runtime->view_bounds[1][2],
runtime->view_bounds[1][1], runtime->view_bounds[1][3]};
Expand All @@ -159,10 +203,33 @@ vr::EVRCompositorError D3D12Component::on_frame(VR* vr) {
if (e != vr::VRCompositorError_None) {
spdlog::error("[VR] VRCompositor failed to submit right eye: {}", (int)e);
return e;
} else {
vr->m_submitted = true;
}

// Resubmit previous left eye frame with its original pose for runtime reprojection
// Skip on first frame when there's no previous frame to resubmit
if (vr->m_presenter_frame_count > 0) {
vr::D3D12TextureData_t left_tex {
m_openvr.get_left().texture.Get(),
command_queue,
0
};

vr::VRTextureWithPose_t left_eye{};
left_eye.handle = (void*)&left_tex;
left_eye.eType = vr::TextureType_DirectX12;
left_eye.eColorSpace = vr::ColorSpace_Auto;
left_eye.mDeviceToAbsoluteTracking = GlobalPool::get_openvr_pose(l_frame);

const auto left_bounds = vr::VRTextureBounds_t{runtime->view_bounds[0][0], runtime->view_bounds[0][2],
runtime->view_bounds[0][1], runtime->view_bounds[0][3]};
e = vr::VRCompositor()->Submit(vr::Eye_Left, (vr::Texture_t*)&left_eye, &left_bounds, vr::Submit_TextureWithPose);

if (e != vr::VRCompositorError_None) {
spdlog::error("[VR] VRCompositor failed to submit left eye (resubmit): {}", (int)e);
}
}

vr->m_submitted = true;
++m_openvr.texture_counter;
}
}
Expand Down
1 change: 0 additions & 1 deletion src/mods/vr/runtimes/OpenXR.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,6 @@ struct OpenXR final : public VRRuntime {
bool session_ready{false};
bool frame_began{false};
bool frame_synced{false};
bool async_aer{true};
#ifdef DEBUG_PROFILING_ENABLED
bool profile_calls{true};
#else
Expand Down
1 change: 1 addition & 0 deletions src/mods/vr/runtimes/VRRuntime.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ struct VRRuntime {
bool got_first_sync{false};
bool handle_pause{false};
bool wants_reset_origin{true};
bool async_aer{true}; // Alternate Frame Rendering - submit both eyes each present with historical poses

std::optional<std::string> error{};

Expand Down