mirror of
https://github.com/mitch030504/Wiicompiled_VR_Frame.git
synced 2026-10-06 13:00:26 +02:00
Show the headset settings panel as its own OpenXR quad layer
The panel was drawn into the eye images, so below a 1.00x OpenXR resolution its 1440x1080 canvas was minified into a small eye region and the text became hard to read. It is now submitted as a quad layer of its own over the scene's projection or menu quad, which the compositor samples directly at any render scale. Each backend (D3D12, Windows Vulkan, Quest) makes the panel's swapchain pair (plus two shared buffers on the Quest) the first time the panel opens. While it is open, the frame hands Aurora one more stereo target after the eyes, which the bridge fills with the panel texture or a transparent image. The panel image follows the eyes' displayed/retained pairing, so a cancelled frame never shows an unwritten panel. The quad hangs where the pointer's hits are tested. Aurora leaves the panel out of the eyes in layer mode, and a backend that cannot make the layer falls back to drawing it into the eyes. On the Quest, debug.wiicompiled.panel_layer 0 selects the old path at run time. Measured there at a race start (render_scale 0.8), the layer costs nothing while the panel is closed; while it is open, app GPU time is 10.5 ms against 9.7 ms drawn into the eyes, with unchanged frame rates. The replay tests cover lazy creation, cancelled frames, closed and unplaced panels, and render-first pacing on D3D12 and Windows Vulkan. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
dd7f046214
commit
54c07c982b
22 files changed
+1223
-420
No files matched your search
@@ -40,6 +40,7 @@
|
||||
#elif defined(__ANDROID__)
|
||||
#include "vr/openxr_android.h"
|
||||
#include "vr/openxr_vulkan.h"
|
||||
#include <sys/system_properties.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#define XR_USE_TIMESPEC
|
||||
@@ -828,6 +829,12 @@ private:
|
||||
: OpenXRFrameMode::VirtualScreen;
|
||||
presentation.quad_distance_meters = policy.config.hud_distance_meters;
|
||||
presentation.quad_width_meters = policy.config.hud_width_meters;
|
||||
// The settings panel gets a compositor layer of its own while it is
|
||||
// open, and Aurora leaves it out of the eyes. A backend that could
|
||||
// not make that layer has the panel drawn into the eyes instead.
|
||||
const bool panel_layer = backend_->PanelLayerAvailable() && !PanelLayerForcedOff();
|
||||
aurora_set_stereo_panel_layer(panel_layer);
|
||||
presentation.panel.requested = panel_layer && OpenXRSettingsPanelOpen();
|
||||
|
||||
// Pipeline caches are stored where their stall is invisible: once when a race ends,
|
||||
// and by the compiler itself while the headset shows the virtual screen. Never
|
||||
@@ -888,12 +895,14 @@ private:
|
||||
// before FinishFrame submits a layer built from it.
|
||||
ServiceRecenterRequest();
|
||||
UpdateVirtualScreenPose(frame);
|
||||
const OpenXRPointerScreen panel_screen = SettingsPanelScreen(frame, policy, immersive);
|
||||
PlacePanelLayer(frame, panel_screen);
|
||||
if (input_ != nullptr) {
|
||||
const diagnostics::ScopedStage input_timer(diagnostics::Stage::InputSync);
|
||||
// After the screen is placed, so the pointer aims at this
|
||||
// frame's screen rather than the previous one's.
|
||||
input_->Sync(frame.xr_frame.predicted_display_time, PointerScreen(frame, policy, immersive),
|
||||
SettingsPanelScreen(frame, policy, immersive), InputSeatFrame(immersive));
|
||||
panel_screen, InputSeatFrame(immersive));
|
||||
}
|
||||
|
||||
if (!frame.expects_gpu_submission) {
|
||||
@@ -1018,6 +1027,7 @@ private:
|
||||
|
||||
SetInterpolationActive(false);
|
||||
aurora_set_pipeline_cache_idle_store(false);
|
||||
aurora_set_stereo_panel_layer(false);
|
||||
running_.store(false, std::memory_order_release);
|
||||
MkwVRPolicySetSessionActive(false);
|
||||
if (!stop_.load(std::memory_order_acquire)) {
|
||||
@@ -1071,10 +1081,12 @@ private:
|
||||
// The head pose this packet was located with places the screens and aims the pointer.
|
||||
ServiceRecenterRequest();
|
||||
UpdateVirtualScreenPose(packet);
|
||||
const OpenXRPointerScreen panel_screen = SettingsPanelScreen(packet, policy, immersive);
|
||||
PlacePanelLayer(packet, panel_screen);
|
||||
if (input_ != nullptr) {
|
||||
const diagnostics::ScopedStage input_timer(diagnostics::Stage::InputSync);
|
||||
input_->Sync(packet.xr_frame.predicted_display_time, PointerScreen(packet, policy, immersive),
|
||||
SettingsPanelScreen(packet, policy, immersive), InputSeatFrame(immersive));
|
||||
panel_screen, InputSeatFrame(immersive));
|
||||
}
|
||||
if (!packet.expects_gpu_submission) {
|
||||
// Nothing to render (no rendering requested or no tracking): keep the compositor fed.
|
||||
@@ -1393,6 +1405,42 @@ private:
|
||||
return screen;
|
||||
}
|
||||
|
||||
// Android: `adb shell setprop debug.wiicompiled.panel_layer 0` draws the settings panel into
|
||||
// the eyes again, to compare the two ways or to rule out a runtime's quad layers. Read about
|
||||
// once a second.
|
||||
bool PanelLayerForcedOff() noexcept {
|
||||
#if defined(__ANDROID__)
|
||||
if (panel_layer_poll_ == 0) {
|
||||
panel_layer_poll_ = 72;
|
||||
char value[PROP_VALUE_MAX] = {};
|
||||
const bool off =
|
||||
__system_property_get("debug.wiicompiled.panel_layer", value) > 0 && value[0] == '0';
|
||||
if (off != panel_layer_forced_off_) {
|
||||
panel_layer_forced_off_ = off;
|
||||
RT_LOG(RT_TAG_RUNTIME) << "OpenXR: settings panel "
|
||||
<< (off ? "drawn into the eyes" : "on its own layer")
|
||||
<< " (debug.wiicompiled.panel_layer)" << std::endl;
|
||||
}
|
||||
}
|
||||
--panel_layer_poll_;
|
||||
return panel_layer_forced_off_;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
// The settings panel's layer hangs exactly where its pointer hits are
|
||||
// tested, the rectangle it used to cover in the eyes.
|
||||
static void PlacePanelLayer(OpenXRBackendFrame& frame, const OpenXRPointerScreen& screen) noexcept {
|
||||
OpenXRPanelLayer& panel = frame.presentation.panel;
|
||||
panel.placed = panel.requested && screen.valid;
|
||||
if (panel.placed) {
|
||||
panel.pose = screen.pose;
|
||||
panel.width_meters = 2.0f * screen.half_width_meters;
|
||||
panel.height_meters = 2.0f * screen.half_height_meters;
|
||||
}
|
||||
}
|
||||
|
||||
// Centre of the race's 2D screen. ViewFromBase maps a point p of the
|
||||
// recorded centre-eye space (in metres) to base + lean * p in the
|
||||
// application space, so the screen Aurora hangs hud_distance_meters ahead
|
||||
@@ -1601,6 +1649,10 @@ private:
|
||||
OpenXRLogCallback logger_;
|
||||
std::unique_ptr<OpenXRRuntime> runtime_;
|
||||
std::unique_ptr<GraphicsBackend> backend_;
|
||||
#if defined(__ANDROID__)
|
||||
uint32_t panel_layer_poll_ = 0;
|
||||
bool panel_layer_forced_off_ = false;
|
||||
#endif
|
||||
std::unique_ptr<OpenXRInput> input_;
|
||||
std::thread pacing_thread_;
|
||||
std::atomic_bool stop_{false};
|
||||
|
||||
Reference in new issue
Block a user