#ifndef AURORA_GFX_H #define AURORA_GFX_H #ifdef __cplusplus #include #include extern "C" { #else #include "stddef.h" #include "stdint.h" #endif #ifndef NDEBUG #define AURORA_GFX_DEBUG_GROUPS #endif void aurora_push_debug_group(const char* label); void aurora_pop_debug_group(); typedef struct { uint32_t queuedPipelines; uint32_t createdPipelines; uint32_t drawCallCount; uint32_t mergedDrawCallCount; uint32_t lastVertSize; uint32_t lastUniformSize; uint32_t lastIndexSize; uint32_t lastStorageSize; uint32_t lastTextureUploadSize; uint32_t presentedFrameCount; uint32_t interpolatedFrameCount; } AuroraStats; typedef struct { uint64_t totalPresentCount; uint32_t sampleCount; double framesPerSecond; double averageFrameTimeMs; double p95FrameTimeMs; double jitterMs; // framesPerSecond with duplicated presentation slots scaled out, so this is the rate of frames // that carried new motion. Equal to framesPerSecond when every slot replayed real interpolation. double effectiveFramesPerSecond; } AuroraPresentTiming; const AuroraStats* aurora_get_stats(); void aurora_get_present_timing(AuroraPresentTiming* timing); // Interpolation health: the per-frame fields describe the last sealed frame, the counters // accumulate since it was configured. This answers "output FPS dropped but the game held 60". typedef struct { uint32_t targetFps; // configured target, 0 when interpolation is off uint32_t targetSamples; // slots the pacing controller currently aims for uint32_t activeSamples; // slots latched for the latest sealed frame uint32_t candidates; // perspective draws in the latest sealed frame uint32_t matchable; // candidates whose identity also existed last frame uint32_t matches; // draws matched to the previous frame uint32_t eligible; // latest frame inserted interpolated slots uint32_t replaySafe; // latest frame could replay its command stream uint64_t framesSealed; uint64_t framesLowMatch; uint64_t framesReplayUnsafe; uint64_t slotReductions; uint64_t lateSealDrops; } AuroraFrameInterpolationDiagnostics; void aurora_get_frame_interpolation_diagnostics(AuroraFrameInterpolationDiagnostics* diagnostics); // Generates transform-interpolated perspective frames between consecutive 60 Hz logical frames. // Supported targets are 0 (off), 120, 180 and 240. Guest simulation and VI timing are unchanged. void aurora_set_frame_interpolation_fps(uint32_t targetFps); uint32_t aurora_get_frame_interpolation_fps(); // Independent from desktop interpolation: replay captured race transforms at // each headset deadline, leaving guest simulation and VI timing at 60 Hz. void aurora_set_stereo_frame_interpolation(bool enabled); bool aurora_get_stereo_frame_interpolation(); // Newly encountered GX pipelines compile on the bounded worker queue. Draws whose pipeline is not // ready are skipped rather than stalling submission, and pick it up once compilation finishes. void aurora_set_skip_unready_pipelines(bool enabled); bool aurora_get_skip_unready_pipelines(); uint32_t aurora_get_queued_pipeline_count(); // Controls whether display copies bypass the Wii's vertical copy filter. void aurora_set_disable_copy_filter(bool disabled); bool aurora_get_disable_copy_filter(); // Immersive (stereo) replay EFB controls, both enabled by default, and both // live: they take effect on the next frame with no restart. // // stop_at_display_copy ends each eye's replay at the frame's final GXCopyDisp, // so an eye holds exactly the image the game presented. skip_copy_clears drops // the EFB reset a GX copy performs after copying, which on the Wii prepares the // reused EFB for the next frame but on a per-frame eye attachment only erases // the replay. Disable either to compare against the raw replay. void aurora_set_stereo_stop_at_display_copy(bool enabled); bool aurora_get_stereo_stop_at_display_copy(); void aurora_set_stereo_skip_copy_clears(bool enabled); bool aurora_get_stereo_skip_copy_clears(); // single_pass_eyes keeps drawing an eye in the render pass it has open across // the frame's GX copies, which only the mono render performs, and leaves out // passes a later clear of the whole EFB erases. The image is the same with // fewer tile loads and stores; on by default, live, and off replays one render // pass per recorded pass. void aurora_set_stereo_single_pass_eyes(bool enabled); bool aurora_get_stereo_single_pass_eyes(); // Fixed foveated rendering of the immersive eyes: 0 off, 1 low, 2 medium, 3 // high. Each eye's render pass runs under a fragment density map that shades // the periphery in 2x2, then 4x4 pixel blocks, the higher the level the closer // to the centre. Only an eye drawn in a single render pass (single_pass_eyes) // is foveated; menus on the virtual screen never are. Live, but it needs a // device created with AuroraConfig::xrFragmentDensityMap and a Dawn built with // Aurora's patches (the Quest build); aurora_stereo_foveation_available says // whether this session has both. void aurora_set_stereo_foveation(uint32_t level); uint32_t aurora_get_stereo_foveation(); bool aurora_stereo_foveation_available(); // Places orthographic GX draws (menus, HUD, 2D overlays) on a fixed virtual // screen during immersive replay instead of stretching them across the whole // eye viewport. The screen hangs `distance` world units straight ahead of the // game camera and is `width` world units across, its height following the // aspect ratio the game is presenting at. It stays put in the camera's frame, // so looking around moves the view across it rather than dragging it along. // Also live; a cleared flag or a non-positive size leaves 2D content on its // recorded GX transforms. void aurora_set_stereo_hud_screen(bool enabled, float width, float distance); bool aurora_get_stereo_hud_screen_enabled(); // Aspect ratios behind the most recent headset frame's 2D content, for mapping a // point on a virtual screen back onto the game picture (the VR Wii Remote // pointer). `pictureAspect` is the game picture's width over height, which the // immersive HUD screen's height follows; `snapshotAspect` is the desktop // presentation image's, which the virtual-screen eye texture letterboxes and // the picture is letterboxed inside. False until a headset frame was encoded. // Safe to call from any thread. bool aurora_get_stereo_screen_aspects(float* pictureAspect, float* snapshotAspect); // What the desktop window shows while a headset is being fed. NORMAL leaves the // ordinary mono presentation untouched, the eye views mirror what the headset is // actually displaying, and NONE presents a black window. Live, and only // consulted while a stereo frame provider is supplying frames. // When a frame has no new XR packet, eye views retain the previous eye image // instead of falling back to the ordinary desktop view. // // A menu frame reaches the headset as a virtual screen carrying the very mono // image the desktop already shows, so there is no distinct eye view to mirror: // every eye choice presents that same image there, and only NONE differs. // // Interpolated presentation slots are encoded before the frame's eyes are // rendered, so under an eye choice they mirror the previous frame's eyes while // the real slot mirrors the current one. typedef enum { AURORA_STEREO_MIRROR_NORMAL = 0, AURORA_STEREO_MIRROR_BOTH_EYES = 1, AURORA_STEREO_MIRROR_LEFT_EYE = 2, AURORA_STEREO_MIRROR_RIGHT_EYE = 3, AURORA_STEREO_MIRROR_NONE = 4, } AuroraStereoMirrorView; void aurora_set_stereo_mirror_view(AuroraStereoMirrorView view); AuroraStereoMirrorView aurora_get_stereo_mirror_view(); // Guest-RAM write tracking. `generation` changes whenever guest RAM covering a host range was // written (or returns AURORA_GUEST_WRITE_UNTRACKED); `notify` reports writes aurora made itself. #define AURORA_GUEST_WRITE_UNTRACKED UINT64_MAX typedef uint64_t (*AuroraGuestWriteGenerationCallback)(const void* hostPtr, size_t size); typedef void (*AuroraGuestWriteNotifyCallback)(const void* hostPtr, size_t size); void aurora_set_guest_write_hooks(AuroraGuestWriteGenerationCallback generation, AuroraGuestWriteNotifyCallback notify); #ifdef __cplusplus } #endif #endif