1be0bebda2
build / build (push) Successful in 1m43s
Replaces the single shared, side-by-side swapchain (game + menu content packed into one image, needing viewport/scissor juggling to keep the menu's own glClear from bleeding into the game's region) with two fully independent XrSwapchainState instances, each sized to exactly its own content and acquired/released on its own within the same xrBeginFrame/xrEndFrame pair - an ordinary multi-layer OpenXR setup. The shared-swapchain design was originally adopted to work around what looked like a Horizon OS compositor limitation with independent swapchains, but that was diagnosed before the real root cause of the "menu shows the game's content" bug was found (gl4es's fpe.c unconditionally substituting its own shader onto the menu's draw call - see README's Debugging notes). Since the actual fix routes the menu's blit through a real, non-gl4es glBlitFramebuffer() call - orthogonal to how many swapchains exist - splitting back onto two swapchains works fine and removes the GL_SCISSOR_TEST workaround and sub-rectangle offset math entirely. Confirmed on-device: both quads render correctly, hit-testing and 90 FPS unaffected. Also adds a visible cursor to the menu quad itself: xr_input.c now tracks whichever hand's aim ray hits the menu each frame and forwards it to a new MenuOverlay.nativeUpdateCursor(), which draws a small dot at that position (composited through the same Bitmap the menu's own content already goes through) - previously there was no visual feedback at all showing where you were pointing before pulling the trigger.
66 lines
2.9 KiB
C
66 lines
2.9 KiB
C
// Minimal OpenXR bring-up for questshock's immersive Quest build. Keeps the
|
|
// game's own rendering untouched (see android/engine-patches/
|
|
// 11-android-openxr-present.patch) - this module only owns the OpenXR
|
|
// instance/session/swapchains and the final "submit quad layers instead of
|
|
// presenting to a window" step. No stereo rendering - the game composite is
|
|
// shown as a single flat quad floating in front of the viewer.
|
|
#ifndef QUESTSHOCK_XR_SESSION_H
|
|
#define QUESTSHOCK_XR_SESSION_H
|
|
|
|
#include <stdbool.h>
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
// Call once, right after init_opengl() (OpenGL.cc) has created and made
|
|
// current the GL context SDL/gl4es already use - creates the OpenXR
|
|
// instance/session sharing that same EGL display/context, plus the game
|
|
// quad's own swapchain, sized to the game's logical resolution
|
|
// (game_width/height, i.e. grd_cap->w/h - see Shock.c's InitSDL()). The
|
|
// menu quad's own, independently-sized swapchain (see xr_menu.h) is created
|
|
// alongside it. Returns false if OpenXR bring-up failed (e.g. no runtime
|
|
// installed) - callers should fall back to the existing window-present path
|
|
// in that case.
|
|
bool xr_init(int game_width, int game_height);
|
|
|
|
// Pumps XR session-state events. Call once per frame, before
|
|
// xr_frame_begin(). Must still be called even when xr_init() returned
|
|
// false (no-op in that case).
|
|
void xr_poll_events(void);
|
|
|
|
// True once the session has reached a state where frames are expected
|
|
// (XR_SESSION_STATE_SYNCHRONIZED or later) - i.e. it's safe/required to
|
|
// start calling xr_frame_begin()/xr_frame_end() each frame.
|
|
bool xr_is_session_running(void);
|
|
|
|
// Begins the XR frame (xrWaitFrame/xrBeginFrame) and, if the runtime wants
|
|
// this frame rendered, acquires the game quad's next swapchain image and
|
|
// binds its framebuffer as the current render target - ready for the
|
|
// caller to draw into exactly as it would have drawn to the default
|
|
// framebuffer. Returns true if the caller should draw this frame;
|
|
// xr_frame_end() must be called unconditionally afterward either way (a
|
|
// begun XR frame must always be ended, rendered or not).
|
|
bool xr_frame_begin(void);
|
|
|
|
// Releases the game quad's swapchain image (if one was acquired this
|
|
// frame), acquires/renders/releases the menu quad's own swapchain image if
|
|
// it's currently visible (see xr_menu.h), submits whichever of the two
|
|
// quads actually rendered this frame as composition layers positioned in
|
|
// front of the local reference space's origin, then ends the XR frame.
|
|
void xr_frame_end(void);
|
|
|
|
void xr_shutdown(void);
|
|
|
|
// Local-space geometry of the single game quad xr_frame_end() submits
|
|
// (distance in front of the local space origin, half-width/half-height,
|
|
// all in meters) - shared with xr_input.c's ray/quad hit-testing so the
|
|
// laser pointer always matches whatever's actually visible.
|
|
void xr_get_game_quad_extent(float *distance_m, float *half_width_m, float *half_height_m);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif
|