75 Commits
Author SHA1 Message Date
Jeremy Bowers 70d096f8d7 Fix issue with intermittent slowdown.
An error in the way frames were submitted to XR resulted in intermittent
slowdown that fooled me for a while as being shader compilation stutter,
and had me down the wrong track of investigating that.

However this was actually the root cause. This should bring Baiji up to
performance parity with the current Dolphin release, as near as I can tell.

Resolves Issue #13.
2026-10-16 01:00:07 -04:00
Jeremy Bowers 38fc6d9a95 Remove the arrow in the help dialogs.
The previous fix to fit them in their dialog box often unseated
the arrow from the widget it is trying to point at. With the user
so actively interacting with the widgets to get the help,
including having to hold the pointer steady to keep it where they
can read it (arguably a problem of its own), I don't think we need
to quite that aggressively point at the target widget.
2026-10-16 00:56:49 -04:00
Jeremy Bowers 3d27e75026 Update Readme with Gamecube emulation notes
Added remarks about Gamecube games performance on Steam Frame and emulation challenges.
2026-10-14 10:04:29 -04:00
Jeremy Bowers f395e45ddf Move the wish list of PRs into Issues. 2026-10-12 21:56:32 -04:00
Jeremy Bowers 14effdb34e Fix the tooltips so they don't exceed the dialog's boundaries.
Steam OS intepreted that as a resize of the window and recentered it.
This caused a lot of displeasing UI churn.

This still leaves the little chevrons pointed at the wrong places
sometimes but it is still a much better user experience.
2026-10-12 19:49:33 -04:00
Jeremy Bowers 8b4a0723fc Tone down my stridency about issues, and rewrite the contribution guide Github links to. 2026-10-12 19:16:59 -04:00
Jeremy Bowers 982671b53f Move default + and - button mappings. 2026-10-12 14:56:55 -04:00
Jeremy Bowers 38cf5cf933 Make the best fix for Room View in S3D we can, given what the OS gives us. 2026-10-11 22:16:20 -04:00
Jeremy Bowers 24634ba1bd Fix the flat backend's way of requesting a surface to draw on. 2026-10-11 12:20:31 -04:00
Jeremy Bowers 0775c13109 Some Readme.md updates. 2026-10-11 11:53:04 -04:00
Jeremy Bowers 6b197206e8 Enhance Readme with UI and VR emulation suggestions
Added suggestions for improving the UI and VR emulation experience.
2026-10-09 14:31:10 -04:00
Jeremy Bowers 89dc31c6e8 Update Readme.md 2026-10-09 09:35:59 -04:00
Jeremy Bowers 46a987148d Update the Readme.md for release. 2026-10-06 09:13:02 -04:00
Jeremy Bowers 0cef1d3651 Add a note acknowledging the QT GUI has this issue too. 2026-10-05 22:37:42 -04:00
Jeremy Bowers dbb7283447 Installation instructions. 2026-10-05 22:27:59 -04:00
Jeremy Bowers 52ffacb887 Update about shortcut mappings. 2026-10-05 22:18:30 -04:00
Jeremy Bowers ac2b377e23 Remove some spurious mappings. 2026-10-05 21:48:18 -04:00
Jeremy Bowers 20c13cc035 Update about the immersive VR. 2026-10-05 21:04:01 -04:00
Jeremy Bowers 57f026c120 Put the proper executable into Gamescope/Big Picture. 2026-10-05 21:00:05 -04:00
Jeremy Bowers 122721b259 Fix odd formatting on the compile instructions. 2026-10-05 20:54:54 -04:00
Jeremy Bowers 23b616ebf8 Note about the immersive VR not working well. 2026-10-05 20:47:38 -04:00
Jeremy Bowers 652ee1ef1b Compile a release build instead of a debug build. 2026-10-05 20:41:10 -04:00
Jeremy Bowers f55ab9b06e Install the flatpak-based SDK if needed. You're up, Ubuntu. 2026-10-05 20:11:38 -04:00
Jeremy Bowers ce1c7928a7 OK, builds on Ubuntu, let's try on SteamOS again. 2026-10-05 19:44:51 -04:00
Jeremy Bowers c4eb076a49 Further attempts to build this elsewhere. 2026-10-05 18:13:10 -04:00
Jeremy Bowers 6712e7cdbf Try to update build scripts to work on something other than the original system. 2026-10-05 18:07:59 -04:00
Jeremy Bowers 3a5060500c Make a note that I don't care to own this. 2026-10-05 17:47:38 -04:00
Jeremy Bowers fbeefedb2a Updates to the Readme.md and compiling scripts. 2026-10-05 17:06:08 -04:00
Jeremy Bowers 97f1160707 Initial Readme.md. 2026-10-05 16:25:04 -04:00
Jeremy Bowers c652e2d702 Frame: remind users to release laser pointer focus
In flat Vulkan mode, Steam Frame controller buttons can appear not to
reach the game while the system's laser-pointer mode still owns focus.
This is an easy mistake to make when starting a game from the headset.

After a successful boot, show an informational dialog for explicit Flat
Display (Vulkan) mode and for legacy configurations with OpenXR disabled.
The check happens after boot metadata and per-game VR settings are loaded,
so immersive VR and Stereo 3D Screen launches are not interrupted.

Add the requested reminder text and a Never See This Dialog Again
checkbox. Persist the opt-out in Main.Interface, and leave it unchecked by
default so the reminder appears for new users.
2026-10-05 00:33:01 -04:00
Jeremy Bowers 18e1811dec Build: carry OpenXR loader workaround as a patch
Keep Externals/OpenXR pinned to Khronos' upstream 1.1.63 commit
instead of carrying local source edits as an unreachable submodule commit.
Record the three Frame loader compatibility changes in the parent tree as
OpenXR-Loader-Exceptions.patch.

When ENABLE_VR is configured, copy the pinned SDK into the binary tree,
apply the patch to that copy, and build the loader from there. This leaves
the checked-out submodule clean and supports read-only source mounts in
container builds. CMake verifies the patch applies to the expected SDK
files before adding the patched copy to the build.
2026-10-05 00:32:47 -04:00
Jeremy Bowers 9dd817d864 OpenXR: add independent stereo separation control
Immersive VR previously used the full runtime-reported left/right view
positions, with Units per Meter scaling both world geometry and the
per-eye offsets. That left no direct way to soften strong near-field
pop-out without also changing the apparent world scale.

Add Graphics.VR.StereoSeparation as a 0-200 percent setting, defaulting
to 100 percent. Scale each eye's positional offset around the average
eye center independently of shared head translation. At 100 percent the
projection is unchanged, 0 percent brings the virtual view positions
together toward mono, and values above 100 percent amplify stereo depth.
Units per Meter continues to set world scale and head-motion mapping.

Expose the setting in the global VR pane and per-game VR configuration,
include it in game VR override application/reset, and refresh cached
projection rows when it changes. Help text explains the scale/depth
tradeoff, possible near-field comfort benefit, and that Stereo 3D Screen
continues to use the existing Stereoscopic Depth control.
2026-10-05 00:21:28 -04:00
Jeremy Bowers 8a150c187e Checkpoint - add some files that have fallen through the cracks. 2026-10-04 23:46:15 -04:00
Jeremy Bowers 75d1994b9c Checkpoint with some stuff that needs to be committed. 2026-10-04 23:17:49 -04:00
Jeremy Bowers 6c95b40453 Steam Frame: complete stereo eye writes before XR release
StereoScreen previously submitted and released each Vulkan eye separately
while its image writes could still be in flight. On native Steam Frame
this produced conspicuous doubled/stale-image hiccups and apparent
backward jumps, even though API-side frame identities remained ordered.
A capture covering 16,699 XFB copies found no gameplay source regression,
GPU-submit reversal, XR display-time reversal, or eye-ID mismatch.
SteamVR motion smoothing was already forced off.

For Baiji StereoScreen, defer eye releases until both blits are recorded,
submit their GPU work together, wait once for completion, release both
images under the graphics-queue lock, then publish the quad layers.
Keep this wait even with timeline semaphores enabled: submitted writes
alone were insufficient for correct image delivery on Frame. The wait
trades some CPU/GPU overlap for a completed stereo pair.

Also exclude xrEndFrame from the video blit/completion/release/publish
transaction with a handoff mutex. The previous atomic flag had a
check-to-submit race. Take the handoff lock before publish/queue locks,
and never hold the graphics-queue lock during the completion wait.
PresentBackbuffer already advances frame resources; the stereo submit
must not advance them again.

CPU-side handoff locking alone did not cure the artifact. Headset tests
with the completed-pair handoff in Super Mario Galaxy 2 at 2x/120 Hz
confirmed that remaining misses look like ordinary dropped frames,
rather than doubled images or huge hiccups. The clean Frame SDK build
and launcher CLI smoke check passed. Remove the temporary timing/order
capture code and retain the findings and lock-order guidance in AGENTS.md.
2026-10-04 23:10:20 -04:00
Jeremy Bowers 4465c932fb Steam Frame: decouple XR heartbeat from game timing 2026-10-04 20:54:26 -04:00
Jeremy Bowers 22f6884ca0 Checkpoint. This has a number of things including defaulting eager_heartbeat to true. 2026-10-04 14:41:52 -04:00
Jeremy Bowers ef1a3a0500 OpenXR: synchronize flat-screen reanchor cache 2026-10-04 14:38:56 -04:00
Jeremy Bowers 8c549d2036 DolphinQt: hide raw motion mappings for Frame 2026-10-03 23:16:44 -04:00
Jeremy Bowers 7df6a30691 DolphinQt: defer Frame mappings until controller loads 2026-10-03 23:03:54 -04:00
Jeremy Bowers 5fa8d90d8b Steam Frame: use dropdown controller mappings and defaults 2026-10-03 22:58:52 -04:00
Jeremy Bowers d3bdaab03a DolphinQt: remove VR mapping configure button 2026-10-03 22:36:43 -04:00
Jeremy Bowers ce93e0606d DolphinQt: pin controller mapping to Steam Frame 2026-10-03 22:26:21 -04:00
Jeremy Bowers 834cdddd2e OpenXR: add Steam Frame controller input 2026-10-03 22:21:35 -04:00
Jeremy Bowers bec9d1beae OpenXR: keep controller input in Flat Vulkan mode 2026-10-03 21:00:54 -04:00
Jeremy Bowers 3ec01541fd OpenXR: add configurable presentation modes 2026-10-03 20:06:38 -04:00
Jeremy Bowers 0e74b57e09 OpenXR: remove temporary recenter/aim debug logging
Diagnosis confirmed: the runtime rebases the reference space on system
recenter (logged head_yaw matched the user's per-run offset exactly), and
controllers share the HMD's tracking frame. Keep only the low-volume
reference-space-change and recenter log lines.
2026-10-03 13:51:35 -04:00
Jeremy Bowers 2e826d8914 OpenXR: re-anchor flat screen on reference space change
The runtime rebases the reference space on system recenter, universe
switches, and relocalization, and notifies apps via
XrEventDataReferenceSpaceChangePending. Dolphin only logged the event, so
the world-locked flat-screen quad kept its stale coordinates and appeared
to jump by the rebase yaw every time the user used the system recenter
(the HMD's yaw in the runtime's arbitrary local frame — random per run).

On the event, invalidate the cached flat-screen pose so the panel is
re-placed in front of the user's current gaze, which is also the expected
behavior after a system recenter. Log the event's poseInPreviousSpace yaw
delta, and add a throttled view-yaw vs aim-yaw diagnostic to check whether
the runtime reports controllers in a different tracking frame.
2026-10-03 13:20:18 -04:00
Jeremy Bowers 1190e903be OpenXR: add minimal recenter/screen-pose debug logging
Log head yaw, screen yaw, and screen direction at initial flat-screen
placement and after recenter, to diagnose the underlying offset issue.
2026-10-03 12:44:50 -04:00
Jeremy Bowers a02a554c86 OpenXR: revert recenter changes to pre-d9ed82e state
Remove the reference-space recreation recenter, ScreenYawOffset config, and
debug logging. Restore the original home-position recenter and world-locked
flat screen placement so we can diagnose the underlying issue from a clean
baseline.
2026-10-03 12:41:08 -04:00
Jeremy Bowers cf72cfeb53 OpenXR: add recenter debug logging
Log head yaw, reference-space offset yaw, and post-recenter screen pose for
5 frames after each recenter. This is diagnostic to find why recenter
produces a fixed per-run error.
2026-10-03 12:29:22 -04:00
Jeremy Bowers 8fb66a2936 Revert "OpenXR: make repeated recenter operations compose correctly"
This reverts commit 75dc76990b.
2026-10-03 12:25:36 -04:00
Jeremy Bowers 75dc76990b OpenXR: make repeated recenter operations compose correctly
The previous recenter code computed the head pose in the current (already
recentered) reference space and passed it directly to xrCreateReferenceSpace,
which interprets the pose relative to the runtime's natural LOCAL frame. This
made repeated recenters compound incorrectly and produced a random-looking
offset per run.

Accumulate the head-in-current-space offset onto a persistent
m_recenter_offset pose relative to the natural LOCAL frame, and create each new
reference space from that accumulated offset. Also add diagnostic logging for
recenter.
2026-10-03 12:11:56 -04:00
Jeremy Bowers 328997747a OpenXR: add ScreenYawOffset config to adjust virtual screen horizontal angle
Adds a VR/ScreenYawOffset setting (degrees, default 0). Positive values
rotate the virtual screen counter-clockwise from above (to the left);
negative values rotate clockwise (to the right). This is intended as a
diagnostic/tuning knob for the stereoscopic virtual screen placement.
2026-10-03 11:38:37 -04:00
Jeremy Bowers f6d7395ea2 OpenXR: fix recenter offset sign
The recenter offset was computing the inverse of the desired transform.
The new reference space should be placed at the current head pose (yaw-only)
so that the current gaze becomes forward, not rotated the opposite way.
2026-10-03 11:16:19 -04:00
Jeremy Bowers c7499b4ccf OpenXR: fix recenter by reorienting reference space
Recenter now recreates the OpenXR reference space with a yaw-only offset
that maps the user's current head pose to the origin. This makes the flat
virtual screen appear directly in front of the user after recentering, with
upright orientation, instead of being left at an arbitrary session-start
forward direction.

Reverts the temporary head-locked stereo-screen behavior; the screen is
world-locked again, so the Wiimote pointer orientation stays consistent.
2026-10-03 11:09:36 -04:00
Jeremy Bowers d9ed82e38f OpenXR: make stereoscopic virtual screen head-locked
In stereo-screen mode, recompute the virtual screen pose every frame from the
user's current head yaw so the screen always stays in front of their gaze.
This avoids the confusing behavior where the initial world-locked placement
captured a random head pose during startup and recenter could leave the screen
off to one side.

Flat mono panel mode keeps the existing world-locked behavior.
2026-10-03 10:55:52 -04:00
Jeremy Bowers 4359d8c989 OpenXR: remove refresh-rate request diagnostics
SteamVR on the Steam Frame returns XR_ERROR_FEATURE_UNSUPPORTED for both
60 Hz and 120 Hz requests, so the request function works but the runtime
has no such modes. Remove the temporary diagnostic log and keep the
feature available for runtimes that do support app-controlled refresh rates.
2026-10-03 10:29:40 -04:00
Jeremy Bowers 7726dbe5a5 OpenXR: add requested display refresh rate
Add GFX_VR_REQUESTED_REFRESH_RATE setting (Auto/60/72/90/120 Hz). When a
non-zero rate is configured, call xrRequestDisplayRefreshRateFB after the
session begins so the runtime can switch the headset panel to a rate that
matches the game's frame rate (e.g. 60 Hz or 120 Hz for 60 fps Wii games,
instead of the default 72 Hz).

This should reduce judder caused by the compositor showing 60 fps content on
a 72 Hz display. The runtime may clamp the request to the nearest supported
rate; the result is logged.

UI exposed in VRPane and VRConfigWidget.
2026-10-03 10:12:22 -04:00
Jeremy Bowers 64878c16c4 Polish stereoscopic virtual screen mode
- Make Flat Screen and Stereo Screen checkboxes mutually exclusive in VRPane.
- Fix Vulkan Android stereo-screen submission to end the render pass and
  submit the command buffer once before releasing both eye images, instead of
  once per eye.
2026-10-03 01:36:00 -04:00
Jeremy Bowers fb2e70a608 OpenXR: implement stereoscopic virtual screen mode
- Add IOpenXRSwapchain::GetEyeSwapchainHandle() and SubmitStereoFlatFrame(),
  with per-backend overrides for Vulkan, D3D11, D3D12, and OGL.
- Add OpenXRManager::SubmitStereoQuadFrame() which builds two world-locked
  XrCompositionLayerQuad layers with XR_EYE_VISIBILITY_LEFT/RIGHT and publishes
  them through the pacing thread (or EndFrame on the legacy path).
- Extend PublishedXRFrame and FrameThreadLoop to submit the stereo quad pair.
- Add UI checkbox for Stereo Screen in VRPane and VRConfigWidget.

The game renders with classic SBS stereoscopy; left/right XFB layers are blit
into the corresponding OpenXR eye swapchains and shown as a 3D floating screen.
2026-10-03 01:29:02 -04:00
Jeremy Bowers 49cf50d0e2 Presenter: add stereoscopic virtual screen submission path
Add IsOpenXRStereoScreen() and route classic SBS frames through a new
SubmitStereoFlatFrame() path. The left XFB layer is blit into the left
OpenXR eye swapchain and the right layer into the right eye swapchain,
then the backend submits two quad layers at the virtual-screen pose.

Stereo-screen mode is treated like flat mode for direct-to-HMD and
pacing-thread deferral: the eye blits happen at submit time, not during
the desktop mirror path.
2026-10-03 01:24:39 -04:00
Jeremy Bowers 3deb147e55 Config: add vr_stereo_screen mode
Add GFX_VR_STEREO_SCREEN setting. When OpenXR is enabled and this mode is
active, force stereo_mode to SBS so the game renders with Dolphin's classic
side-by-side stereoscopy. Extend VRSessionActive() to keep the OpenXR session
alive for this path. This is the first step toward submitting a stereoscopic
virtual screen via OpenXR quad layers.
2026-10-03 01:23:38 -04:00
Jeremy Bowers aa2871d9e6 VK/OpenXR: support headless Vulkan VR session
- Skip Vulkan surface creation when VR session is active; output goes to
  OpenXR swapchains, not a desktop window. This avoids WSI crashes under
  compositors such as Gamescope.
- Guard VKGfx backbuffer/present/fullscreen paths against a null swapchain
  in headless mode.
- Allow Present() and Presenter::Initialize() to run on any VR-active
  backend, not only Android GLES, so the XR frame lifecycle works with
  headless Vulkan.

Cleaned up diagnostic init logging added during earlier debugging.
2026-10-03 01:22:39 -04:00
iChris4 5e9a304a65 Merge branch 'openxr-work' of https://github.com/iChris4/dolphinXR into openxr-work 2026-09-30 19:56:24 +02:00
iChris4 1678bc7cd5 Update fmt submodule to latest commit 2026-09-30 19:56:16 +02:00
iChris4 ffe128309f Add tracked eye projection rows to OpenXRManager for HUD independence 2026-09-30 19:55:15 +02:00
Christophe 6955095298 Merge pull request #5 from BookOfGreg/qt6-10-fix
Qt6 10 fix
2026-09-21 00:26:55 +02:00
Christophe 308ce19adf Add GitHub Sponsors username to FUNDING.yml 2026-09-21 00:26:23 +02:00
Greg Myers 6f5b20ac24 Dist 2026-08-21 22:15:04 +01:00
Greg Myers 1292404e31 docker build 2026-08-21 22:14:52 +01:00
Greg Myers 2d41ce7ac4 qt6 2026-08-19 19:34:22 +01:00
Greg Myers ca0070222d WIP Docker 2026-08-18 21:25:33 +01:00
Greg Myers 3d069f0bb9 fix: qt6.10 on ubuntu does not appear to have guiprivate that causes the need for the specific fix 2026-08-17 23:08:36 +01:00
iChris4 9bd33b5f6b Clears m_loaded_game_id when stopping emulation 2026-08-11 17:22:42 +02:00
177 changed files with 4226 additions and 1267 deletions

No files matched your search

+52
View File
@@ -0,0 +1,52 @@
### Copy of gitignore
# Ignore image thumbnail files created by windows
Thumbs.db
# Ignore Finder view option files created by OS X
.DS_Store
# Ignore autogenerated source files
Externals/mGBA/version.c
Source/Core/Common/scmrev.h
# Ignore files output by build
/cmake-build-debug
/cmake-build-release
/[Bb]uild/
/[Bb]inary/
/obj/
# Ignore files output by Android cmake build
/Source/Android/app/.cxx/
/libs/
# Ignore various files created by visual studio/msbuild
*.ipch
*.opensdf
*.sdf
*.suo
*.vcxproj.user
*.obj
*.tlog
*.VC.opendb
*.VC.db
.vs*/
/Source/enc_temp_folder/
# Ignore build info file created by QtCreator
CMakeLists.txt.user
# Ignore vim swapfiles
*.swp
# Ignore kdevelop files/dirs
*.kdev4
# Ignore IDEA/Clion files/dirs
.idea/
# Ignore Visual Studio Code's working dir
/.vscode/
# Ignore flatpak-builder's cache dir
.flatpak-builder
# DolphinXR dev artifacts
codex_apk_backups/
quest_perf_capture/
vulkan_pipeline_failures/
vulkan_pipeline_failures_latest/
vulkan_pipeline_failures_latest2/
quest_first_mv_vs.glsl
quest_mv_vs.glsl
### Changes from gitignore
+15
View File
@@ -0,0 +1,15 @@
# These are supported funding model platforms
github: [iChris4] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
polar: # Replace with a single Polar username
buy_me_a_coffee: # Replace with a single Buy Me a Coffee username
thanks_dev: # Replace with a single thanks.dev username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
+8 -1
View File
@@ -43,7 +43,7 @@ CMakeLists.txt.user
/.vscode/
# Ignore flatpak-builder's cache dir
.flatpak-builder
# DolphinXR dev artifacts
# Local development artifacts
codex_apk_backups/
quest_perf_capture/
vulkan_pipeline_failures/
@@ -51,3 +51,10 @@ vulkan_pipeline_failures_latest/
vulkan_pipeline_failures_latest2/
quest_first_mv_vs.glsl
quest_mv_vs.glsl
legacy/
hostpid/
patches/
/state/
/dist/*
/hostpid/libhostpid.so
+167
View File
@@ -0,0 +1,167 @@
# Repository guidance
- This is a CMake-based Dolphin/OpenXR fork. Native Steam Frame (AArch64) builds
use `scripts/compile-cross-sdk.sh`; the maintained build/deploy workflow and
local SDK details are in `docs/build-runbook.md`. Flatpak files under
`legacy/flatpak/` are archived, not the active Frame workflow.
- Recent `openxr-work` changes focus on Steam Frame OpenXR presentation and input.
`OpenXRPresentationMode` (Vulkan, Immersive, StereoScreen, or legacy settings)
is resolved in `VideoCommon/VideoConfig.cpp`; keep its config/UI and backend
paths in sync. StereoScreen reuses the SBS presenter path but submits separate
OpenXR quad layers; its shared submission/pose logic is in `VideoCommon/Present.*`
and `VideoCommon/VR/OpenXRManager.*`, with swapchain work in video backends.
OpenXR reference-space events are polled on the XR pacing thread; flat-screen pose
invalidation is deferred until `LocateViews` refreshes the video-thread view snapshot.
Preserve this ordering and the cache synchronization when changing recenter behavior.
- Config defaults are declared in `Source/Core/Core/Config/GraphicsSettings.cpp`;
the VR mode is `GFX_VR_PRESENTATION_MODE` (`Graphics.VR.PresentationMode`). Keep
its choices aligned with `DolphinQt/Config/VRConfigWidget.cpp` and
`DolphinQt/Settings/VRPane.cpp`; runtime mode resolution is in
`VideoCommon/VideoConfig.cpp`.
- XR heartbeat is `GFX_VR_EAGER_HEARTBEAT` (`Graphics.VR.EagerHeartbeat`), declared
in `GraphicsSettings.cpp` and loaded in `VideoConfig.cpp`. `true` is Eager (submit
each HMD refresh, reusing the last frame); `false` is Lazy (pace submissions to game
frames so PC runtime motion smoothing can engage).
- Steam Frame presentation fixes (SMG2, 2026-10-04): the XR pacing loop does not
wait for new game content after `xrWaitFrame`; that removed a significant source
of hitching. StereoScreen also batches both Vulkan eye blits, waits once for GPU
completion, releases both images, then publishes the quad layers. Submitted but
unfinished eye writes produced conspicuous doubling/stale-image hiccups on Frame;
the completed-pair handoff resolved them in headset testing at 2x/120 Hz. Keep
this completion wait even when timeline semaphores are enabled. It trades some
CPU/GPU overlap for correct image delivery. `PresentBackbuffer` already advances
frame resources; the stereo submit must not advance them again.
- `m_video_handoff_mutex` excludes `xrEndFrame` from the video's blit/completion/
release/publish transaction. The previous atomic flag had a check-to-submit race.
Keep the handoff -> publish/graphics-queue lock order; never take the handoff
lock while holding either of those other locks. Do not hold the graphics-queue
lock during the GPU-completion wait.
- Investigation evidence: 16699 XFB copies showed no detected gameplay source,
GPU-submit, XR display-time reversal, or eye-ID mismatch, while CPU-side handoff
locking alone did not cure doubling. SteamVR motion smoothing was already
ForceOff (`motionSmoothingOverride=2`); reprojection counts did not establish
temporal blending. GPU readbacks accounted for long waits and 1x improved the
remaining isolated drops. Keep 120 Hz for comparison; refresh-rate mismatch was
already investigated. Temporary timing/order captures and analyzers were removed
after the fix. Desktop mirroring is forced off and its Qt options are hidden.
- Frame controller changes span `Common/VR/OpenXRInputState.h`,
`InputCommon/ControllerInterface/OpenXR/OpenXR.cpp`, Vulkan/OpenXR session setup,
the Qt mapping UI, and `Data/Sys/Profiles/`. For Frame controllers, Flat Vulkan
uses SDL/Steam Input; StereoScreen and Immersive VR use OpenXR controller actions.
Preserve this mode-dependent split. Keep profile defaults and UI/controller
loading order aligned.
- Open issue (tabled while focusing on StereoScreen): Flat-mode orientation pointing
through SDL is unresolved. The Frame's `SDL/0/Steam Frame Controllers` provides
button/axis inputs, but the diagnostic trace found no SDL Accel/Gyro inputs and
sensor values stayed zero while the user rotated the controller. The captured trace
did show d-pad, trigger, and stick events, so it did not reproduce total SDL input
loss. Keep the thumbstick IR fallback; do not assume SDL sensor support.
- Frame audio quirk (2026-10-11): AudioCommon sends stereo through Cubeb/PipeWire;
SteamOS WirePlumber creates a `spatialize_filter_chain` for output streams when the
built-in speaker sink is default. `node.stream.enable-spatial-audio` is a global
setting, and the current policy has no per-application opt-out. Do not change this
global setting for Baiji; leave the UI-position spatialization documented as a quirk
unless Frame exposes a supported per-stream opt-out.
- Baiji is a Steam Frame-only Dolphin cut; changes may be intentionally more
aggressive than upstream Dolphin. This branch is temporary and can end once
upstream incorporates its features. Inspect Baiji data only under
`~/.config/baiji` and `~/.local/share/baiji`; ignore the separate Dolphin
installation/config. Legacy INI filenames may remain, but Dolphin installation
or user-data paths inside Baiji config are suspicious and must not be followed.
- Never modify Frame/SteamOS/SteamVR system or runtime settings as part of Baiji
development, testing, or deployment, even for temporary experiments. Treat
`~/.config/openvr/config/steamvr.vrsettings` and other non-Baiji settings as
read-only; keep testing changes within Baiji-owned code, binaries, and config.
- Frame build: from the repository root run
`INSTALL_PREFIX=/home/steamos/baiji ./scripts/compile-cross-sdk.sh`, then
`./scripts/deploy-frame.sh frame`. The build uses Podman, installs the AArch64 KDE SDK
into ignored `state/` via Flatpak when missing, rebuilds the image when
`Containerfile.cross` changes, and stages to
`state/stage-frame/`. Its persistent build/cache are
`state/build-baiji/` and `state/ccache-cross-sdk/`. It configures
`ENABLE_TESTS=OFF`; this is not a test build.
- `scripts/compile.sh [native|aarch64] [target...]` is the general container build
helper; it defaults to `native` and `dolphin-emu`. It uses cached local Podman
images `baijisteamvr-build:amd64` and `baijisteamvr-build:arm64` and does not rebuild
the container environment for each code build. Run `scripts/build-env.sh` for a
missing image or after changing `Containerfile.build`; normal `compile.sh` builds
reuse the tagged images and ignored `state/build-*` CMake build directories.
`state/ccache/` also persists between builds and is wired through CMake compiler
launchers. Do not clear either cache for normal edits; a changed compiler/image may
cause one full rebuild, but later builds should be incremental. Use
`compile-cross-sdk.sh` for the maintained Steam Frame SDK/staging workflow above.
- `scripts/compile.sh aarch64 dolphin-emu` builds an arm64 executable at
`state/build-aarch64/Binaries/baiji`, but this uses the Ubuntu 26.04 build image
(glibc 2.43). The Frame has glibc 2.39, so do not copy that raw executable there;
use `compile-cross-sdk.sh` and its Frame-compatible SDK/staging output instead.
- For binary-only Frame builds, atomically replace
`~/baiji/bin/baiji` with `state/stage-frame/home/steamos/baiji/bin/baiji`; this is
the emulator executable launched by `~/baiji/bin/baiji-vr` from the Big Picture /
Gamescope shortcut. Leave `baiji-vr` in place. Use `deploy-frame.sh` when staged
libraries/assets also changed.
The user promoted the current Frame build to known-good on 2026-10-04 despite
uncertainty about intermittent controller input and reported performance improvement.
Preserve `~/baiji/bin/baiji-known-good`; only replace it on explicit user promotion.
To restore the Big Picture shortcut to that build, copy it back to `~/baiji/bin/baiji`.
We cannot test headset controls directly from the development host: collaborate with
the user on debug runs and retrieve logs over SSH.
- On the Frame, creating `~/.config/baiji/debug-logging` makes the existing
`baiji-vr` shortcut enable verbose Video/OpenXR/Controller Interface (`CI`) logging.
Retrieve `~/.local/share/baiji/Logs/dolphin.log` and
`~/.local/share/baiji/Logs/baiji-launcher.log` over SSH; remove the marker to
return to normal logging. Collaborate with the user for headset input tests, then
inspect the resulting logs.
- The configured SSH alias is `frame`. If it is absent on a development machine,
ask the user to create it; it makes build transfer and device debugging much easier.
- Steam Frame debugging guidance, especially core-dump access and processing, is at
<https://partner.steamgames.com/doc/steamhardware/steamframe/debugging>; consult it
before retrieving or processing Frame crash dumps.
- The deploy script copies Baiji-named files under `~/baiji` on the target. CLI
smoke tests are documented in `docs/build-runbook.md`; the GUI launcher is
`baiji-vr`.
- For a host Linux VR build, configure with
`cmake -S . -B Build -DENABLE_VR=ON -DENABLE_VULKAN=ON`, then build with
`cmake --build Build --target dolphin-emu -j "$(nproc)"`.
- Unit tests are enabled by default in the root CMake configuration, but the
Frame cross-build disables them. In a test-enabled build, use
`cmake --build <build-dir> --target unittests`; to run a focused GoogleTest,
build `tests` and invoke `<build-dir>/Binaries/Tests/tests --gtest_filter=<filter>`.
- `Tools/lint.sh` checks changed/staged source files and requires clang-format
19.1. See `Contributing.md` for formatting details.
- Before changing submodules, inspect their worktrees and preserve local edits.
`scripts/fix-submodules.sh` force-checks out fmt and OpenXR revisions; the
runbook marks it for reviewed use on a fresh checkout only.
- Keep build/cache/staging outputs in ignored `state/` and `dist/`. Do not deploy
or alter unrelated existing Frame binaries, user data, or Steam shortcuts;
follow the runbook's Baiji-only paths. Do not publish from this checkout unless
explicitly requested.
- This project is not particularly worried about linting. Don't worry
about trying to run clang-format. Nor is there any practical way to
unit test most of the work this project is doing as it is all UI work.
## External technical references
- [Steam Frame developer setup](https://partner.steamgames.com/doc/steamhardware/steamframe/setup)
covers Developer Mode, SSH/ADB access, and recommended beta channels; consult it
when setting up or troubleshooting access to a Frame development headset.
- [Steam Frame OpenXR engine integrations](https://partner.steamgames.com/doc/steamhardware/steamframe/engines)
collects platform-specific OpenXR integration guidance for supported engines.
Start here when adapting general OpenXR behavior to the Frame runtime.
- [Steam Frame custom engine integration](https://partner.steamgames.com/doc/steamhardware/steamframe/engines/custom)
is the more direct reference for applications integrating OpenXR without one of
the documented game engines; check its runtime and extension guidance for
Frame-specific requirements.
- [Steam Frame Input](https://partner.steamgames.com/doc/steamhardware/steamframe/input)
documents the headset's controller/input behavior and is useful when investigating
controller profiles, bindings, or input expectations on-device.
- [Khronos OpenXR Tutorial](https://openxr-tutorial.com/)
provides practical, API-level examples of initialization, graphics/swapchains,
actions, and extensions across platforms; use it for implementation patterns, then
verify runtime-specific support separately.
- [Khronos OpenXR 1.1 Specification](https://registry.khronos.org/OpenXR/specs/1.1/html/xrspec.html)
is the normative reference for API semantics, synchronization, and extension behavior;
consult it when tutorial examples leave behavior ambiguous.
- [Khronos OpenXR SDK Source](https://github.com/KhronosGroup/OpenXR-SDK-Source)
contains the OpenXR loader and SDK source; use it to investigate loader behavior or
SDK integration details, not as a substitute for checking extensions exposed by the
Frame runtime.
+34
View File
@@ -0,0 +1,34 @@
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index b26bbcc..f687560 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -166 +166 @@ option(
- ON
+ OFF
@@ -167,0 +168,4 @@ option(
+if(NOT BUILD_LOADER_WITH_EXCEPTION_HANDLING)
+ add_definitions(-DXRLOADER_DISABLE_EXCEPTION_HANDLING)
+ add_definitions(-DJSON_USE_EXCEPTIONS=0)
+endif()
diff --git a/src/loader/CMakeLists.txt b/src/loader/CMakeLists.txt
index fead046..9db503f 100644
--- a/src/loader/CMakeLists.txt
+++ b/src/loader/CMakeLists.txt
@@ -157,0 +158,5 @@ endif()
+# Parent project (Dolphin) builds with -fno-exceptions, but a few loader
+# destructors still contain unconditional catch(...) blocks. Re-enable
+# exceptions for this target only so those compile.
+target_compile_options(openxr_loader PRIVATE -fexceptions)
+
diff --git a/src/loader/api_layer_interface.cpp b/src/loader/api_layer_interface.cpp
index b8f0881..90f5a31 100644
--- a/src/loader/api_layer_interface.cpp
+++ b/src/loader/api_layer_interface.cpp
@@ -455,0 +456 @@ ApiLayerInterface::~ApiLayerInterface() {
+#ifndef XRLOADER_DISABLE_EXCEPTION_HANDLING
@@ -456,0 +458 @@ ApiLayerInterface::~ApiLayerInterface() {
+#endif
@@ -459,0 +462 @@ ApiLayerInterface::~ApiLayerInterface() {
+#ifndef XRLOADER_DISABLE_EXCEPTION_HANDLING
@@ -465,0 +469 @@ ApiLayerInterface::~ApiLayerInterface() {
+#endif
+70 -14
View File
@@ -13,7 +13,7 @@ endif()
# This is inserted into the Info.plist as well.
set(CMAKE_OSX_DEPLOYMENT_TARGET "11.0.0" CACHE STRING "")
set(CMAKE_USER_MAKE_RULES_OVERRIDE "${CMAKE_CURRENT_SOURCE_DIR}/CMake/FlagsOverride.cmake")
set(CMAKE_USER_MAKE_RULES_OVERRIDE "CMake/FlagsOverride.cmake")
# CMake 3.28 and later scan c++ source files for module imports by default. Since we don't use
# modules scanning is pointless, so disable it. This also prevents Clang from generating an error
@@ -23,6 +23,10 @@ set(CMAKE_CXX_SCAN_FOR_MODULES OFF)
project(dolphin-emu)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
add_compile_definitions(BAIJI_STEAMVR)
endif()
if (CMAKE_VERSION VERSION_LESS "3.25" AND CMAKE_SYSTEM_NAME MATCHES "Linux")
set(LINUX TRUE)
endif()
@@ -61,7 +65,7 @@ endif()
# Name of the Dolphin distributor. If you redistribute Dolphin builds (forks,
# unofficial builds) please consider identifying your distribution with a
# unique name here.
set(DISTRIBUTOR "None" CACHE STRING "Name of the distributor.")
set(DISTRIBUTOR "BaijiSteamVR" CACHE STRING "Name of the distributor.")
set(DOLPHIN_DEFAULT_UPDATE_TRACK "" CACHE STRING "Name of the default update track. If empty, disables auto-update.")
@@ -171,7 +175,7 @@ include(RemoveCompileFlag)
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
# Set up paths
set(datadir ${CMAKE_INSTALL_FULL_DATADIR}/dolphin-emu CACHE PATH "datadir")
set(datadir ${CMAKE_INSTALL_FULL_DATADIR}/baiji CACHE PATH "datadir")
add_definitions(-DDATA_DIR="${datadir}/")
if(CMAKE_SYSROOT)
@@ -490,6 +494,13 @@ endif()
# TODO: We should have options for dependencies included in the externals to
# override autodetection of system libraries and force the usage of the
# externals.
if (ENABLE_QT AND MSVC)
# Windows has no system Qt6 package, so use the vendored one from Externals/Qt (locked to 6.5.1).
# On Linux we use the system Qt6 package instead: mixing the vendored Qt6.5.1 (which lacks a DBus
# module) with a system Qt6 for DBus fails, since CMake's Qt6 package requires all found
# components to share the exact same version.
list(PREPEND CMAKE_PREFIX_PATH "${CMAKE_SOURCE_DIR}/Externals/Qt/Qt6.5.1/x64")
endif()
include(CheckLib)
include(CheckCXXSourceRuns)
@@ -677,7 +688,46 @@ if(ENABLE_VR)
set(BUILD_CONFORMANCE_TESTS OFF CACHE BOOL "" FORCE)
set(BUILD_SDK_TESTS OFF CACHE BOOL "" FORCE)
set(DYNAMIC_LOADER OFF CACHE BOOL "" FORCE)
add_subdirectory(Externals/OpenXR "${CMAKE_BINARY_DIR}/Externals/OpenXR" EXCLUDE_FROM_ALL)
# Keep the Khronos SDK submodule pinned upstream and apply Baiji's narrow
# no-exceptions loader compatibility patch to a binary-tree copy. This also
# works when the checked-out source tree is read-only.
set(OPENXR_PATCHED_SOURCE_DIR "${CMAKE_BINARY_DIR}/OpenXR-patched-source")
file(REMOVE_RECURSE "${OPENXR_PATCHED_SOURCE_DIR}")
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/Externals/OpenXR/"
DESTINATION "${OPENXR_PATCHED_SOURCE_DIR}"
PATTERN ".git" EXCLUDE)
find_program(OPENXR_PATCH_GIT_EXECUTABLE git)
if(NOT OPENXR_PATCH_GIT_EXECUTABLE)
message(FATAL_ERROR "Git is required to prepare the OpenXR SDK.")
endif()
set(OPENXR_COMPATIBILITY_PATCH
"${CMAKE_CURRENT_SOURCE_DIR}/CMake/OpenXR-Loader-Exceptions.patch")
execute_process(
COMMAND "${OPENXR_PATCH_GIT_EXECUTABLE}" -C "${OPENXR_PATCHED_SOURCE_DIR}" apply
--unidiff-zero --check "${OPENXR_COMPATIBILITY_PATCH}"
RESULT_VARIABLE OPENXR_PATCH_CHECK_RESULT
OUTPUT_VARIABLE OPENXR_PATCH_CHECK_OUTPUT
ERROR_VARIABLE OPENXR_PATCH_CHECK_ERROR)
if(NOT OPENXR_PATCH_CHECK_RESULT EQUAL 0)
message(FATAL_ERROR
"OpenXR compatibility patch does not match the pinned SDK.\n"
"${OPENXR_PATCH_CHECK_OUTPUT}\n${OPENXR_PATCH_CHECK_ERROR}")
endif()
execute_process(
COMMAND "${OPENXR_PATCH_GIT_EXECUTABLE}" -C "${OPENXR_PATCHED_SOURCE_DIR}" apply
--unidiff-zero "${OPENXR_COMPATIBILITY_PATCH}"
RESULT_VARIABLE OPENXR_PATCH_APPLY_RESULT
OUTPUT_VARIABLE OPENXR_PATCH_APPLY_OUTPUT
ERROR_VARIABLE OPENXR_PATCH_APPLY_ERROR)
if(NOT OPENXR_PATCH_APPLY_RESULT EQUAL 0)
message(FATAL_ERROR
"Could not apply OpenXR compatibility patch.\n"
"${OPENXR_PATCH_APPLY_OUTPUT}\n${OPENXR_PATCH_APPLY_ERROR}")
endif()
add_subdirectory("${OPENXR_PATCHED_SOURCE_DIR}" "${CMAKE_BINARY_DIR}/Externals/OpenXR"
EXCLUDE_FROM_ALL)
endif()
if(NOT (WIN32 AND _M_ARM_64))
@@ -881,22 +931,28 @@ if(NOT CMAKE_SYSTEM_NAME MATCHES "Linux|FreeBSD|OpenBSD|Darwin")
endif()
if(CMAKE_SYSTEM_NAME MATCHES "Linux|FreeBSD|OpenBSD")
# Install the application icon and menu item
install(FILES Data/dolphin-emu.svg
DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/scalable/apps)
install(FILES Data/dolphin-emu.png
DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/256x256/apps)
install(FILES Data/dolphin-emu.desktop
DESTINATION ${CMAKE_INSTALL_PREFIX}/share/applications)
install(FILES Data/baiji.png
DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/256x256/apps)
install(FILES Data/org.baijisteamvr.BaijiSteamVR.desktop
DESTINATION ${CMAKE_INSTALL_DATADIR}/applications)
# Install manpages
install(FILES Data/dolphin-emu.6
install(FILES Data/baiji.6
DESTINATION ${CMAKE_INSTALL_MANDIR}/man6)
install(FILES Data/dolphin-emu-nogui.6
install(FILES Data/baiji-nogui.6
DESTINATION ${CMAKE_INSTALL_MANDIR}/man6)
install(PROGRAMS scripts/baiji-vr DESTINATION ${CMAKE_INSTALL_BINDIR})
endif()
# packaging information
set(CPACK_PACKAGE_NAME "dolphin-emu")
set(CPACK_PACKAGE_VENDOR "Dolphin Team")
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
set(CPACK_PACKAGE_NAME "baijisteamvr")
set(CPACK_PACKAGE_VENDOR "BaijiSteamVR")
set(CPACK_PACKAGE_CONTACT "https://github.com/thejerf/baijiSteamVR")
else()
set(CPACK_PACKAGE_NAME "dolphin-emu")
set(CPACK_PACKAGE_VENDOR "Dolphin Team")
set(CPACK_PACKAGE_CONTACT "dolphinxr@example.com")
endif()
set(CPACK_PACKAGE_VERSION_MAJOR ${DOLPHIN_VERSION_MAJOR})
set(CPACK_PACKAGE_VERSION_MINOR ${DOLPHIN_VERSION_MINOR})
set(CPACK_PACKAGE_VERSION_PATCH ${DOLPHIN_VERSION_PATCH})
+61
View File
@@ -0,0 +1,61 @@
FROM ubuntu:26.04
ENV DEBIAN_FRONTEND=noninteractive
# BaijiSteamVR's Linux build dependencies, plus ccache and ninja-build.
RUN apt-get update \
&& apt-get install -y \
build-essential \
ccache \
clang \
cmake \
file \
ninja-build \
qt6-base-dev \
qt6-base-private-dev \
qt6-svg-dev \
pkg-config \
libgl1-mesa-dev \
libx11-dev \
libxrandr-dev \
libxi-dev \
libegl1-mesa-dev \
libavcodec-dev \
libavformat-dev \
libavutil-dev \
libswresample-dev \
libswscale-dev \
libudev-dev \
libevdev-dev \
libsdl3-dev \
glslang-dev \
glslang-tools \
libpugixml-dev \
libenet-dev \
libxxhash-dev \
libbz2-dev \
liblzma-dev \
libzstd-dev \
zlib1g-dev \
libminizip-ng-dev \
liblzo2-dev \
liblz4-dev \
libspng-dev \
libcubeb-dev \
libusb-1.0-0-dev \
libsfml-dev \
libminiupnpc-dev \
libcurl4-openssl-dev \
libhidapi-dev \
libsystemd-dev \
libgtest-dev \
libasound2-dev \
libpulse-dev \
llvm-dev \
libbluetooth-dev \
gettext \
libvulkan-dev \
vulkan-tools \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /work
+49
View File
@@ -0,0 +1,49 @@
FROM docker.io/library/ubuntu:26.04
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
cmake \
ninja-build \
meson \
git \
ccache \
pkgconf \
python3 \
gettext \
file \
curl \
ca-certificates \
qemu-user \
gcc-aarch64-linux-gnu \
g++-aarch64-linux-gnu \
binutils-aarch64-linux-gnu \
&& rm -rf /var/lib/apt/lists/*
# Wrapper for CMake try_run and AArch64 SDK tools imported from Qt CMake packages.
RUN printf '%s\n' \
'#!/bin/sh' \
'if [ "$0" = "/usr/local/bin/qemu-aarch64-wrapper" ]; then' \
' exec /usr/bin/qemu-aarch64 "$@"' \
'fi' \
'case "$0" in' \
' /usr/bin/*) target="/sysroot/usr/bin/${0##*/}" ;;' \
' /usr/lib/libexec/*) target="/sysroot/usr/lib/libexec/${0##*/}" ;;' \
' /usr/lib/aarch64-linux-gnu/libexec/kf6/*) target="/sysroot/usr/lib/aarch64-linux-gnu/libexec/kf6/${0##*/}" ;;' \
' *) exec /usr/bin/qemu-aarch64 "$@" ;;' \
'esac' \
'exec /usr/bin/qemu-aarch64 "$target" "$@"' \
> /usr/local/bin/qemu-aarch64-wrapper && chmod +x /usr/local/bin/qemu-aarch64-wrapper
# The KDE SDK's glibc linker scripts use absolute AArch64 library paths.
RUN ln -sfn /sysroot/usr/lib/aarch64-linux-gnu/libm.so.6 \
/usr/lib/aarch64-linux-gnu/libm.so.6 && \
ln -sfn /sysroot/usr/lib/aarch64-linux-gnu/libmvec.so.1 \
/usr/lib/aarch64-linux-gnu/libmvec.so.1
# Qt package exports also check their installed plugin paths during configuration.
RUN ln -sfn /sysroot/usr/lib/plugins /usr/lib/plugins
ENV QEMU_LD_PREFIX=/sysroot
ENV CCACHE_DIR=/run/ccache
WORKDIR /work
+62 -302
View File
@@ -1,302 +1,62 @@
# <a name="main-section-overview"></a>Dolphin Coding Style & Legal Requirements
- [Legal](#legal)
- [Coding style introduction](#introduction)
- [C++ coding style and formatting](#cpp-coding-style-and-formatting)
- [C++ code-specific guidelines](#cpp-code-specific-guidelines)
- [Android](#android)
- [Help](#help)
# <a name="legal"></a>Legal
Summary:
- [Trade secrets](#trade-secrets)
- [Code licensing](#code-licensing)
## <a name="trade-secrets"></a>Trade secrets
Following all relevant laws is of utmost importance for an emulation project like Dolphin.
If you know any confidential information related to the GameCube, Wii, or Triforce, either because you signed a non-disclosure agreement or because you looked at leaked materials, we ask that you don't contribute code to Dolphin **at all**. While accepting code from contributors who know confidential information is legal if the code is unrelated to the confidential information, we refuse to accept code from such contributors because it greatly increases our review burden and increases the legal risk we take.
Also, this probably goes without saying, but piracy is strictly forbidden both on GitHub and in all other Dolphin channels.
## <a name="code-licensing"></a>Code licensing
If you make any contributions to Dolphin after December 1st, 2014, you are agreeing that any code you have contributed will be licensed under the GNU GPL version 2 (or any later version).
# <a name="introduction"></a>Coding style introduction
Summary:
- [Aims](#intro-aims)
- [Checking and fixing formatting issues](#intro-formatting-issues)
## <a name="intro-aims"></a>Aims
This guide is for developers who wish to contribute to the Dolphin codebase. It details how to properly style and format code for this project. This guide also offers suggestions on specific functions and other elements that may be used in code.
Following this guide and formatting your code as detailed will likely get your pull request merged much faster than if you don't (assuming the code itself has no mistakes).
This project uses clang-format 19.1 to check for common style issues. In case of conflicts between this guide and clang-format rules, the latter should be followed instead of this guide.
## <a name="intro-formatting-issues"></a>Checking and fixing formatting issues
Windows users need to be careful about line endings. Windows users should configure git to checkout UNIX-style line endings to keep clang-format simple.
In most cases, clang-format can and **should** be used to automatically reformat code and solve most formatting issues.
- To run clang-format on all staged files:
```
git diff --cached --name-only | grep -E '[.](cpp|h|mm)$' | xargs -I {} clang-format -i {}
```
- Formatting issues can be checked for before committing with a lint script that is included with the codebase. To enable it as a pre-commit hook (assuming you are in the repository root):
```
ln -s ../../Tools/lint.sh .git/hooks/pre-commit
```
- Alternatively, a custom git filter driver can be used to automatically and transparently reformat any changes:
```
git config filter.clang_format.smudge 'cat'
git config filter.clang_format.clean 'clang-format %f'
echo '/Source/Core/**/*.cpp filter=clang_format' >> .git/info/attributes
echo '/Source/Core/**/*.h filter=clang_format' >> .git/info/attributes
echo '/Source/Core/**/*.mm filter=clang_format' >> .git/info/attributes
```
- Visual Studio supports automatically formatting the current document according to the clang-format configuration by pressing <kbd>Control</kbd>+<kbd>K</kbd> followed by <kbd>Control</kbd>+<kbd>D</kbd> (or selecting Edit &rarr; Advanced &rarr; Format Document). This can be used without separately installing clang-format.
# <a name="cpp-coding-style-and-formatting"></a>C++ coding style and formatting
Summary:
- [General](#cpp-style-general)
- [Naming](#cpp-style-naming)
- [Conditionals](#cpp-style-conditionals)
- [Classes and structs](#cpp-style-classes-and-structs)
## <a name="cpp-style-general"></a>General
- Try to limit lines of code to a maximum of 100 characters.
- Note that this does not mean you should try and use all 100 characters every time you have the chance. Typically with well formatted code, you normally shouldn't hit a line count of anything over 80 or 90 characters.
- The indentation style we use is 2 spaces per level.
- The opening brace for namespaces, classes, functions, enums, structs, unions, conditionals, and loops go on the next line.
- With array initializer lists and lambda expressions it is OK to keep the brace on the same line.
- References and pointers have the ampersand or asterisk against the type name, not the variable name. Example: `int* var`, not `int *var`.
- Don't use multi-line comments (`/* Comment text */`), use single-line comments (`// Comment text`) instead.
- Don't collapse single line conditional or loop bodies onto the same line as its header. Put it on the next line.
- Yes:
```c++
if (condition)
return 0;
while (var != 0)
var--;
```
- No:
```c++
if (condition) return 0;
while (var != 0) var--;
```
## <a name="cpp-style-naming"></a>Naming
- All class, enum, function, and struct names should be in upper CamelCase. If the name contains an abbreviation uppercase it.
- `class SomeClassName`
- `enum IPCCommandType`
- All compile time constants should be fully uppercased. With constants that have more than one word in them, use an underscore to separate them.
- `constexpr double PI = 3.14159;`
- `constexpr int MAX_PATH = 260;`
- All variables should be lowercase with underscores separating the individual words in the name.
- `int this_variable_name;`
- Please do not use [Hungarian notation](https://en.wikipedia.org/wiki/Hungarian_notation) prefixes with variables. The only exceptions to this are the variable prefixes below.
- Global variables – `g_`
- Class variables – `m_`
- Static variables – `s_`
## <a name="cpp-style-conditionals"></a>Conditionals
- Do not leave `else` or `else if` conditions dangling unless the `if` condition lacks braces.
- Yes:
```c++
if (condition)
{
// code
}
else
{
// code
}
```
- Acceptable:
```c++
if (condition)
// code line
else
// code line
```
- No:
```c++
if (condition)
{
// code
}
else
// code line
```
## <a name="cpp-style-classes-and-structs"></a>Classes and structs
- If making a [POD](https://en.wikipedia.org/wiki/Passive_data_structure) type, use a `struct` for this. Use a `class` otherwise.
- Class layout should be in the order, `public`, `protected`, and then `private`.
- If one or more of these sections are not needed, then simply don't include them.
- For each of the above specified access levels, the contents of each should follow this given order: constructor, destructor, operator overloads, functions, then variables.
- When defining the variables, define `static` variables before the non-static ones.
```c++
class ExampleClass : public SomeParent
{
public:
ExampleClass(int x, int y);
int GetX() const;
int GetY() const;
protected:
virtual void SomeProtectedFunction() = 0;
static float s_some_variable;
private:
int m_x;
int m_y;
};
```
# <a name="cpp-code-specific-guidelines"></a>C++ code-specific guidelines
Summary:
- [General](#cpp-code-general)
- [Headers](#cpp-code-headers)
- [Loops](#cpp-code-loops)
- [Functions](#cpp-code-functions)
- [Classes and Structs](#cpp-code-classes-and-structs)
## <a name="cpp-code-general"></a>General
- The codebase currently uses C++20, though not all compilers support all C++20 features.
- See CMakeLists.txt "Enforce minimum compiler versions" for the currently supported compilers.
- Use the [nullptr](https://en.cppreference.com/w/cpp/language/nullptr) type over the macro `NULL`.
- If a [range-based for loop](https://en.cppreference.com/w/cpp/language/range-for) can be used instead of container iterators, use it.
- Obviously, try not to use `goto` unless you have a *really* good reason for it.
- If a compiler warning is found, please try and fix it.
- Try to avoid using raw pointers (pointers allocated with `new`) as much as possible. There are cases where using a raw pointer is unavoidable, and in these situations it is OK to use them. An example of this is functions from a C library that require them. In cases where it is avoidable, the STL usually has a means to solve this (`vector`, `unique_ptr`, etc).
- Do not use the `auto` keyword everywhere. While it's nice that the type can be determined by the compiler, it cannot be resolved at 'readtime' by the developer as easily. Use auto only in cases where it is obvious what the type being assigned is (note: 'obvious' means not having to open other files or reading the header file). Some situations where it is appropriate to use `auto` is when iterating over a `std::map` container in a foreach loop, or to shorten the length of container iterator variable declarations.
- Do not use `using namespace [x];` in headers. Try not to use it at all if you can.
- The preferred form of the increment and decrement operator in for-loops is prefix-form (e.g. `++var`).
## <a name="cpp-code-headers"></a>Headers
- If a header is not necessary in a certain source file, remove them.
- If you find duplicate includes of a certain header, remove it.
- When declaring includes in a source file, make sure they follow the given pattern:
- The header for the source file
- Standard library headers
- System-specific headers (these should also likely be in an `#ifdef` block unless the source file itself is system-specific).
- Other Dolphin source file headers
- Each of the above header sections should also be in alphabetical order
- Project source file headers should be included in a way that is relative to the `[Dolphin Root]/Source/Core` directory.
- This project uses `#pragma once` as header guards.
## <a name="cpp-code-loops"></a>Loops
- If an infinite loop is required, do not use `for (;;)`, use `while (true)`.
- Empty-bodied loops should use braces after their header, not a semicolon.
- Yes: `while (condition) {}`
- No: `while (condition);`
- For do-while loops, place 'while' on the same line as the closing brackets
```c++
do
{
// code
} while (false);
```
## <a name="cpp-code-functions"></a>Functions
- If a function parameter is a pointer or reference and its value or data isn't intended to be changed, please mark that parameter as `const`.
- Functions that specifically modify their parameters should have the respective parameter(s) marked as a pointer so that the variables being modified are syntactically obvious.
- What not to do:
```c++
template<class T>
inline void Clamp(T& val, const T& min, const T& max)
{
if (val < min)
val = min;
else if (val > max)
val = max;
}
```
Example call: `Clamp(var, 1000, 5000);`
- What to do:
```c++
template<class T>
inline void Clamp(T* val, const T& min, const T& max)
{
if (*val < min)
*val = min;
else if (*val > max)
*val = max;
}
```
Example call: `Clamp(&var, 1000, 5000);`
- Class member functions that you do not want to be overridden in inheriting classes should be marked with the `final` specifier.
```c++
class ClassName : ParentClass
{
public:
void Update() final;
};
```
- Overridden member functions that can also be inherited should be marked with the `override` specifier to make it easier to see which functions belong to the parent class.
```c++
class ClassName : ParentClass
{
public:
void Update() override;
};
```
## <a name="cpp-code-classes-and-structs"></a>Classes and structs
- Classes and structs that are not intended to be extended through inheritance should be marked with the `final` specifier.
```c++
class ClassName final : ParentClass
{
// Class definitions
};
```
# <a name="android"></a>Android
If you are using Kotlin, just use the built-in official Kotlin code style.
To install the Java code style in Android Studio, select the gear icon in the Code Style settings as shown, select `Import Scheme...` and select `dolphin/Source/Android/code-style-java.xml`. The Code Style menu should look like this when complete. ![Code Style Window][code-style]
You can now select any section of code and press `Ctrl + Alt + L` to automatically format it.
# <a name="help"></a>Help
If you have any questions about Dolphin's development or would like some help, Dolphin developers use `#dolphin-emu @ irc.libera.chat` to communicate. If you are new to IRC, [Libera.Chat has resources to get started chatting with IRC.](https://libera.chat/)
[code-style]: https://i.imgur.com/3b3UBhb.png
# Contributing to Baiji
In an era of AI, the value you bring to a PR
submitted to any project *IS NOT THE CODE*. Code may not be free yet,
but its value is rapidly dropping.
Or, in other words, I have an AI too. The utility to me of just
shoving some AI code at the project is fairly limited.
The value you bring is [in the
*TESTING*](https://jerf.org/iri/post/2026/what_value_code_in_ai_era/).
You may develop code in any way you like for Baiji, but the value is
in the testing, not a code dump.
Once you have a tested branch in your local repo(s), the AI can walk
you through the process of creating a PR if you don't already
know. The PR prompt will hopefull guide you in this as well, but
please tell us all what testing you have done on your PR.
That doesn't mean you need to have tested every possible interaction
with every possible feature on every possible game. Goodness knows
Baiji's work doesn't even remotely rise to that standard either! But
it is very helpful to know what testing has and has not been done, so
we can know what to look out for, and others may know to make their
own PRs against your PR. Do not be shy to say "I haven't tested this
with X". The space of "all possible Wii and Gamecube games" is
huge.
Because the true value of a PR is testing, note that _testing_ someone
else's PR can be as valuable or even more valuable than coming up with
one of your own. Before starting a PR check the PR tab and see if
there's anything either close to your work or is what you'd have
made. If so, please join with that PR rather than source a new
one by building that PR yourself and running it on your local Steam
Frame. There is nothing as valuable as the _second_ pair of eyes on a
PR!
# Baiji's Scope
The scope of Baiji is:
* The UI as it is presented in Steam OS.
* The stereoscopic and VR views.
The Baiji project will not fix game-specific emulation bugs, unless
someone can make an extremely good case for why it really is a Steam
Frame-specific issue. Fixing emulation bugs is a frought process of
testing hundreds of games for regressions, having deep knowledge of
the relevant systems, and testing, testing, testing. Resources Baiji
does not have.
At most, if someone wants to port in the latest Dolphin work, and then
test it and see that it is some sort of improvement, I might take
that. But it's the only emulation improvement we're going to take.
As such, all Issues filed about games will be closed without
work. Replicate them in the latest official Dolphin release and file
them there, if they are still a problem.
Plus this keeps us out of hot water with Nintendo. We haven't touched
the parts of Dolphin Nintendo cares about.
@@ -0,0 +1,27 @@
[Profile]
Device = OpenXR/0/OpenXR Controller
Buttons/A = `Right Button A`
Buttons/B = `Right Button B`
Buttons/X = `Right Button X`
Buttons/Y = `Right Button Y`
Buttons/Z = `Right Button Squeeze`
Buttons/Start = `Right Button Menu`
Main Stick/Up = `Left Thumbstick Y+`
Main Stick/Down = `Left Thumbstick Y-`
Main Stick/Left = `Left Thumbstick X-`
Main Stick/Right = `Left Thumbstick X+`
Main Stick/Calibration = 100.00
C-Stick/Up = `Right Thumbstick Y+`
C-Stick/Down = `Right Thumbstick Y-`
C-Stick/Left = `Right Thumbstick X-`
C-Stick/Right = `Right Thumbstick X+`
C-Stick/Calibration = 100.00
Triggers/L = `Left Button Trigger`
Triggers/R = `Right Button Trigger`
Triggers/L-Analog = `Left Trigger`
Triggers/R-Analog = `Right Trigger`
D-Pad/Up = `Left D-Pad Up`
D-Pad/Down = `Left D-Pad Down`
D-Pad/Left = `Left D-Pad Left`
D-Pad/Right = `Left D-Pad Right`
Rumble/Motor = Motor
@@ -0,0 +1,5 @@
[Profile]
Device = OpenXR/0/OpenXR Controller
; Right Button Menu is reserved for GameCube Start.
General/Stop = `Left Button View`
; Steam Frame handles headset recentering; leave the application hotkey unbound.
@@ -0,0 +1,31 @@
[Profile]
Device = OpenXR/0/OpenXR Controller
Buttons/A = `Right Button A`
Buttons/B = `Right Trigger`
Buttons/1 = `Right Button X`
Buttons/2 = `Right Button Y`
Buttons/- = `Left Button Bumper`
Buttons/+ = `Right Button Bumper`
Buttons/Home = `Left Button System`
D-Pad/Up = `Left D-Pad Up`
D-Pad/Down = `Left D-Pad Down`
D-Pad/Left = `Left D-Pad Left`
D-Pad/Right = `Left D-Pad Right`
IR/Up = `Right Thumbstick Y-`
IR/Down = `Right Thumbstick Y+`
IR/Left = `Right Thumbstick X-`
IR/Right = `Right Thumbstick X+`
IR/Relative Input = False
Shake/X = `Right Button Squeeze`
Shake/Y = `Right Button Squeeze`
Shake/Z = `Right Button Squeeze`
IMUIR/Enabled = False
Extension = Nunchuk
Nunchuk/Buttons/C = `Left Button Squeeze`
Nunchuk/Buttons/Z = `Left Trigger`
Nunchuk/Stick/Up = `Left Thumbstick Y+`
Nunchuk/Stick/Down = `Left Thumbstick Y-`
Nunchuk/Stick/Left = `Left Thumbstick X-`
Nunchuk/Stick/Right = `Left Thumbstick X+`
Nunchuk/Stick/Calibration = 100 100 100 100 100 100 100 100
Rumble/Motor = Motor
@@ -0,0 +1,24 @@
[Profile]
Device = OpenXR/0/OpenXR Controller
Buttons/A = `Right Button A`
Buttons/B = `Right Trigger`
Buttons/1 = `Right Button X`
Buttons/2 = `Right Button Y`
Buttons/- = `Left Button View`
Buttons/+ = `Right Button Menu`
Buttons/Home = `Left Button System`
D-Pad/Up = `Left D-Pad Up`
D-Pad/Down = `Left D-Pad Down`
D-Pad/Left = `Left D-Pad Left`
D-Pad/Right = `Left D-Pad Right`
IR/Up = `Right Thumbstick Y-`
IR/Down = `Right Thumbstick Y+`
IR/Left = `Right Thumbstick X-`
IR/Right = `Right Thumbstick X+`
IR/Relative Input = False
Shake/X = `Right Button Squeeze`
Shake/Y = `Right Button Squeeze`
Shake/Z = `Right Button Squeeze`
IMUIR/Enabled = False
Extension = None
Rumble/Motor = Motor
Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 548 KiB

+29
View File
@@ -0,0 +1,29 @@
.Dd October 4, 2026
.Dt BAIJI-NOGUI 6
.Os
.Sh NAME
.Nm baiji-nogui
.Nd headless GameCube and Wii emulator
.Sh SYNOPSIS
.Nm
.Op Fl hv
.Op Fl e Ar file
.Sh DESCRIPTION
.Nm
runs BaijiSteamVR without a graphical user interface.
.Sh OPTIONS
.Bl -tag -width Ds
.It Fl e Ar file , Fl Fl exec= Ns Ar file
Load the specified file.
.It Fl h , Fl Fl help
Print a help message.
.It Fl v , Fl Fl version
Print version and exit.
.El
.Sh FILES
.Bl -tag -width Ds
.It Pa $HOME/.local/share/baiji
Default application data directory.
.It Pa $HOME/.config/baiji
Default configuration directory.
.El
+48
View File
@@ -0,0 +1,48 @@
.Dd October 4, 2026
.Dt BAIJI 6
.Os
.Sh NAME
.Nm baiji
.Nd GameCube and Wii emulator for Steam Frame
.Sh SYNOPSIS
.Nm
.Op Fl bdhl
.Op Fl a Ar audio
.Op Fl c Ar str
.Op Fl e Ar file
.Op Fl m Ar file
.Op Fl u Ar path
.Op Fl v Ar video
.Sh DESCRIPTION
.Nm
is a GameCube and Wii emulator with a graphical user interface.
.Sh OPTIONS
.Bl -tag -width Ds
.It Fl a Ar audio , Fl Fl audio_emulation= Ns Ar audio
Select low-level or high-level audio emulation.
.It Fl b , Fl Fl batch
Run without the user interface.
.It Fl c Ar text , Fl Fl confirm= Ns Ar text
Set confirmation on stop.
.It Fl d , Fl Fl debugger
Open the debugger.
.It Fl e Ar file , Fl Fl exec= Ns Ar file
Load the specified file.
.It Fl h , Fl Fl help
Print a help message.
.It Fl l , Fl Fl logger
Open the logger.
.It Fl m Ar file , Fl Fl movie= Ns Ar file
Play a movie file.
.It Fl u Ar path , Fl Fl user= Ns Ar path
Set the user folder path.
.It Fl v , Fl Fl video_backend= Ns Ar video
Select a video backend.
.El
.Sh FILES
.Bl -tag -width Ds
.It Pa $HOME/.local/share/baiji
Default application data directory.
.It Pa $HOME/.config/baiji
Default configuration directory.
.El
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

@@ -0,0 +1,12 @@
[Desktop Entry]
Version=1.0
Type=Application
Name=BaijiSteamVR
GenericName=VR GameCube/Wii Emulator
Comment=GameCube and Wii emulator for Steam Frame
Icon=baiji
Exec=/home/steamos/baiji/bin/baiji-vr
TryExec=/home/steamos/baiji/bin/baiji-vr
Terminal=false
Categories=Game;Emulator;
StartupWMClass=BaijiSteamVR
+66
View File
@@ -0,0 +1,66 @@
FROM ubuntu:26.04
RUN apt-get update \
&& apt-get install -y \
build-essential \
clang \
cmake \
file \
qt6-base-dev \
qt6-base-private-dev \
qt6-svg-dev \
pkg-config \
libgl1-mesa-dev \
libx11-dev \
libxrandr-dev \
libxi-dev \
libegl1-mesa-dev \
libavcodec-dev \
libavformat-dev \
libavutil-dev \
libswresample-dev \
libswscale-dev \
libudev-dev \
libevdev-dev \
libsdl3-dev \
glslang-dev \
glslang-tools \
libpugixml-dev \
libenet-dev \
libxxhash-dev \
libbz2-dev \
liblzma-dev \
libzstd-dev \
zlib1g-dev \
libminizip-ng-dev \
liblzo2-dev \
liblz4-dev \
libspng-dev \
libcubeb-dev \
libusb-1.0-0-dev \
libsfml-dev \
libminiupnpc-dev \
libcurl4-openssl-dev \
libhidapi-dev \
libsystemd-dev \
libgtest-dev \
libasound2-dev \
libpulse-dev \
llvm-dev \
libbluetooth-dev \
gettext \
libvulkan-dev \
vulkan-tools
## fmt that comes with ubuntu 26 also seems incorrect.
# libfmt-dev \
RUN mkdir -p /app/dolphinxr
WORKDIR /app/dolphinxr
COPY . .
RUN mkdir Build \
&& cd Build \
&& cmake .. -DENABLE_VR=ON -DENABLE_VULKAN=ON -DUSE_SYSTEM_MBEDTLS=OFF -DUSE_SYSTEM_LIBMGBA=OFF \
&& cd .. \
&& cmake --build Build --target dolphin-emu -j $(nproc)
+1 -1
+18
View File
@@ -0,0 +1,18 @@
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 7efde81..9d5e1fd 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -163,8 +163,12 @@ option(BUILD_ALL_EXTENSIONS "Build loader and layers with all extensions" OFF)
option(
BUILD_LOADER_WITH_EXCEPTION_HANDLING
"Enable exception handling in the loader. Leave this on unless your standard library is built to not throw."
- ON
+ OFF
)
+if(NOT BUILD_LOADER_WITH_EXCEPTION_HANDLING)
+ add_definitions(-DXRLOADER_DISABLE_EXCEPTION_HANDLING)
+ add_definitions(-DJSON_USE_EXCEPTIONS=0)
+endif()
if(WIN32)
set(OPENXR_DEBUG_POSTFIX
+316 -196
View File
@@ -1,251 +1,310 @@
# Dolphin - A GameCube and Wii Emulator
# Baiji - Steam Frame-specific fork of DolphinXR, a fork of Dolphin
[Homepage](https://dolphin-emu.org/) | [Project Site](https://github.com/dolphin-emu/dolphin) | [Buildbot](https://dolphin.ci/) | [Forums](https://forums.dolphin-emu.org/) | [Wiki](https://wiki.dolphin-emu.org/) | [GitHub Wiki](https://github.com/dolphin-emu/dolphin/wiki) | [Issue Tracker](https://bugs.dolphin-emu.org/projects/emulator/issues) | [Coding Style](https://github.com/dolphin-emu/dolphin/blob/master/Contributing.md) | [Transifex Page](https://app.transifex.com/dolphinemu/dolphin-emu/dashboard/) | [Analytics](https://mon.dolphin-emu.org/)
Baiji is an AI-slop fork of
[dolphinXR](https://github.com/iChris4/dolphinXR/), a "developed with
the use of AI tools" (straight from their readme) fork of Dolphin.
Dolphin is an emulator for running GameCube and Wii games on Windows,
Linux, macOS, and recent Android devices. It's licensed under the terms
of the GNU General Public License, version 2 or later (GPLv2+).
Baiji may be AI slop but this Readme.md is organic and home-grown by a
human.
This fork adds OpenXR support to Dolphin so users can play in VR on Windows,
desktop Linux, and standalone Meta Quest headsets, and was developed with the
use of AI tools.
Baiji is intended to be a near-term fork that directly integrates with
the Steam Frame, removing the complication of trying to figure out how
to stream VR from a remote computer, deal with VR control schemes,
etc., and so forth, making a fork of Dolphin that _just works_ in 3D
on the Steam Frame.
* **Windows** — VR runs on the Direct3D 11, Direct3D 12, Vulkan, and OpenGL
backends with any OpenXR runtime (SteamVR, Oculus/Meta Link, VDXR, etc.).
* **Linux** — VR runs on the Vulkan and OpenGL backends and requires a working
system OpenXR runtime such as Monado or SteamVR.
* **Meta Quest** — a standalone Android build (Quest 2, Quest 3, Quest 3S, and
Quest Pro) renders natively in the headset on the Vulkan and OpenGL ES
backends, with OpenXR controller support.
3D? Did I say 3D? Yes, 3D. Core Dolphin has a long-standing feature
called [stereoscopic
3D](https://wiki.dolphin-emu.org/index.php?title=Stereoscopic_3D_Setup),
which allows the running of Dolphin on a 3D monitor or with 3D
glasses. However the hardware is specialized and the setup was not VR
aware, so a default Dolphin install can only run flat on a virtual
screen.
Please read the [FAQ](https://dolphin-emu.org/docs/faq/) before using Dolphin.
The primary purpose of this fork is to make this stereoscopic 3D Just
Work™. I can't show what this looks like in a static shot on GitHub,
but if you can cross your eyes, here's [Super Mario Galaxy 2 in
stereoscopic 3D on
YouTube](https://www.youtube.com/watch?v=XmgdqCL2toE). I found a
normal phone a pretty good way to view that with cross-eyes; getting
the sizing right on a desktop is pretty challenging.
## System Requirements
In principle it is as easy as installing Baiji, getting a legal file
Dolphin can read as a Wii game, and starting the ROM. Baiji should
come up with a sensible Steam Frame controller mapping for a WiiMote +
Nunchunk, in stereoscopic 3D, with sensible performance settings
(which includes "precompiling shaders" before startup, though you may
see some initial stutters as the cache is built out), and be off to
the races. In practice, this is the work of a long weekend and I've
tested a whopping 4 games, only one from the Gamecube, and one of
which had an early crash with at least one of the development
version.
### Desktop
So don't expect miracles.
* OS
* Windows (10 1903 or higher).
* Linux.
* macOS (11.0 Big Sur or higher).
* Unix-like systems other than Linux are not officially supported but might work.
* Processor
* A CPU with SSE2 support.
* A modern CPU (3 GHz and Dual Core, not older than 2008) is highly recommended.
* Graphics
* A reasonably modern graphics card (Direct3D 11.1 / OpenGL 3.3).
* A graphics card that supports Direct3D 11.1 / OpenGL 4.4 is recommended.
But I figured this had gotten to the point where more eyes was the
better way to go.
### Android
A ["Baiji" is a possibly-extinct subspecies of
dolphin](https://en.wikipedia.org/wiki/Baiji). Most dolphin species
have clumsy, branding-unfriendly names like "Hector's Dolphin". Baiji
is a nice snappy name. Baiji are also possibly extinct, which
represents the fact I don't necessarily expect this to be a long-term
fork of the Dolphin project. I expect that someday, they will
incorporate the major features of this project into the
mainline, and that will mark the end of this fork. However, due to
their completely rational and justifiable policy about AI, it may take
some time because they can not and will not just pick this code up.
* OS
* Android (5.0 Lollipop or higher).
* Processor
* A processor with support for 64-bit applications (either ARMv8 or x86-64).
* Graphics
* A graphics processor that supports OpenGL ES 3.0 or higher. Performance varies heavily with [driver quality](https://dolphin-emu.org/blog/2013/09/26/dolphin-emulator-and-opengl-drivers-hall-fameshame/).
* A graphics processor that supports standard desktop OpenGL features is recommended for best performance.
I also aspire to demonstrate the utility for any emulator of any 3D
system of building a native Steam Frame build that Just Works™ with
similar stereoscopic 3D, until someday the release of Baiji is looked
back as the harbinger of when running the Emustation or similar
install script doesn't just install a bunch of flat emulators but
installs 3D-aware emulators for all the 3D systems. Especially the
3DS, because as the only native 3D commercial gaming system that will
not have the issues with eye-twisting things like text behind other 3D
objects and stuff.
Dolphin can only be installed on devices that satisfy the above requirements. Attempting to install on an unsupported device will fail and display an error message.
I aspire to see the Steam Frame become considered
_the_ definitive way to emulate 3D-based systems because of the additional
3D experience it can offer, out of the box, such that anyone can use
it without trying to get widely disparate enviromnents and libraries
and streaming and everything set up. Perhaps even, dare I think it,
that this use case becomes considered one of the definitive reasons to
get a Steam Frame. Vive le matériel libre.
### VR (OpenXR)
# Features
* Windows
* An OpenXR runtime (SteamVR, Oculus/Meta Link, VDXR, etc.) and a headset it supports.
* Direct3D 11, Direct3D 12, Vulkan, or OpenGL backend.
* Linux
* An OpenXR runtime such as Monado or SteamVR.
* Vulkan (recommended) or OpenGL backend.
* Meta Quest
* Quest 2, Quest 3, Quest 3S, or Quest Pro, running the standalone `quest` build.
* Vulkan or OpenGL ES backend.
* VR is not supported on macOS.
* Steam Frame-centric default settings, including mappings and such.
* Integrated Stereoscopic 3D, including some new settings not in the
original 3D support of use in VR.
* Retained the VR work from the dolphinXR branch, selectable in a
drop-down.
* Also retained flat mode, where at least the default Steam Frame
configurations can be of some use.
* Controller configuration that works in the Steam Frame UI.
## Building for Windows
# Installation And Startup
Use the solution file `Source/dolphin-emu.sln` to build Dolphin on Windows.
Dolphin targets the latest MSVC shipped with Visual Studio or Build Tools.
Other compilers might be able to build Dolphin on Windows but have not been
tested and are not recommended to be used. Git and latest Windows SDK must be
installed when building.
Unfortunately, as far as I can tell, it is not currently possible to
release this as a Flatpak, because Flatpak software can not get to the
VR infrastructure. I expect this to change over time, but who knows
when.
Make sure to pull submodules before building:
```sh
git submodule update --init --recursive
```
## Install From Snapshot
### Building the OpenXR VR version
(These instructions assume you haven't changed the `steamos` user. If
you don't know what that means, you haven't. I think some paths end up
in the executable. If you have changed it, you may need to do some
symlinking or hardlinking to have this end up unpacked into
`/home/steamos/baiji`.)
To build the VR-enabled version of this fork, OpenXR support must be enabled
with `-DENABLE_VR=ON`. VR is supported on Windows, desktop Linux, and Android
(Meta Quest); see the Linux and Android sections below for those platforms.
1. Start the Desktop environment in your Steam Frame.
2. Navigate to this URL in a browser.
3. Start `Konsole`, or the terminal of your choice.
4. Copy this by clicking on the little double-square next to these
commands:
If you are generating a Visual Studio build with CMake, configure with
`-DENABLE_VR=ON`:
```sh
cmake -S . -B Build-vs2022 -G "Visual Studio 17 2022" -A x64 -DENABLE_VR=ON
```
```bash
cd
wget https://github.com/thejerf/baijiSteamVR/releases/download/baiji-v0.1-alpha/baiji-v0.1-alpha.tar.bz2
tar xjf baiji-v0.1-alpha.tar.bz2
ssh frame "steamos-add-to-steam ./baiji/bin/baiji-vr"
```
5. Paste that into your Konsole session and hit "enter" on the
keyboard.
`baiji-vr` will appear as an option in your Non-Steam Games library.
When using the Visual Studio generator, build the OpenXR loader first:
```sh
cmake --build Build-vs2022 --config Release --target openxr_loader
```
From there you'll need to load it up with your legally-acquired ROMs.
Finally, build Dolphin:
```sh
cmake --build Build-vs2022 --config Release --target dolphin-emu
```
## Build and Install From an x86_64 Linux Machine
If you prefer building OpenXR separately first, the repository also includes
`Externals/OpenXR/build-win64/OPENXR.sln`.
This is the maintained way to build a Steam Frame version. The host needs
Git and Podman. If the AArch64 KDE SDK is not already present in the
checkout, Flatpak is needed on the first build to install it into ignored
`state/` build data. This SDK is a compiler sysroot; Baiji itself is built
as a regular executable, not a Flatpak. QEMU's AArch64 emulator is installed
in the build image, so the host does not need to provide it.
The "Release" solution configuration includes performance optimizations for the best user experience but complicates debugging Dolphin.
The "Debug" solution configuration is significantly slower, more verbose and less permissive but makes debugging Dolphin easier.
1. Turn on Developer Mode on the Frame and enable SSH access. Configure an
SSH host alias on your Linux machine (replace the example address with
the Frame's IP address):
## Building for Linux and macOS
```sshconfig
Host frame
HostName 192.168.1.123
User steamos
```
Dolphin requires [CMake](https://cmake.org/) for systems other than Windows.
You need a recent version of GCC or Clang with decent c++20 support. CMake will
inform you if your compiler is too old.
Many libraries are bundled with Dolphin and used if they're not installed on
your system. CMake will inform you if a bundled library is used or if you need
to install any missing packages yourself. You may refer to the [wiki](https://github.com/dolphin-emu/dolphin/wiki/Building-for-Linux) for more information.
Verify the connection with `ssh frame`. If you use a different alias,
pass it instead of `frame` in the deploy command below.
Make sure to pull submodules before building:
```sh
git submodule update --init --recursive
```
2. Clone baiji, set up some necessary cross-compilation code, build,
and deploy:
### Building the OpenXR VR version on Linux:
```bash
git clone --recurse-submodules https://github.com/thejerf/baijiSteamVR.git
cd baijiSteamVR
./scripts/compile-cross-sdk.sh
./scripts/deploy-frame.sh frame
ssh frame "steamos-add-to-steam ./baiji/bin/baiji-vr"
```
OpenXR VR is available on desktop Linux (it is not supported on macOS). It
requires a working system OpenXR runtime such as Monado or SteamVR, and runs on
the Vulkan and OpenGL backends. Configure with OpenXR and Vulkan enabled:
Debug symbols are omitted by default. To include them, run the build command as
`DEBUG_SYMBOLS=1 ./scripts/compile-cross-sdk.sh`.
```sh
cmake -S . -B Build -DENABLE_VR=ON -DENABLE_VULKAN=ON
cmake --build Build --target dolphin-emu -j $(nproc)
```
These instructions build the current checkout rather than a packaged
release, so the code may be unstable.
OpenGL (GLX) is always built on desktop Linux, so VR remains usable even
without `-DENABLE_VULKAN=ON`, though Vulkan is recommended.
The build stages the Frame-compatible files under
`state/stage-frame/home/steamos/baiji` before transferring them. The
deploy script installs Baiji's executables, private libraries, and data
under `~/baiji`.
### macOS Build Steps:
3. On the Frame, launch `~/baiji/bin/baiji-vr` from a Desktop terminal, or
add that path as a non-Steam game to launch it from Big
Picture. Add legally dumped game images through Baiji's open dialog or configure the
game search paths in Baiji.
A binary supporting a single architecture can be built using the following steps:
I don't use Windows but any ol' AI can probably adapt this to a
Windows or MacOS build process pretty easily. If an AI offers to build
you an "emulation-based" toolchain, where it runs a native ARM
toolchain on an x86 CPU, decline that. It was miserably slow. I don't
know about ARM-based Mac OS machines.
1. `mkdir build`
2. `cd build`
3. `cmake ..`
4. `make -j $(sysctl -n hw.logicalcpu)`
# Performance Issues
An application bundle will be created in `./Binaries`.
* Remarkably, there are still even some Gamecube games that the Steam
Frame can struggle with. I have verified this with a native build of
Dolphin 2609: The Steam Frame can only barely push Wind Waker
at native resolution on one screen, and it still makes some stutters
even so. The good news is, if you sit through the emulation stuttering,
it actually doesn't look all that great in 3D. The cell shading effect
flattens everything out into a rather visually boring 3D effect,
rather than looking awesome, so we're not missing anything.
A script is also provided to build universal binaries supporting both x64 and ARM in the same
application bundle using the following steps:
# Ownership
1. `mkdir build`
2. `cd build`
3. `python ../BuildMacOSUniversalBinary.py`
4. Universal binaries will be available in the `universal` folder
I see a number of other people are working on similar forks. Honestly,
I don't really care to own this. All I want is the stereoscopic 3D,
even if you pursue VR being another option, because of the ability to
manipulate the stereoscopic 3D settings as I have them in this repo
and the utility I think that will have. (Skies of Arcadia is seriously
eye-crossing if you don't turn down the 3D.) Have a look at the
reconfigured UI for the VR panel in this branch and how it allows you
to select the various options. If anyone wants to have their AI look
over my patch stream, break it down by feature, and incorporate it
into your project, that's great. You can have the branding too if you
like. I don't care.
Doing this is more complex as it requires installation of library dependencies for both x64 and ARM (or universal library
equivalents) and may require specifying additional arguments to point to relevant library locations.
Execute BuildMacOSUniversalBinary.py --help for more details.
# Known Quirks
### Linux Global Build Steps:
* In Stereoscopic 3D mode, stopping the emulation (default the "View"
button, the button on top of the left controller) pops up a dialog
box in the QT environment asking you if you want to stop
emulation. The user experience is that emulation just freezes and
there is no indication of this. You must hit the Steam button to
pull up the Steam UI, and then, it seems to be random whether it
shows the default Steam OS controls for stopping or resuming the
game or the QT UI. You can select the QT UI from the list of running
windows on the left, then click "Yes", and emulation will stop and
control return to the main UI.
* You may need to recenter once to align the pointer in Stereoscopic
3D mode.
* If you choose to emulate in Flat Mode, your controllers will be in
laser mode when you click "play". You *must* be in gamepad mode to
actually play the game. I panicked several times during
development that I had broken controller support but it was just
that I had forgotten to switch. There is a dialog that should remind
you. Note this is an aspect of the Steam OS, not Baiji.
* The main UI
is mostly frozen during emulation. But only mostly. Still, best just
to treat it as frozen until you stop the emulation.
* The "Immersive VR" only works with a certain set of settings,
but they are not locked in when it is selected. This is next
on the agenda.
To install to your system.
# The Usual Fake FAQs
1. `mkdir build`
2. `cd build`
3. `cmake ..`
4. `make -j $(nproc)`
5. `sudo make install`
Most FAQs aren't really "frequently asked", they're just made up
things the developer expects to be asked. This list is no different.
### Linux Local Build Steps:
## Why Not A Flatpak?
Useful for development as root access is not required.
As near as I can tell, it is currently *impossible* to get to VR from
a flatpak, and the reason why can only be fixed by Valve.
1. `mkdir Build`
2. `cd Build`
3. `cmake .. -DLINUX_LOCAL_DEV=true`
4. `make -j $(nproc)`
5. `ln -s ../../Data/Sys Binaries/`
To get to VR, you need to open a Unix socket to the VR server. The VR
server has some validation on the incoming PID and possibly some other
checks that flatpaks can't pass. The AI and tried some hacking around
but I was focused on getting this to work at all and didn't bang on
this too hard.
### Linux Portable Build Steps:
A successful Flatpak PR that proves me wrong is one I'd accept with gusto.
Can be stored on external storage and used on different Linux systems.
Or useful for having multiple distinct Dolphin setups for testing/development/TAS.
This also, unfortunately, suggests that until this is fixed, it may
not be a great idea to try to pack this with Emustation or
anything. If they disagree I have no objection, but I would suggest
that at least as I write this, this project is not necessarily ready
for that sort of prime time.
1. `mkdir Build`
2. `cd Build`
3. `cmake .. -DLINUX_LOCAL_DEV=true`
4. `make -j $(nproc)`
5. `cp -r ../Data/Sys/ Binaries/`
6. `touch Binaries/portable.txt`
## Why Did You Rename This Project? Are You Trying To Steal Credit Or Something?
## Building for Android
No, this is actually out of politeness to the Dolphin project, and I
believe in accordance with their wishes. The name of the project isn't
just about the name of the executable or the title screen that comes
up when you run it. It's about who is standing behind it and who is
responsible for it.
These instructions assume familiarity with Android development. If you do not have an
Android dev environment set up, see [AndroidSetup.md](AndroidSetup.md).
The Dolphin team is not behind this project. In particular that means,
if the pieces break, you own them, maybe I have a bit of
responsibility for them, but the Dolphin team has no responsibility
whatsoever. Not even the polite one of at least listening to your
problem. The correct solution for the Dolphin project, if anyone files a
bug with them, or starts a forum thread about bugs in Baiji, or
anything else like that, is to immediately close it/lock it, and scold
you a bit for putting it in the wrong place.
Make sure to pull submodules before building:
```sh
git submodule update --init --recursive
```
Renaming this project is part of a statement that says, if you have a
problem with Baiji, you do not go to the Dolphin forum for support any
more than you'd go there for support with LibreOffice.
If using Android Studio, import the Gradle project located in `./Source/Android`.
Anyone who distributes a very modified version of an open source
project, especially if like me the _know_ upstream can not and will
not take their patches as-is, _should_ rename the project.
Android apps are compiled using a build system called Gradle. Dolphin's native component,
however, is compiled using CMake. The Gradle script will attempt to run a CMake build
automatically while building the Java code.
Me trying to steal credit would look like me trying to erase all signs
of the Dolphin heritage out of the executable entirely.
### Building the Meta Quest VR version
Instead: I am a mere minnow next to the awesome Dolphin project. I am standing
on the shoulder of their giantness, and to a lesser but still
significant extent, on the work of the dolphinXR fork. I am
deeply appreciative and while I want to help the Steam Frame, this is
a mere trivial "couple o' weekends" gloss on top of the
who-knows-how-many person-centuries of work the Dolphin project
represents. Do not overestimate my "contribution". Nothing in this
paragraph is a joke or even slightly sarcastic.
The Android project has two product flavors on the `device` dimension:
`standard` (phones and tablets, built with `-DENABLE_VR=OFF`) and `quest`
(standalone headsets, built with `-DENABLE_VR=ON`). The `quest` flavor is
arm64-only, installs under the application ID `org.dolphinemu.dolphinemu.quest`
so it can live alongside a standard install, and declares the OpenXR manifest
entries required by Quest 2, Quest 3, Quest 3S, and Quest Pro.
On that note, if I've screwed up licensing or if anyone from the
Dolphin project has opinions about the details around how I've done
this, I am very open to change, correction, PRs on this matter,
etc. This is a sign of me trying to do it very correctly and
carefully, not carelessly, and not to steal credit.
Build it with Gradle from `Source/Android`:
```sh
./gradlew assembleQuestDebug # or assembleQuestRelease
```
Helper scripts are also provided for Windows:
```powershell
.\Source\Android\build-quest.ps1 # debug APK
.\Source\Android\build-quest-release.ps1 # release APK (needs signing properties)
```
Install the resulting APK on a headset with adb:
```sh
adb install -r Source/Android/app/build/outputs/apk/quest/debug/app-quest-debug.apk
```
VR settings for the headset (launch in VR, resolution scale, reference space,
controller bindings, and so on) live under the OpenXR section of the in-app
settings.
## Uninstalling
On Windows, simply remove the extracted directory, unless it was installed with the NSIS installer,
in which case you can uninstall Dolphin like any other Windows application.
Linux users can run `cat install_manifest.txt | xargs -d '\n' rm` as root from the build directory
to uninstall Dolphin from their system.
macOS users can simply delete Dolphin.app to uninstall it.
Additionally, you'll want to remove the global user directory if you don't plan on reinstalling Dolphin.
# Command Line Tooling
## Command Line Usage
Command line is inherited from Dolphin, just renamed. This has not
been gone over with a fine-toothed comb and may contain options not
relevant to the Steam Frame, may partially or completely not work on a
Steam Frame (e.g. I have no idea what a "movie" will do on a Steam
Frame, especially in its various modes), etc.
```
Usage: Dolphin.exe [options]... [FILE]...
Usage: baiji [options]... [FILE]...
Options:
--version show program's version number and exit
@@ -277,14 +336,10 @@ LLE (Low Level Emulation). HLE is faster but less accurate whereas
LLE is slower but close to perfect. Note that LLE has two submodes (Interpreter and Recompiler)
but they cannot be selected from the command line.
Available video backends are "D3D" and "D3D12" (they are only available on Windows), "OGL", and "Vulkan".
There's also "Null", which will not render anything, and
"Software Renderer", which uses the CPU for rendering and
is intended for debugging purposes only.
## Baiji Tool Usage
## DolphinTool Usage
```
usage: dolphin-tool COMMAND -h
usage: baiji-tool COMMAND -h
commands supported: [convert, verify, header, extract]
```
@@ -364,3 +419,68 @@ Options:
-q, --quiet Mute all messages except for errors.
-g, --gameonly Only extracts the DATA partition.
```
# Dolphin Links
Relevant links for the original Dolphin underneath Baiji:
* [Homepage](https://dolphin-emu.org/)
* [Project Site](https://github.com/dolphin-emu/dolphin)
* [Forums](https://forums.dolphin-emu.org/) but DO NOT report Baiji
bugs
* [Wiki](https://wiki.dolphin-emu.org/)
* [GitHub Wiki](https://github.com/dolphin-emu/dolphin/wiki)
* [Issue
Tracker](https://bugs.dolphin-emu.org/projects/emulator/issues) but
DO NOT... you ought to have gotten this by now... report Baiji bugs
* [FAQ](https://dolphin-emu.org/docs/faq/)
# Known Quirks/Bugs That Don't Seem Fixable
For any of these, a PR that proves me wrong would be great, but as far
as I know these are currently not reasonable fixable:
* When the QT UI is visible during 3D emulation, SteamOS spatializes
Baiji's emulation output to be coming from the location of the QT
UI, not the emulation. The Frame's OS does not seem to offer a way
to bypass this for just one application. It seems to have a switch
that could be thrown for the whole OS but I'm not touching it.
# Changelog
* Todo before release:
* Check Room View in VR, can probably leave that rendering while the
Steam UI is up
* Check the Reddit feedback about the settings that make VR work,
and lock the ones that _must_ be set for Immersive VR to work,
when Immersive VR is selected.
* v0.2-alpha (not released yet)
* Fixed what seems to be the last major performance regression
against a natively-compiled Dolphin.
* Added + and - to mapping on left & right bumper for Wii +
Nunchuck.
* Turning on Room View with the Steam UI stops rendering in Stereo
and VR mode and pauses the emulation, rather than continuing to
render and emulate and making it look like it was ignoring
controls.
Ideally, we'd leave the game UI up if you bring up the Steam UI,
and only stop displaying the game if you go to full room view
mode, but once focus is removed from the game, baiji can't tell
what you're doing. Since we can't be smart about this, we have to
not display the game even if you only are looking at the Steam UI.
This may be a bug in the UI's Room View support; it shouldn't let
us draw on it. If it correctly ignored our draw requests we could
get it to work like most other games, which still render in the
background.
* Improved the way a surface is requested for flat 2D mode. I'm
honestly uncertain if v0.1-alpha was broken, but if it was this
should fix it, if it wasn't, this should make future builds less
likely to break.
* v0.1-alpha - Initial release.
* Many Frame-specific UI changes to make working with the Frame
specifically slicker.
* Support for the full Frame controllers with their XR profile.
* Support for native display of stereoscopic 3D.
+1 -1
View File
@@ -83,7 +83,7 @@ bool CubebStream::Init()
INFO_LOG_FMT(AUDIO, "Minimum latency: {} frames", minimum_latency);
return_value =
cubeb_stream_init(m_ctx.get(), &m_stream, "Dolphin Audio Output", nullptr, nullptr,
cubeb_stream_init(m_ctx.get(), &m_stream, "BaijiSteamVR Audio Output", nullptr, nullptr,
nullptr, &params, std::max(BUFFER_SAMPLES, minimum_latency),
DataCallback, StateCallback, this) == CUBEB_OK;
}
+4
View File
@@ -68,7 +68,11 @@ std::shared_ptr<cubeb> GetContext()
}
cubeb* ctx;
#ifdef BAIJI_STEAMVR
if (cubeb_init(&ctx, "BaijiSteamVR", nullptr) != CUBEB_OK)
#else
if (cubeb_init(&ctx, "Dolphin Emulator", nullptr) != CUBEB_OK)
#endif
{
ERROR_LOG_FMT(AUDIO, "Error initializing cubeb library");
return nullptr;
+2
View File
@@ -17,6 +17,8 @@
#define NORMAL_USER_DIR "Library/Application Support/Dolphin"
#elif defined(ANDROID)
#define NORMAL_USER_DIR "/sdcard/dolphin-emu"
#elif defined(__linux__)
#define NORMAL_USER_DIR "baiji"
#else
#define NORMAL_USER_DIR "dolphin-emu"
#endif
+4
View File
@@ -155,7 +155,11 @@ void ClearCurrentRunLayer()
}
static const std::map<System, std::string> system_to_name = {
#ifdef BAIJI_STEAMVR
{System::Main, "BaijiSteamVR"},
#else
{System::Main, "Dolphin"},
#endif
{System::GCPad, "GCPad"},
{System::WiiPad, "Wiimote"},
{System::GCKeyboard, "GCKeyboard"},
+1 -1
View File
@@ -655,7 +655,7 @@ std::string CreateTempDir()
return dir;
#else
const char* base = getenv("TMPDIR") ?: "/tmp";
std::string path = std::string(base) + "/DolphinWii.XXXXXX";
std::string path = std::string(base) + "/BaijiWii.XXXXXX";
if (!mkdtemp(&path[0]))
return "";
return path;
+1 -1
View File
@@ -102,7 +102,7 @@ LogManager::LogManager()
m_log[LogType::BOOT] = {"BOOT", "Boot"};
m_log[LogType::COMMANDPROCESSOR] = {"CP", "Command Processor"};
m_log[LogType::COMMON] = {"COMMON", "Common"};
m_log[LogType::CONSOLE] = {"CONSOLE", "Dolphin Console"};
m_log[LogType::CONSOLE] = {"CONSOLE", "BaijiSteamVR Console"};
m_log[LogType::CONTROLLERINTERFACE] = {"CI", "Controller Interface"};
m_log[LogType::CORE] = {"CORE", "Core"};
m_log[LogType::DISCIO] = {"DIO", "Disc IO"};
+1 -1
View File
@@ -175,7 +175,7 @@ void TraversalClient::HandleServerPacket(TraversalPacket* packet)
ENetAddress addr = MakeENetAddress(packet->pleaseSendPacket.address);
if (addr.port != 0)
{
char message[] = "Hello from Dolphin Netplay...";
char message[] = "Hello from BaijiSteamVR Netplay...";
ENetBuffer buf;
buf.data = message;
buf.dataLength = sizeof(message) - 1;
+1 -1
View File
@@ -134,7 +134,7 @@ static bool MapPort(const char* addr, const u16 port)
std::string port_str = std::to_string(port);
int result = UPNP_AddPortMapping(
s_urls.controlURL, s_data.first.servicetype, port_str.c_str(), port_str.c_str(), addr,
(std::string("dolphin-emu UDP on ") + addr).c_str(), "UDP", nullptr, nullptr);
(std::string("BaijiSteamVR UDP on ") + addr).c_str(), "UDP", nullptr, nullptr);
if (result != 0)
return false;
+19
View File
@@ -44,7 +44,16 @@ struct OpenXRControllerState
bool connected = false;
bool primary_button = false;
bool secondary_button = false;
bool frame_x_button = false;
bool frame_y_button = false;
bool menu_button = false;
bool system_button = false;
bool view_button = false;
bool bumper_button = false;
bool dpad_up = false;
bool dpad_down = false;
bool dpad_left = false;
bool dpad_right = false;
bool trigger_button = false;
bool squeeze_button = false;
bool thumbstick_button = false;
@@ -114,6 +123,16 @@ public:
++s_state.generation;
}
static void SetSessionFocused(bool focused)
{
std::lock_guard lk(s_state_mutex);
if (s_state.session_focused == focused)
return;
s_state.session_focused = focused;
++s_state.generation;
}
static std::string GetDiagnosticString()
{
std::lock_guard lk(s_state_mutex);
+4
View File
@@ -9,7 +9,11 @@
namespace Common
{
#ifdef BAIJI_STEAMVR
#define EMULATOR_NAME "BaijiSteamVR"
#else
#define EMULATOR_NAME "Dolphin"
#endif
#ifdef _DEBUG
#define BUILD_TYPE_STR "Debug "
+1 -1
View File
@@ -82,7 +82,7 @@ static void WarnIfRunningUnderEmulation()
// The process is not native; could use IsWow64Process2 to get native machine type, but for now
// we can assume it is arm64.
PanicAlertFmtT("This build of Dolphin is not natively compiled for your CPU.\n"
PanicAlertFmtT("This build of BaijiSteamVR is not natively compiled for your CPU.\n"
"Please run the ARM64 build of Dolphin for a better experience.");
}
+4 -4
View File
@@ -87,7 +87,7 @@ void AchievementManager::Init(void* hwnd)
// In non-x64 build, will only look for RA_Integration.dll.
rc_client_begin_load_raintegration(
m_client, UTF8ToWString(File::GetExeDirectory()).c_str(), reinterpret_cast<HWND>(hwnd),
"Dolphin", Common::GetScmDescStr().c_str(), LoadIntegrationCallback, NULL);
"BaijiSteamVR", Common::GetScmDescStr().c_str(), LoadIntegrationCallback, NULL);
#else // RC_CLIENT_SUPPORTS_RAINTEGRATION
if (HasAPIToken())
Login("");
@@ -989,10 +989,10 @@ void AchievementManager::LoadGameCallback(int result, const char* error_message,
instance.m_loading_volume.reset(nullptr);
if (result == RC_API_FAILURE)
{
WARN_LOG_FMT(ACHIEVEMENTS, "Load data request rejected for old Dolphin version.");
OSD::AddMessage("RetroAchievements no longer supports this version of Dolphin.",
WARN_LOG_FMT(ACHIEVEMENTS, "Load data request rejected for an old BaijiSteamVR version.");
OSD::AddMessage("RetroAchievements no longer supports this version of BaijiSteamVR.",
OSD::Duration::VERY_LONG, OSD::Color::RED);
OSD::AddMessage("Please update Dolphin to a newer version.", OSD::Duration::VERY_LONG,
OSD::AddMessage("Please update BaijiSteamVR to a newer version.", OSD::Duration::VERY_LONG,
OSD::Color::RED);
return;
}
+1 -1
View File
@@ -973,7 +973,7 @@ static bool RunCodeLocked(const Core::CPUThreadGuard& guard, const ARCode& arcod
default:
LogInfo("ZCode: Unknown");
PanicAlertFmtT("Zero code unknown to Dolphin: {0:08x}", zcode);
PanicAlertFmtT("Zero code unknown to BaijiSteamVR: {0:08x}", zcode);
return false;
}
+1 -1
View File
@@ -130,7 +130,7 @@ bool ElfReader::LoadIntoMemory(Core::System& system, bool only_in_mem1) const
if (bRelocate)
{
PanicAlertFmt("Error: Dolphin doesn't know how to load a relocatable elf.");
PanicAlertFmt("Error: BaijiSteamVR doesn't know how to load a relocatable elf.");
return false;
}
+18 -5
View File
@@ -84,7 +84,7 @@ const Info<bool> GFX_ENABLE_PIXEL_LIGHTING{{System::GFX, "Settings", "EnablePixe
const Info<bool> GFX_FAST_DEPTH_CALC{{System::GFX, "Settings", "FastDepthCalc"}, true};
const Info<u32> GFX_MSAA{{System::GFX, "Settings", "MSAA"}, 1};
const Info<bool> GFX_SSAA{{System::GFX, "Settings", "SSAA"}, false};
const Info<int> GFX_EFB_SCALE{{System::GFX, "Settings", "InternalResolution"}, 1};
const Info<int> GFX_EFB_SCALE{{System::GFX, "Settings", "InternalResolution"}, 2};
const Info<int> GFX_MAX_EFB_SCALE{{System::GFX, "Settings", "MaxInternalResolution"}, 12};
const Info<bool> GFX_TEXFMT_OVERLAY_ENABLE{{System::GFX, "Settings", "TexFmtOverlayEnable"}, false};
const Info<bool> GFX_TEXFMT_OVERLAY_CENTER{{System::GFX, "Settings", "TexFmtOverlayCenter"}, false};
@@ -104,7 +104,7 @@ const Info<int> GFX_COMMAND_BUFFERS_IN_FLIGHT{
const Info<bool> GFX_SHADER_CACHE{{System::GFX, "Settings", "ShaderCache"}, true};
const Info<bool> GFX_WAIT_FOR_SHADERS_BEFORE_STARTING{
{System::GFX, "Settings", "WaitForShadersBeforeStarting"}, false};
{System::GFX, "Settings", "WaitForShadersBeforeStarting"}, true};
const Info<ShaderCompilationMode> GFX_SHADER_COMPILATION_MODE{
{System::GFX, "Settings", "ShaderCompilationMode"}, ShaderCompilationMode::Synchronous};
const Info<int> GFX_SHADER_COMPILER_THREADS{{System::GFX, "Settings", "ShaderCompilerThreads"}, 1};
@@ -191,7 +191,13 @@ const Info<bool> GFX_VR_ENABLE_OPENXR{{System::GFX, "VR", "EnableOpenXR"}, true}
// When OpenXR is enabled, render the game as a flat mono panel in the VR scene instead of
// per-eye stereoscopic 3D (the "Launch games in VR" off / cinema path).
const Info<bool> GFX_VR_FLAT_SCREEN{{System::GFX, "VR", "FlatScreen"}, false};
// When OpenXR is enabled, render the game using classic SBS stereoscopy and submit it as a
// stereoscopic virtual screen (two quad layers) instead of immersive per-eye reprojection.
const Info<bool> GFX_VR_STEREO_SCREEN{{System::GFX, "VR", "StereoScreen"}, false};
const Info<OpenXRPresentationMode> GFX_VR_PRESENTATION_MODE{
{System::GFX, "VR", "PresentationMode"}, OpenXRPresentationMode::StereoScreen};
const Info<float> GFX_VR_UNITS_PER_METER{{System::GFX, "VR", "UnitsPerMeter"}, 1.0f};
const Info<float> GFX_VR_STEREO_SEPARATION{{System::GFX, "VR", "StereoSeparation"}, 100.0f};
const Info<bool> GFX_VR_ENABLE_LEAN_BACK_ANGLE{{System::GFX, "VR", "EnableLeanBackAngle"}, true};
const Info<float> GFX_VR_LEAN_BACK_ANGLE{{System::GFX, "VR", "LeanBackAngle"}, 0.0f};
const Info<bool> GFX_VR_ENABLE_CAMERA_FORWARD{{System::GFX, "VR", "EnableCameraForward"}, true};
@@ -204,14 +210,18 @@ const Info<float> GFX_VR_CAMERA_ANCHOR_SMOOTHING{{System::GFX, "VR", "CameraAnch
const Info<bool> GFX_VR_ENABLE_CONTROLLER_ANCHOR{{System::GFX, "VR", "EnableControllerAnchor"},
false};
const Info<bool> GFX_VR_VIRTUAL_SCREEN{{System::GFX, "VR", "VirtualScreen"}, true};
const Info<float> GFX_VR_SCREEN_DISTANCE{{System::GFX, "VR", "ScreenDistance"}, 1.5f};
const Info<float> GFX_VR_SCREEN_DISTANCE{{System::GFX, "VR", "ScreenDistance"}, 2.0f};
const Info<float> GFX_VR_SCREEN_SIZE{{System::GFX, "VR", "ScreenSize"}, 1.5f};
const Info<float> GFX_VR_HEAD_LOCKED_CURVATURE{{System::GFX, "VR", "HeadLockedCurvature"}, 0.0f};
const Info<bool> GFX_VR_DONT_CLEAR_SCREEN{{System::GFX, "VR", "DontClearScreen"}, false};
const Info<bool> GFX_VR_LOAD_CUSTOM_SHADERS{{System::GFX, "VR", "LoadCustomShaders"}, false};
const Info<bool> GFX_VR_DISABLE_CPU_CULL{{System::GFX, "VR", "DisableCPUCull"}, false};
const Info<OpenXRMirrorView> GFX_VR_MIRROR_VIEW{{System::GFX, "VR", "MirrorView"},
OpenXRMirrorView::BothEyes};
#ifdef BAIJI_STEAMVR
OpenXRMirrorView::None};
#else
OpenXRMirrorView::BothEyes};
#endif
const Info<OpenXRReferenceSpaceMode> GFX_VR_REFERENCE_SPACE_MODE{
{System::GFX, "VR", "ReferenceSpaceMode"}, OpenXRReferenceSpaceMode::Local};
const Info<OpenXRTrackingMode> GFX_VR_TRACKING_MODE{{System::GFX, "VR", "TrackingMode"},
@@ -226,7 +236,7 @@ constexpr bool DEFAULT_VR_PIN_EMULATION_CORES = false;
#endif
const Info<bool> GFX_VR_PIN_EMULATION_CORES{{System::GFX, "VR", "PinEmulationCores"},
DEFAULT_VR_PIN_EMULATION_CORES};
const Info<bool> GFX_VR_EAGER_HEARTBEAT{{System::GFX, "VR", "EagerHeartbeat"}, false};
const Info<bool> GFX_VR_EAGER_HEARTBEAT{{System::GFX, "VR", "EagerHeartbeat"}, true};
#if defined(__ANDROID__) && defined(ENABLE_VR)
constexpr bool DEFAULT_VR_ANDROID_DIRECT_TO_HMD = true;
constexpr bool DEFAULT_IMMEDIATE_XFB = true;
@@ -236,6 +246,9 @@ constexpr bool DEFAULT_IMMEDIATE_XFB = false;
#endif
const Info<int> GFX_VR_FORCED_VBI_FREQUENCY{{System::GFX, "VR", "ForcedVBIFrequency"}, 0};
// Request a specific display refresh rate from the OpenXR runtime (Hz). 0 means no request
// (use the runtime's default). The runtime may clamp to the nearest available rate.
const Info<int> GFX_VR_REQUESTED_REFRESH_RATE{{System::GFX, "VR", "RequestedRefreshRate"}, 0};
const Info<bool> GFX_VR_AUTO_VBI_FROM_HMD{{System::GFX, "VR", "AutoVBIFromHMD"}, false};
const Info<bool> GFX_VR_EXACT_SCREEN_DEPTH{{System::GFX, "VR", "ExactScreenDepth"}, true};
const Info<bool> GFX_VR_AUTO_NATIVE_EFB_EFFECTS{{System::GFX, "VR", "AutoNativeEfbEffects"},
@@ -22,6 +22,7 @@ enum class VertexLoaderType : int;
enum class OpenXRMirrorView : int;
enum class OpenXRReferenceSpaceMode : int;
enum class OpenXRTrackingMode : int;
enum class OpenXRPresentationMode : int;
enum class VRPassthroughCoverageMode : int;
namespace Config
@@ -172,7 +173,10 @@ static constexpr float GFX_STEREO_CONVERGENCE_MAXIMUM = 200;
extern const Info<bool> GFX_VR_ENABLE_OPENXR;
extern const Info<bool> GFX_VR_FLAT_SCREEN;
extern const Info<bool> GFX_VR_STEREO_SCREEN;
extern const Info<OpenXRPresentationMode> GFX_VR_PRESENTATION_MODE;
extern const Info<float> GFX_VR_UNITS_PER_METER;
extern const Info<float> GFX_VR_STEREO_SEPARATION;
extern const Info<bool> GFX_VR_ENABLE_LEAN_BACK_ANGLE;
extern const Info<float> GFX_VR_LEAN_BACK_ANGLE;
extern const Info<bool> GFX_VR_ENABLE_CAMERA_FORWARD;
@@ -186,6 +190,9 @@ extern const Info<bool> GFX_VR_ENABLE_CONTROLLER_ANCHOR;
static constexpr float GFX_VR_UNITS_PER_METER_MIN = 0.1f;
static constexpr float GFX_VR_UNITS_PER_METER_MAX = 2000.0f;
static constexpr float GFX_VR_UNITS_PER_METER_STEP = 0.1f;
static constexpr float GFX_VR_STEREO_SEPARATION_MIN = 0.0f;
static constexpr float GFX_VR_STEREO_SEPARATION_MAX = 200.0f;
static constexpr float GFX_VR_STEREO_SEPARATION_STEP = 1.0f;
static constexpr float GFX_VR_LEAN_BACK_ANGLE_MIN = -45.0f;
static constexpr float GFX_VR_LEAN_BACK_ANGLE_MAX = 45.0f;
static constexpr float GFX_VR_LEAN_BACK_ANGLE_STEP = 0.1f;
@@ -211,6 +218,7 @@ extern const Info<OpenXRReferenceSpaceMode> GFX_VR_REFERENCE_SPACE_MODE;
extern const Info<OpenXRTrackingMode> GFX_VR_TRACKING_MODE;
extern const Info<bool> GFX_VR_USE_OPENXR_PLAY_SPACE_CENTER;
extern const Info<int> GFX_VR_FORCED_VBI_FREQUENCY;
extern const Info<int> GFX_VR_REQUESTED_REFRESH_RATE;
// Dedicated XR frame-pacing thread: owns xrWaitFrame/xrBeginFrame/xrEndFrame and
// re-submits the last frame at HMD cadence when the game runs slower (replaces the
// legacy Opcode Replay). INI-only escape hatch; disable to fall back to the inline
@@ -279,6 +287,11 @@ static constexpr int GFX_VR_FORCED_VBI_FREQUENCY_OFF = 0;
static constexpr int GFX_VR_FORCED_VBI_FREQUENCY_72 = 72;
static constexpr int GFX_VR_FORCED_VBI_FREQUENCY_90 = 90;
static constexpr int GFX_VR_FORCED_VBI_FREQUENCY_120 = 120;
static constexpr int GFX_VR_REQUESTED_REFRESH_RATE_AUTO = 0;
static constexpr int GFX_VR_REQUESTED_REFRESH_RATE_60 = 60;
static constexpr int GFX_VR_REQUESTED_REFRESH_RATE_72 = 72;
static constexpr int GFX_VR_REQUESTED_REFRESH_RATE_90 = 90;
static constexpr int GFX_VR_REQUESTED_REFRESH_RATE_120 = 120;
static constexpr float GFX_VR_HUD_THICKNESS_MIN = 0.0f;
static constexpr float GFX_VR_HUD_THICKNESS_MAX = 1.0f;
static constexpr float GFX_VR_HUD_THICKNESS_STEP = 0.02f;
+2
View File
@@ -426,6 +426,8 @@ const Info<bool> MAIN_ABORT_ON_PANIC_ALERT{{System::Main, "Interface", "AbortOnP
const Info<bool> MAIN_OSD_MESSAGES{{System::Main, "Interface", "OnScreenDisplayMessages"}, true};
const Info<int> MAIN_OSD_FONT_SIZE{{System::Main, "Settings", "OSDFontSize"}, 13};
const Info<bool> MAIN_SKIP_NKIT_WARNING{{System::Main, "Interface", "SkipNKitWarning"}, false};
const Info<bool> MAIN_SKIP_FLAT_MODE_INPUT_WARNING{
{System::Main, "Interface", "SkipFlatModeInputWarning"}, false};
const Info<bool> MAIN_CONFIRM_ON_STOP{{System::Main, "Interface", "ConfirmStop"}, true};
const Info<ShowCursor> MAIN_SHOW_CURSOR{{System::Main, "Interface", "CursorVisibility"},
ShowCursor::OnMovement};
+1
View File
@@ -248,6 +248,7 @@ extern const Info<bool> MAIN_ABORT_ON_PANIC_ALERT;
extern const Info<bool> MAIN_OSD_MESSAGES;
extern const Info<int> MAIN_OSD_FONT_SIZE;
extern const Info<bool> MAIN_SKIP_NKIT_WARNING;
extern const Info<bool> MAIN_SKIP_FLAT_MODE_INPUT_WARNING;
extern const Info<bool> MAIN_CONFIRM_ON_STOP;
enum class ShowCursor
+1 -1
View File
@@ -8,7 +8,7 @@
namespace Config
{
const Info<WiimoteSource> WIIMOTE_1_SOURCE{{System::WiiPad, "Wiimote1", "Source"},
WiimoteSource::Emulated};
WiimoteSource::OpenXR};
const Info<WiimoteSource> WIIMOTE_2_SOURCE{{System::WiiPad, "Wiimote2", "Source"},
WiimoteSource::None};
const Info<WiimoteSource> WIIMOTE_3_SOURCE{{System::WiiPad, "Wiimote3", "Source"},
+6
View File
@@ -158,7 +158,10 @@ static void ClearAppliedVRSettings()
{
ClearAppliedVRSetting("EnableOpenXR", Config::GFX_VR_ENABLE_OPENXR);
ClearAppliedVRSetting("FlatScreen", Config::GFX_VR_FLAT_SCREEN);
ClearAppliedVRSetting("StereoScreen", Config::GFX_VR_STEREO_SCREEN);
ClearAppliedVRSetting("PresentationMode", Config::GFX_VR_PRESENTATION_MODE);
ClearAppliedVRSetting("UnitsPerMeter", Config::GFX_VR_UNITS_PER_METER);
ClearAppliedVRSetting("StereoSeparation", Config::GFX_VR_STEREO_SEPARATION);
ClearAppliedVRSetting("EnableLeanBackAngle", Config::GFX_VR_ENABLE_LEAN_BACK_ANGLE);
ClearAppliedVRSetting("LeanBackAngle", Config::GFX_VR_LEAN_BACK_ANGLE);
ClearAppliedVRSetting("EnableCameraForward", Config::GFX_VR_ENABLE_CAMERA_FORWARD);
@@ -237,7 +240,10 @@ static void ApplyGameVRConfigOverrides(std::string_view game_id, std::optional<u
ApplyVRSetting(values, "EnableOpenXR", Config::GFX_VR_ENABLE_OPENXR);
ApplyVRSetting(values, "FlatScreen", Config::GFX_VR_FLAT_SCREEN);
ApplyVRSetting(values, "StereoScreen", Config::GFX_VR_STEREO_SCREEN);
ApplyVRSetting(values, "PresentationMode", Config::GFX_VR_PRESENTATION_MODE);
ApplyVRSetting(values, "UnitsPerMeter", Config::GFX_VR_UNITS_PER_METER);
ApplyVRSetting(values, "StereoSeparation", Config::GFX_VR_STEREO_SEPARATION);
ApplyVRSetting(values, "EnableLeanBackAngle", Config::GFX_VR_ENABLE_LEAN_BACK_ANGLE);
ApplyVRSetting(values, "LeanBackAngle", Config::GFX_VR_LEAN_BACK_ANGLE);
ApplyVRSetting(values, "EnableCameraForward", Config::GFX_VR_ENABLE_CAMERA_FORWARD);
+4
View File
@@ -45,7 +45,9 @@
namespace
{
#ifdef USE_ANALYTICS
constexpr char ANALYTICS_ENDPOINT[] = "https://analytics.dolphin-emu.org/report";
#endif
} // namespace
#if defined(ANDROID)
@@ -90,10 +92,12 @@ void DolphinAnalytics::ReloadConfig()
// Install the HTTP backend if analytics support is enabled.
std::unique_ptr<Common::AnalyticsReportingBackend> new_backend;
#ifdef USE_ANALYTICS
if (m_last_analytics_enabled)
{
new_backend = std::make_unique<Common::HttpAnalyticsBackend>(ANALYTICS_ENDPOINT);
}
#endif
m_reporter.SetBackend(std::move(new_backend));
// Load the unique ID or generate it if needed.
+1 -1
View File
@@ -407,7 +407,7 @@ void DVDInterface::SetDisc(std::unique_ptr<DiscIO::VolumeDisc> disc,
{
OSD::AddMessage("You are running a disc image with a very large block size.", 60000);
OSD::AddMessage("This will likely lead to performance problems.", 60000);
OSD::AddMessage("You can use Dolphin's convert feature to reduce the block size.", 60000);
OSD::AddMessage("You can use BaijiSteamVR's convert feature to reduce the block size.", 60000);
}
}
+1 -1
View File
@@ -730,7 +730,7 @@ void CEXIETHERNET::BuiltInBBAInterface::ReadThreadHandler(CEXIETHERNET::BuiltInB
if (datasize > BBA_RECV_SIZE)
{
ERROR_LOG_FMT(SP1, "Frame size is exceiding BBA capacity, frame stack might be corrupted"
"Killing Dolphin...");
"Killing BaijiSteamVR...");
std::exit(0);
}
std::memcpy(self->m_eth_ref->mRecvBuffer.get(), self->m_queue_data[self->m_queue_read].data(),
+2 -2
View File
@@ -31,7 +31,7 @@ bool CEXIETHERNET::TAPNetworkInterface::Activate()
if (IsActivated())
return true;
// Assumes that there is a TAP device named "Dolphin" preconfigured for
// Assumes that there is a TAP device named "Baiji" preconfigured for
// bridge/NAT/whatever the user wants it configured.
if ((fd = open("/dev/net/tun", O_RDWR)) < 0)
@@ -47,7 +47,7 @@ bool CEXIETHERNET::TAPNetworkInterface::Activate()
const int MAX_INTERFACES = 32;
for (int i = 0; i < MAX_INTERFACES; ++i)
{
fmt::format_to_n(ifr.ifr_name, IFNAMSIZ, "Dolphin{}", i);
fmt::format_to_n(ifr.ifr_name, IFNAMSIZ, "Baiji{}", i);
int err;
if ((err = ioctl(fd, TUNSETIFF, (void*)&ifr)) < 0)
+1 -1
View File
@@ -140,7 +140,7 @@ std::unique_ptr<IEXIDevice> EXIDevice_Create(Core::System& system, const EXIDevi
#ifdef HAVE_CUBEB
result = std::make_unique<CEXIMic>(system, channel_num);
#else
PanicAlertFmtT("Dolphin was built with Cubeb disabled. The Microphone device cannot be used.");
PanicAlertFmtT("BaijiSteamVR was built with Cubeb disabled. The Microphone device cannot be used.");
result = std::make_unique<IEXIDevice>(system);
#endif
break;
@@ -205,7 +205,7 @@ void CEXIMemoryCard::SetupGciFolder(const Memcard::HeaderData& header_data)
{
// TODO more user friendly abort
PanicAlertFmtT("{0} is not a directory, failed to move to *.original.\n Verify your "
"write permissions or move the file outside of Dolphin",
"write permissions or move the file outside of BaijiSteamVR",
dir_path);
std::exit(0);
}
+1 -1
View File
@@ -114,7 +114,7 @@ void CEXIMic::StreamStart()
}
if (cubeb_stream_init(m_cubeb_ctx.get(), &m_cubeb_stream,
"Dolphin Emulated GameCube Microphone", nullptr, &params, nullptr,
"BaijiSteamVR Emulated GameCube Microphone", nullptr, &params, nullptr,
nullptr, std::max<u32>(buff_size_samples, minimum_latency), DataCallback,
state_callback, this) != CUBEB_OK)
{
+1 -1
View File
@@ -469,7 +469,7 @@ void Core::SetAVStream()
void Core::SetupEvent()
{
m_event.context = this;
m_event.name = "Dolphin Sync";
m_event.name = "BaijiSteamVR Sync";
m_event.callback = [](mTiming* timing, void* context, u32 cycles_late) {
Core* core = static_cast<Core*>(context);
if (core->m_core->platform(core->m_core) == mPLATFORM_GBA)
@@ -597,7 +597,7 @@ bool GCMemcardDirectory::SetUsedBlocks(int save_index)
block = current_bat->GetNextBlock(block);
if (block == 0)
{
PanicAlertFmtT("BAT incorrect. Dolphin will now exit");
PanicAlertFmtT("BAT incorrect. BaijiSteamVR will now exit");
exit(0);
}
}
@@ -136,7 +136,7 @@ void MemoryCard::FlushThread()
{
PanicAlertFmtT(
"Could not write memory card file {0}.\n\n"
"Are you running Dolphin from a CD/DVD, or is the save file maybe write protected?\n\n"
"Are you running BaijiSteamVR from a CD/DVD, or is the save file maybe write protected?\n\n"
"Are you receiving this after moving the emulator directory?\nIf so, then you may "
"need to re-specify your memory card location in the options.",
m_filename);
+33 -1
View File
@@ -191,7 +191,39 @@ void GCPad::LoadDefaults(const ControllerInterface& ciface)
{
EmulatedController::LoadDefaults(ciface);
#ifdef ANDROID
#ifdef ENABLE_VR
SetDefaultDevice("OpenXR/0/OpenXR Controller");
// Baiju's default pad is the Steam Frame controller, not a keyboard.
m_buttons->SetControlExpression(0, "`Right Button A`");
m_buttons->SetControlExpression(1, "`Right Button B`");
m_buttons->SetControlExpression(2, "`Right Button X`");
m_buttons->SetControlExpression(3, "`Right Button Y`");
m_buttons->SetControlExpression(4, "`Right Button Squeeze`");
m_buttons->SetControlExpression(5, "`Right Button Menu`");
m_main_stick->SetControlExpression(0, "`Left Thumbstick Y+`");
m_main_stick->SetControlExpression(1, "`Left Thumbstick Y-`");
m_main_stick->SetControlExpression(2, "`Left Thumbstick X-`");
m_main_stick->SetControlExpression(3, "`Left Thumbstick X+`");
m_c_stick->SetControlExpression(0, "`Right Thumbstick Y+`");
m_c_stick->SetControlExpression(1, "`Right Thumbstick Y-`");
m_c_stick->SetControlExpression(2, "`Right Thumbstick X-`");
m_c_stick->SetControlExpression(3, "`Right Thumbstick X+`");
m_triggers->SetControlExpression(0, "`Left Button Trigger`");
m_triggers->SetControlExpression(1, "`Right Button Trigger`");
m_triggers->SetControlExpression(2, "`Left Trigger`");
m_triggers->SetControlExpression(3, "`Right Trigger`");
m_dpad->SetControlExpression(0, "`Left D-Pad Up`");
m_dpad->SetControlExpression(1, "`Left D-Pad Down`");
m_dpad->SetControlExpression(2, "`Left D-Pad Left`");
m_dpad->SetControlExpression(3, "`Left D-Pad Right`");
m_rumble->SetControlExpression(0, "Motor");
#elif defined(ANDROID)
// Rumble
m_rumble->SetControlExpression(0, "`Android/0/Device Sensors:Motor 0`");
@@ -178,7 +178,16 @@ void Nunchuk::DoState(PointerWrap& p)
void Nunchuk::LoadDefaults()
{
#ifndef ANDROID
#ifdef ENABLE_VR
m_stick->SetControlExpression(0, "`Left Thumbstick Y+`");
m_stick->SetControlExpression(1, "`Left Thumbstick Y-`");
m_stick->SetControlExpression(2, "`Left Thumbstick X-`");
m_stick->SetControlExpression(3, "`Left Thumbstick X+`");
m_buttons->SetControlExpression(0, "`Left Button Squeeze`");
m_buttons->SetControlExpression(1, "`Left Trigger`");
#elif !defined(ANDROID)
// Stick
m_stick->SetControlExpression(0, "W"); // up
m_stick->SetControlExpression(1, "S"); // down
+27 -1
View File
@@ -693,7 +693,33 @@ void Wiimote::LoadDefaults(const ControllerInterface& ciface)
{
EmulatedController::LoadDefaults(ciface);
#ifdef ANDROID
#ifdef ENABLE_VR
SetDefaultDevice("OpenXR/0/OpenXR Controller");
m_buttons->SetControlExpression(0, "`Right Button A`");
m_buttons->SetControlExpression(1, "`Right Trigger`");
m_buttons->SetControlExpression(2, "`Right Button X`");
m_buttons->SetControlExpression(3, "`Right Button Y`");
m_buttons->SetControlExpression(4, "`Left Button View`");
m_buttons->SetControlExpression(5, "`Right Button Menu`");
m_buttons->SetControlExpression(6, "`Left Button System`");
m_dpad->SetControlExpression(0, "`Left D-Pad Up`");
m_dpad->SetControlExpression(1, "`Left D-Pad Down`");
m_dpad->SetControlExpression(2, "`Left D-Pad Left`");
m_dpad->SetControlExpression(3, "`Left D-Pad Right`");
m_ir->SetControlExpression(0, "`Right Thumbstick Y-`");
m_ir->SetControlExpression(1, "`Right Thumbstick Y+`");
m_ir->SetControlExpression(2, "`Right Thumbstick X-`");
m_ir->SetControlExpression(3, "`Right Thumbstick X+`");
m_ir->SetRelativeInput(false);
for (int i = 0; i < 3; ++i)
m_shake->SetControlExpression(i, "`Right Button Squeeze`");
m_rumble->SetControlExpression(0, "Motor");
#elif defined(ANDROID)
// Rumble
m_rumble->SetControlExpression(0, "`Android/0/Device Sensors:Motor 0`");
+8
View File
@@ -456,6 +456,14 @@ void HotkeyManager::LoadDefaults(const ControllerInterface& ciface)
return fmt::format("@({})", fmt::join(inputs, "+"));
};
#ifdef ENABLE_VR
SetDefaultDevice("OpenXR/0/OpenXR Controller");
// Keep Right Button Menu available for GameCube Start.
set_key_expression(HK_STOP, "`Left Button View`");
// Steam Frame provides headset recentering at the OS/runtime level; leave the app hotkey unset.
return;
#endif
// General hotkeys
set_key_expression(HK_OPEN, hotkey_string({"Ctrl", "O"}));
set_key_expression(HK_PLAY_PAUSE, "F10");
+1 -2
View File
@@ -340,8 +340,7 @@ bool ESDevice::LaunchTitle(u64 title_id, HangPPC hang_ppc)
ERROR_LOG_FMT(IOS_ES, "Refusing to launch the shop channel with default device credentials");
CriticalAlertFmtT(
"You cannot use the Wii Shop Channel without using your own device credentials."
"\nPlease refer to the NAND usage guide for setup instructions: "
"https://dolphin-emu.org/docs/guides/nand-usage-guide/");
"\nPlease check the NAND setup instructions and use your own device credentials.");
// Send the user back to the system menu instead of returning an error, which would
// likely make the system menu crash. Doing this is okay as anyone who has the shop
+2 -2
View File
@@ -51,7 +51,7 @@ IPCReply ESDevice::GetTicketViewCount(const IOCtlVRequest& request)
if (!IsEmulated(TitleID))
{
view_count = 0;
ERROR_LOG_FMT(IOS_ES, "GetViewCount: Dolphin doesn't emulate IOS title {:016x}", TitleID);
ERROR_LOG_FMT(IOS_ES, "GetViewCount: BaijiSteamVR doesn't emulate IOS title {:016x}", TitleID);
}
else if (ShouldReturnFakeViewsForIOSes(TitleID, m_core.m_title_context))
{
@@ -81,7 +81,7 @@ IPCReply ESDevice::GetTicketViews(const IOCtlVRequest& request)
if (!IsEmulated(TitleID))
{
ERROR_LOG_FMT(IOS_ES, "GetViews: Dolphin doesn't emulate IOS title {:016x}", TitleID);
ERROR_LOG_FMT(IOS_ES, "GetViews: BaijiSteamVR doesn't emulate IOS title {:016x}", TitleID);
}
else if (ticket.IsValid())
{
+4 -6
View File
@@ -162,9 +162,8 @@ static std::vector<u8> ReadCertFile(const std::string& path, const std::array<u8
ERROR_LOG_FMT(IOS_SSL, "Failed to read {}", path);
if (!silent)
{
PanicAlertFmtT("IOS: Could not read a file required for SSL services ({0}). Please refer to "
"https://dolphin-emu.org/docs/guides/wii-network-guide/ for "
"instructions on setting up Wii networking.",
PanicAlertFmtT("IOS: Could not read a file required for SSL services ({0}). "
"Check the Wii networking certificate files in the user data directory.",
path);
}
return {};
@@ -177,9 +176,8 @@ static std::vector<u8> ReadCertFile(const std::string& path, const std::array<u8
ERROR_LOG_FMT(IOS_SSL, "Wrong hash for {}", path);
if (!silent)
{
PanicAlertFmtT("IOS: A file required for SSL services ({0}) is invalid. Please refer to "
"https://dolphin-emu.org/docs/guides/wii-network-guide/ for "
"instructions on setting up Wii networking.",
PanicAlertFmtT("IOS: A file required for SSL services ({0}) is invalid. "
"Check the Wii networking certificate files in the user data directory.",
path);
}
return {};
@@ -11,7 +11,7 @@ namespace IOS::HLE
{
std::optional<IPCReply> BluetoothStubDevice::Open(const OpenRequest& request)
{
PanicAlertFmtT("Bluetooth passthrough mode is enabled, but Dolphin was built without libusb."
PanicAlertFmtT("Bluetooth passthrough mode is enabled, but BaijiSteamVR was built without libusb."
" Passthrough mode cannot be used.");
return IPCReply(IPC_ENOENT);
}
@@ -148,7 +148,7 @@ LibUSBBluetoothAdapter::LibUSBBluetoothAdapter()
{
CriticalAlertFmtT(
"Could not find any usable Bluetooth USB adapter for Bluetooth Passthrough.\n"
"The following error occurred when Dolphin tried to use an adapter:\n{0}\n\n"
"The following error occurred when BaijiSteamVR tried to use an adapter:\n{0}\n\n"
"The emulated console will now stop.",
m_last_open_error);
}
@@ -485,8 +485,7 @@ static void ShowFirmwareReadError(std::string_view fw_path)
{
PanicAlertFmtT("Bluetooth passthrough failed to read firmware file from:\n"
"{0}\n\n"
"Refer to https://wiki.dolphin-emu.org/index.php?title=Bluetooth_Passthrough "
"for instructions.",
"Refer to the Bluetooth passthrough setup instructions.",
fw_path);
}
@@ -81,7 +81,7 @@ private:
}
std::string GetCubebStreamName() const override
{
return "Dolphin Emulated Logitech USB Microphone " + std::to_string(m_index);
return "BaijiSteamVR Emulated Logitech USB Microphone " + std::to_string(m_index);
}
s16 GetVolumeModifier() const override
{
@@ -42,7 +42,7 @@ private:
{
return Config::Get(Config::MAIN_WII_SPEAK_MICROPHONE);
}
std::string GetCubebStreamName() const override { return "Dolphin Emulated Wii Speak"; }
std::string GetCubebStreamName() const override { return "BaijiSteamVR Emulated Wii Speak"; }
s16 GetVolumeModifier() const override
{
return Config::Get(Config::MAIN_WII_SPEAK_VOLUME_MODIFIER);
@@ -335,7 +335,7 @@ void CachedInterpreter::Jit(u32 em_address, bool clear_cache_and_retry_on_failur
}
PanicAlertFmtT("JIT failed to find code space after a cache clear. This should never happen. "
"Please report this incident on the bug tracker. Dolphin will now exit.");
"Please report this incident in the BaijiSteamVR project. The application will now exit.");
std::exit(-1);
}
+1 -1
View File
@@ -883,7 +883,7 @@ void Jit64::Jit(u32 em_address, bool clear_cache_and_retry_on_failure)
}
PanicAlertFmtT("JIT failed to find code space after a cache clear. This should never happen. "
"Please report this incident on the bug tracker. Dolphin will now exit.");
"Please report this incident in the BaijiSteamVR project. The application will now exit.");
std::exit(-1);
}
+1 -1
View File
@@ -1079,7 +1079,7 @@ void JitArm64::Jit(u32 em_address, bool clear_cache_and_retry_on_failure)
}
PanicAlertFmtT("JIT failed to find code space after a cache clear. This should never happen. "
"Please report this incident on the bug tracker. Dolphin will now exit.");
"Please report this incident in the BaijiSteamVR project. The application will now exit.");
exit(-1);
}
+2 -2
View File
@@ -743,7 +743,7 @@ static bool ValidateHeaders(const StateHeader& header)
std::string oldest_version = version_range.first;
std::string newest_version = version_range.second;
loaded_str = "Dolphin " + oldest_version + " - " + newest_version;
loaded_str = "BaijiSteamVR " + oldest_version + " - " + newest_version;
}
else if (loaded_version != STATE_VERSION)
{
@@ -754,7 +754,7 @@ static bool ValidateHeaders(const StateHeader& header)
{
const std::string message =
loaded_str.empty() ?
"This savestate was created using an incompatible version of Dolphin" :
"This savestate was created using an incompatible version of BaijiSteamVR" :
"This savestate was created using the incompatible version " + loaded_str;
Core::DisplayMessage(message, OSD::Duration::NORMAL);
}
+9 -9
View File
@@ -1358,22 +1358,22 @@ void VolumeVerifier::Finish()
else
{
m_result.summary_text =
Common::GetStringT("This is a good dump according to Redump.org, but Dolphin has found "
"problems. This might be a bug in Dolphin.");
Common::GetStringT("This is a good dump according to Redump.org, but BaijiSteamVR has found "
"problems. This might be a bug in BaijiSteamVR.");
}
return;
}
if (m_is_datel)
{
m_result.summary_text = Common::GetStringT("Dolphin is unable to verify unlicensed discs.");
m_result.summary_text = Common::GetStringT("BaijiSteamVR is unable to verify unlicensed discs.");
return;
}
if (m_is_tgc)
{
m_result.summary_text =
Common::GetStringT("Dolphin is unable to verify typical TGC files properly, "
Common::GetStringT("BaijiSteamVR is unable to verify typical TGC files properly, "
"since they are not dumps of actual discs.");
return;
}
@@ -1381,7 +1381,7 @@ void VolumeVerifier::Finish()
if (m_is_triforce)
{
m_result.summary_text =
Common::GetStringT("Dolphin is currently unable to verify Triforce games.");
Common::GetStringT("BaijiSteamVR is currently unable to verify Triforce games.");
return;
}
@@ -1393,7 +1393,7 @@ void VolumeVerifier::Finish()
m_result.summary_text =
Common::GetStringT("Compared to the Wii disc release of the game, this is a bad dump. "
"Despite this, it's possible that this is a good dump compared to the "
"Wii U eShop release of the game. Dolphin can't verify this.");
"Wii U eShop release of the game. BaijiSteamVR can't verify this.");
}
else
{
@@ -1429,7 +1429,7 @@ void VolumeVerifier::Finish()
m_result.summary_text = Common::GetStringT(
"Compared to the Wii disc release of the game, problems of low severity were found. "
"Despite this, it's possible that this is a good dump compared to the Wii U eShop "
"release of the game. Dolphin can't verify this.");
"release of the game. BaijiSteamVR can't verify this.");
}
else
{
@@ -1454,13 +1454,13 @@ void VolumeVerifier::Finish()
{
m_result.summary_text +=
Common::GetStringT("\n\nBecause GameCube disc images contain little verification data, "
"there may be problems that Dolphin is unable to detect.");
"there may be problems that BaijiSteamVR is unable to detect.");
}
else if (m_is_not_retail)
{
m_result.summary_text +=
Common::GetStringT("\n\nBecause this title is not for retail Wii consoles, "
"Dolphin cannot ensure that it hasn't been tampered with, even if "
"BaijiSteamVR cannot ensure that it hasn't been tampered with, even if "
"signatures appear valid.");
}
}
+2 -1
View File
@@ -30,6 +30,8 @@ if (WIN32)
DEBUG_POSTFIX D
OUTPUT_NAME DolphinNoGUI
)
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
set_target_properties(dolphin-nogui PROPERTIES OUTPUT_NAME baiji-nogui)
else()
set_target_properties(dolphin-nogui PROPERTIES OUTPUT_NAME dolphin-emu-nogui)
endif()
@@ -66,4 +68,3 @@ endif()
set(CPACK_PACKAGE_EXECUTABLES ${CPACK_PACKAGE_EXECUTABLES} dolphin-nogui)
install(TARGETS dolphin-nogui RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
+2 -1
View File
@@ -33,7 +33,8 @@ static std::unique_ptr<Platform> s_platform;
static void signal_handler(int)
{
constexpr char message[] = "A signal was received. A second signal will force Dolphin to stop.\n";
constexpr char message[] =
"A signal was received. A second signal will force BaijiSteamVR to stop.\n";
#ifdef _WIN32
puts(message);
#else
+11 -52
View File
@@ -14,68 +14,27 @@
AboutDialog::AboutDialog(QWidget* parent) : QDialog(parent)
{
setWindowTitle(tr("About Dolphin"));
QString branch_str = QString::fromStdString(Common::GetScmBranchStr());
const int commits_ahead = Common::GetScmCommitsAheadMaster();
if (commits_ahead > 0)
{
branch_str = tr("%1 (%2)").arg(
branch_str,
// i18n: A positive number of version control commits made compared to some named branch
tr("%1 commit(s) ahead of %2").arg(commits_ahead).arg(QStringLiteral("master")));
}
setWindowTitle(tr("About BaijiSteamVR"));
const QString text =
QStringLiteral(R"(
<p style='font-size:38pt; font-weight:400;'>Dolphin</p>
<p style='font-size:38pt; font-weight:400;'>BaijiSteamVR</p>
<p style='font-size:18pt;'>%VERSION_STRING%</p>
<p style='font-size:18pt;'>%VERSION%</p>
<p style='font-size: small;'>
%BRANCH%<br>
%REVISION%<br><br>
%QT_VERSION%
<p>
BaijiSteamVR is a free and open-source GameCube and Wii emulator.
</p>
<p>
%CHECK_FOR_UPDATES%: <a href='https://dolphin-emu.org/download'>dolphin-emu.org/download</a>
<a href='https://github.com/thejerf/baijiSteamVR'>BaijiSteamVR project page</a>
</p>
<p>
%ABOUT_DOLPHIN%
</p>
<p>
%GAMES_YOU_OWN%
</p>
<p>
<a href='https://github.com/dolphin-emu/dolphin/blob/master/COPYING'>%LICENSE%</a> |
<a href='https://github.com/dolphin-emu/dolphin/graphs/contributors'>%AUTHORS%</a> |
<a href='https://forums.dolphin-emu.org/'>%SUPPORT%</a>
Licensed under GPL-2.0-or-later. See COPYING and LICENSES in the installation for license texts.
)")
.replace(QStringLiteral("%VERSION_STRING%"),
QString::fromUtf8(Common::GetScmDescStr().c_str()))
.replace(QStringLiteral("%BRANCH%"),
// i18n: "Branch" means the version control term, not a literal tree branch.
tr("Branch: %1").arg(branch_str))
.replace(QStringLiteral("%REVISION%"),
tr("Revision: %1").arg(QString::fromUtf8(Common::GetScmRevGitStr().c_str())))
.replace(QStringLiteral("%QT_VERSION%"),
tr("Using Qt %1").arg(QStringLiteral(QT_VERSION_STR)))
.replace(QStringLiteral("%CHECK_FOR_UPDATES%"), tr("Check for updates"))
.replace(QStringLiteral("%ABOUT_DOLPHIN%"),
// i18n: The word "free" in the standard phrase "free and open source"
// is "free" as in "freedom" - it refers to certain properties of the
// software's license, not the software's price. (It is true that Dolphin
// can be downloaded at no cost, but that's not what this message says.)
tr("Dolphin is a free and open-source GameCube and Wii emulator."))
.replace(QStringLiteral("%GAMES_YOU_OWN%"),
tr("This software should not be used to play games you do not legally own."))
.replace(QStringLiteral("%LICENSE%"), tr("License"))
.replace(QStringLiteral("%AUTHORS%"), tr("Authors"))
.replace(QStringLiteral("%SUPPORT%"), tr("Support"));
.replace(QStringLiteral("%VERSION%"),
QString::fromUtf8(Common::GetScmDescStr().c_str()));
QLabel* text_label = new QLabel(text);
text_label->setTextInteractionFlags(Qt::TextBrowserInteraction);
@@ -88,8 +47,8 @@ AboutDialog::AboutDialog(QWidget* parent) : QDialog(parent)
// in your translation, please use the type of curly quotes that's appropriate for
// your language. If you aren't sure which type is appropriate, see
// https://en.wikipedia.org/wiki/Quotation_mark#Specific_language_features
tr("\u00A9 2003-2024+ Dolphin Team. \u201cGameCube\u201d and \u201cWii\u201d are "
"trademarks of Nintendo. Dolphin is not affiliated with Nintendo in any way.")));
tr("\u00A9 2003-2024+ Dolphin Team. \u201cGameCube\u201d and \u201cWii\u201d are "
"trademarks of Nintendo. BaijiSteamVR is not affiliated with Nintendo.")));
QLabel* logo = new QLabel();
logo->setPixmap(Resources::GetAppIcon().pixmap(200, 200));
@@ -66,7 +66,7 @@ void AchievementSettingsWidget::CreateLayout()
new ToolTipCheckBox(tr("Enable RetroAchievements.org Integration"));
m_common_integration_enabled_input->SetDescription(
tr("Enable integration with RetroAchievements for earning achievements and competing in "
"leaderboards.<br><br>Must log in with a RetroAchievements account to use. Dolphin does "
"leaderboards.<br><br>Must log in with a RetroAchievements account to use. BaijiSteamVR does "
"not save your password locally and uses an API token to maintain login."));
m_common_username_label = new QLabel(tr("Username"));
m_common_username_input = new QLineEdit(QStringLiteral(""));
+12
View File
@@ -1,3 +1,4 @@
if (MSVC)
if(_M_ARM_64)
list(APPEND CMAKE_PREFIX_PATH "${CMAKE_SOURCE_DIR}/Externals/Qt/Qt6.5.1/ARM64")
@@ -338,6 +339,8 @@ add_executable(dolphin-emu
NetPlay/PadMappingDialog.h
NANDRepairDialog.cpp
NANDRepairDialog.h
FrameFlatModeInputWarningDialog.cpp
FrameFlatModeInputWarningDialog.h
NKitWarningDialog.cpp
NKitWarningDialog.h
QtUtils/AnalyticsPrompt.cpp
@@ -450,6 +453,10 @@ add_executable(dolphin-emu
WiiUpdate.h
)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
set_target_properties(dolphin-emu PROPERTIES OUTPUT_NAME baiji)
endif()
if (WIN32)
target_sources(dolphin-emu PRIVATE
Styles/Dark/dark.qrc
@@ -622,6 +629,9 @@ if(GETTEXT_MSGFMT_EXECUTABLE)
if(WIN32)
set(mo_dir ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/Languages)
set(mo ${mo_dir}/${lang}.mo)
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
set(mo_dir ${CMAKE_CURRENT_BINARY_DIR}/${lang})
set(mo ${mo_dir}/baiji.mo)
else()
set(mo_dir ${CMAKE_CURRENT_BINARY_DIR}/${lang})
set(mo ${mo_dir}/dolphin-emu.mo)
@@ -632,6 +642,8 @@ if(GETTEXT_MSGFMT_EXECUTABLE)
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
set_source_files_properties(${mo} PROPERTIES MACOSX_PACKAGE_LOCATION "Resources/${lang}.lproj")
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
install(FILES ${mo} DESTINATION ${datadir}/locale/${lang}/LC_MESSAGES)
else()
install(FILES ${mo} DESTINATION share/locale/${lang}/LC_MESSAGES)
endif()
@@ -35,7 +35,7 @@ CheatWarningWidget::CheatWarningWidget(const std::string& game_id, bool restart_
void CheatWarningWidget::CreateWidgets()
{
m_text = new QLabel();
m_config_button = new QPushButton(tr("Configure Dolphin"));
m_config_button = new QPushButton(tr("Configure BaijiSteamVR"));
m_config_button->setHidden(true);
@@ -62,7 +62,7 @@ void CheatWarningWidget::Update(bool running)
{
hide_widget = false;
hide_config_button = false;
m_text->setText(tr("Dolphin's cheat system is currently disabled."));
m_text->setText(tr("BaijiSteamVR's cheat system is currently disabled."));
}
setHidden(hide_widget);
@@ -48,10 +48,7 @@ void DualShockUDPClientWidget::CreateWidgets()
auto* description =
new QLabel(tr("DSU protocol enables the use of input and motion data from compatible "
"sources, like PlayStation, Nintendo Switch and Steam controllers.<br><br>"
"For setup instructions, "
"<a href=\"https://wiki.dolphin-emu.org/index.php?title=DSU_Client\">"
"refer to this page</a>."));
"sources, like PlayStation, Nintendo Switch and Steam controllers."));
description->setTextFormat(Qt::RichText);
description->setWordWrap(true);
description->setTextInteractionFlags(Qt::TextBrowserInteraction);
@@ -54,9 +54,7 @@ void FreeLookWidget::CreateLayout()
auto* description =
new QLabel(tr("Free Look allows for manipulation of the in-game camera. "
"Different camera types are available from the dropdown.<br><br>"
"For detailed instructions, "
"<a href=\"https://wiki.dolphin-emu.org/index.php?title=Free_Look\">"
"refer to this page</a>."));
"Use the camera type and movement controls to adjust the view."));
description->setTextFormat(Qt::RichText);
description->setWordWrap(true);
description->setTextInteractionFlags(Qt::TextBrowserInteraction);
@@ -263,7 +263,7 @@ void GameConfigWidget::CreateWidgets()
"settings are disabled when the global graphics backend doesn't "
"match the game setting.");
auto* const help_label = new QLabel(tr("These settings override core Dolphin settings."));
auto* const help_label = new QLabel(tr("These settings override core BaijiSteamVR settings."));
auto* const help_widget =
QtUtils::CreateIconWarning(this, QStyle::SP_MessageBoxQuestion, help_label);
@@ -94,6 +94,14 @@ void GamecubeControllersWidget::CreateLayout()
m_gc_layout->addWidget(gc_label, controller_row, 0);
m_gc_layout->addWidget(gc_box, controller_row, 1);
m_gc_layout->addWidget(gc_button, controller_row, 2);
// Baiju exposes one controller port on the Frame; retain the other ports in core config.
if (i != 0)
{
gc_label->hide();
gc_box->hide();
gc_button->hide();
}
}
m_gc_box->setLayout(m_gc_layout);
@@ -268,7 +268,7 @@ void AdvancedWidget::AddDescriptions()
"leave this unchecked.</dolphin_emphasis>");
static const char TR_LOG_RENDERTIME_DESCRIPTION[] = QT_TR_NOOP(
"Logs the render time of every frame to User/Logs/render_time.txt.<br><br>Use this "
"feature to measure Dolphin's performance.<br><br><dolphin_emphasis>If "
"feature to measure BaijiSteamVR's performance.<br><br><dolphin_emphasis>If "
"unsure, leave this unchecked.</dolphin_emphasis>");
static const char TR_DUMP_TEXTURE_DESCRIPTION[] =
QT_TR_NOOP("Dumps decoded game textures based on the other flags to "
@@ -360,7 +360,7 @@ void AdvancedWidget::AddDescriptions()
"<dolphin_emphasis>If unsure, leave this unchecked.</dolphin_emphasis>");
static const char TR_COMMAND_BUFFERS_IN_FLIGHT_DESCRIPTION[] = QT_TR_NOOP(
"How many command lists (D3D12) or command buffers (Vulkan) the backend keeps in flight. "
"Each time one is submitted, Dolphin reuses the oldest and must wait for it to finish on "
"Each time one is submitted, BaijiSteamVR reuses the oldest and must wait for it to finish on "
"the GPU, so a shallow ring stalls whenever the GPU is slower to complete work than Dolphin "
"is to queue it. Raising this can recover a lot of performance in games that submit many "
"times per frame, such as those needing CPU EFB Access, and in VR.<br><br>Higher values cost "
@@ -46,8 +46,6 @@ EnhancementsWidget::EnhancementsWidget(GraphicsPane* gfx_pane)
connect(gfx_pane, &GraphicsPane::UseGPUTextureDecodingChanged, this, [this] {
m_arbitrary_mipmap_detection->setEnabled(!ReadSetting(Config::GFX_ENABLE_GPU_TEXTURE_DECODING));
});
connect(&Settings::Instance(), &Settings::ConfigChanged, this,
&EnhancementsWidget::UpdateStereoscopyAvailability);
}
constexpr int ANISO_1x = std::to_underlying(AnisotropicFilteringMode::Force1x);
@@ -209,46 +207,7 @@ void EnhancementsWidget::CreateWidgets()
enhancements_layout->addWidget(m_hdr, row, 1, 1, -1);
++row;
// Stereoscopy
m_stereoscopy_box = new QGroupBox(tr("Stereoscopy"));
auto* stereoscopy_layout = new QGridLayout();
m_stereoscopy_box->setLayout(stereoscopy_layout);
m_3d_mode = new ConfigChoice({tr("Off"), tr("Side-by-Side"), tr("Top-and-Bottom"), tr("Anaglyph"),
tr("HDMI 3D"), tr("Passive")},
Config::GFX_STEREO_MODE, m_game_layer);
m_3d_depth = new ConfigFloatSlider(0, Config::GFX_STEREO_DEPTH_MAXIMUM, Config::GFX_STEREO_DEPTH,
1.0f, m_game_layer);
m_3d_convergence = new ConfigFloatSlider(0, Config::GFX_STEREO_CONVERGENCE_MAXIMUM,
Config::GFX_STEREO_CONVERGENCE, 0.01f, m_game_layer);
m_3d_depth_value = new QLabel();
m_3d_convergence_value = new QLabel();
m_3d_swap_eyes = new ConfigBool(tr("Swap Eyes"), Config::GFX_STEREO_SWAP_EYES, m_game_layer);
m_3d_per_eye_resolution = new ConfigBool(
tr("Use Full Resolution Per Eye"), Config::GFX_STEREO_PER_EYE_RESOLUTION_FULL, m_game_layer);
stereoscopy_layout->addWidget(new QLabel(tr("Stereoscopic 3D Mode:")), 0, 0);
stereoscopy_layout->addWidget(m_3d_mode, 0, 1);
stereoscopy_layout->addWidget(new ConfigFloatLabel(tr("Depth:"), m_3d_depth), 1, 0);
stereoscopy_layout->addWidget(m_3d_depth, 1, 1);
stereoscopy_layout->addWidget(m_3d_depth_value, 1, 2);
stereoscopy_layout->addWidget(new ConfigFloatLabel(tr("Convergence:"), m_3d_convergence), 2, 0);
stereoscopy_layout->addWidget(m_3d_convergence, 2, 1);
stereoscopy_layout->addWidget(m_3d_convergence_value, 2, 2);
stereoscopy_layout->addWidget(m_3d_swap_eyes, 3, 0);
stereoscopy_layout->addWidget(m_3d_per_eye_resolution, 4, 0);
m_3d_depth_value->setText(QString::asprintf("%.0f", m_3d_depth->GetValue()));
m_3d_convergence_value->setText(QString::asprintf("%.2f", m_3d_convergence->GetValue()));
auto current_stereo_mode = ReadSetting(Config::GFX_STEREO_MODE);
if (current_stereo_mode != StereoMode::SBS && current_stereo_mode != StereoMode::TAB)
m_3d_per_eye_resolution->hide();
main_layout->addWidget(enhancements_box);
main_layout->addWidget(m_stereoscopy_box);
main_layout->addStretch();
setLayout(main_layout);
@@ -256,16 +215,6 @@ void EnhancementsWidget::CreateWidgets()
void EnhancementsWidget::ConnectWidgets()
{
connect(m_3d_mode, &QComboBox::currentIndexChanged, [this] {
auto current_stereo_mode = ReadSetting(Config::GFX_STEREO_MODE);
LoadPostProcessingShaders();
if (current_stereo_mode == StereoMode::SBS || current_stereo_mode == StereoMode::TAB)
m_3d_per_eye_resolution->show();
else
m_3d_per_eye_resolution->hide();
});
connect(m_post_processing_effect, &QComboBox::currentIndexChanged, this,
&EnhancementsWidget::ShaderChanged);
@@ -273,12 +222,6 @@ void EnhancementsWidget::ConnectWidgets()
&EnhancementsWidget::ConfigureColorCorrection);
connect(m_configure_post_processing_effect, &QPushButton::clicked, this,
&EnhancementsWidget::ConfigurePostProcessingShader);
connect(m_3d_depth, &ConfigFloatSlider::valueChanged, this,
[this] { m_3d_depth_value->setText(QString::asprintf("%.0f", m_3d_depth->GetValue())); });
connect(m_3d_convergence, &ConfigFloatSlider::valueChanged, this, [this] {
m_3d_convergence_value->setText(QString::asprintf("%.2f", m_3d_convergence->GetValue()));
});
}
template <typename T>
@@ -353,8 +296,6 @@ void EnhancementsWidget::OnBackendChanged()
m_configure_color_correction->setEnabled(g_backend_info.bSupportsPostProcessing);
m_hdr->setEnabled(g_backend_info.bSupportsHDROutput);
UpdateStereoscopyAvailability();
// PostProcessing
const bool supports_postprocessing = g_backend_info.bSupportsPostProcessing;
if (!supports_postprocessing)
@@ -375,13 +316,6 @@ void EnhancementsWidget::OnBackendChanged()
UpdateAntialiasingOptions();
}
void EnhancementsWidget::UpdateStereoscopyAvailability()
{
const bool supports_stereoscopy = g_backend_info.bSupportsGeometryShaders;
const bool openxr_enabled = Config::Get(Config::GFX_VR_ENABLE_OPENXR);
m_stereoscopy_box->setEnabled(supports_stereoscopy && !openxr_enabled);
}
void EnhancementsWidget::ShaderChanged()
{
auto shader = ReadSetting(Config::GFX_ENHANCE_POST_SHADER);
@@ -416,7 +350,6 @@ void EnhancementsWidget::OnConfigChanged()
// being global.
m_texture_filtering_combo->setEnabled(ReadSetting(Config::GFX_HACK_FAST_TEXTURE_SAMPLING));
m_arbitrary_mipmap_detection->setEnabled(!ReadSetting(Config::GFX_ENABLE_GPU_TEXTURE_DECODING));
UpdateStereoscopyAvailability();
UpdateAntialiasingOptions();
// Needs to update after deleting a key for 3d settings.
@@ -538,28 +471,6 @@ void EnhancementsWidget::AddDescriptions()
"detail.<br><br>Disabling fog will break some games which rely on proper fog "
"emulation.<br><br><dolphin_emphasis>If unsure, leave this "
"unchecked.</dolphin_emphasis>");
static const char TR_3D_MODE_DESCRIPTION[] = QT_TR_NOOP(
"Selects the stereoscopic 3D mode. Stereoscopy allows a better feeling "
"of depth if the necessary hardware is present. Heavily decreases "
"emulation speed and sometimes causes issues.<br><br>Side-by-Side and Top-and-Bottom are "
"used by most 3D TVs.<br>Anaglyph is used for Red-Cyan colored glasses.<br>HDMI 3D is "
"used when the monitor supports 3D display resolutions.<br>Passive is another type of 3D "
"used by some TVs."
"<br><br><dolphin_emphasis>If unsure, select Off.</dolphin_emphasis>");
static const char TR_3D_DEPTH_DESCRIPTION[] = QT_TR_NOOP(
"Controls the separation distance between the virtual cameras.<br><br>A higher "
"value creates a stronger feeling of depth while a lower value is more comfortable.");
static const char TR_3D_CONVERGENCE_DESCRIPTION[] = QT_TR_NOOP(
"Controls the distance of the convergence plane. This is the distance at which "
"virtual objects will appear to be in front of the screen.<br><br>A higher value creates "
"stronger out-of-screen effects while a lower value is more comfortable.");
static const char TR_3D_SWAP_EYES_DESCRIPTION[] = QT_TR_NOOP(
"Swaps the left and right eye. Most useful in side-by-side stereoscopy "
"mode.<br><br><dolphin_emphasis>If unsure, leave this unchecked.</dolphin_emphasis>");
static const char TR_3D_PER_EYE_RESOLUTION_DESCRIPTION[] =
QT_TR_NOOP("Whether each eye gets full or half image resolution when using side-by-side "
"or above-and-below 3D."
"<br><br><dolphin_emphasis>If unsure, leave this unchecked.</dolphin_emphasis>");
static const char TR_FORCE_24BIT_DESCRIPTION[] = QT_TR_NOOP(
"Forces the game to render the RGB color channels in 24-bit, thereby increasing "
"quality by reducing color banding.<br><br>Has no impact on performance and causes "
@@ -620,19 +531,6 @@ void EnhancementsWidget::AddDescriptions()
m_arbitrary_mipmap_detection->SetDescription(tr(TR_ARBITRARY_MIPMAP_DETECTION_DESCRIPTION));
m_hdr->SetDescription(tr(TR_HDR_DESCRIPTION));
m_3d_mode->SetTitle(tr("Stereoscopic 3D Mode"));
m_3d_mode->SetDescription(tr(TR_3D_MODE_DESCRIPTION));
m_3d_depth->SetTitle(tr("Depth"));
m_3d_depth->SetDescription(tr(TR_3D_DEPTH_DESCRIPTION));
m_3d_convergence->SetTitle(tr("Convergence"));
m_3d_convergence->SetDescription(tr(TR_3D_CONVERGENCE_DESCRIPTION));
m_3d_per_eye_resolution->SetDescription(tr(TR_3D_PER_EYE_RESOLUTION_DESCRIPTION));
m_3d_swap_eyes->SetDescription(tr(TR_3D_SWAP_EYES_DESCRIPTION));
}
void EnhancementsWidget::ConfigureColorCorrection()
@@ -11,7 +11,6 @@ class ConfigComplexChoice;
class ConfigStringChoice;
class ConfigFloatSlider;
class GraphicsPane;
class QGroupBox;
class QPushButton;
class QLabel;
class ToolTipPushButton;
@@ -38,7 +37,6 @@ private:
void AddDescriptions();
void OnBackendChanged();
void UpdateStereoscopyAvailability();
void UpdateAntialiasingOptions();
void LoadPostProcessingShaders();
void ShaderChanged();
@@ -64,15 +62,5 @@ private:
ConfigBool* m_arbitrary_mipmap_detection;
ConfigBool* m_hdr;
// Stereoscopy
QGroupBox* m_stereoscopy_box;
ConfigChoice* m_3d_mode;
ConfigFloatSlider* m_3d_depth;
QLabel* m_3d_depth_value;
ConfigFloatSlider* m_3d_convergence;
QLabel* m_3d_convergence_value;
ConfigBool* m_3d_swap_eyes;
ConfigBool* m_3d_per_eye_resolution;
Config::Layer* m_game_layer = nullptr;
};
@@ -234,14 +234,14 @@ void GeneralWidget::AddDescriptions()
QT_TR_NOOP("Automatically adjusts the window size to the internal resolution.<br><br>"
"<dolphin_emphasis>If unsure, leave this unchecked.</dolphin_emphasis>");
static const char TR_RENDER_TO_MAINWINDOW_DESCRIPTION[] =
QT_TR_NOOP("Uses the main Dolphin window for rendering rather than "
QT_TR_NOOP("Uses the main BaijiSteamVR window for rendering rather than "
"a separate render window.<br><br><dolphin_emphasis>If unsure, leave "
"this unchecked.</dolphin_emphasis>");
static const char TR_ASPECT_RATIO_DESCRIPTION[] = QT_TR_NOOP(
"Selects which aspect ratio to use for displaying the game."
"<br><br>The aspect ratio of the image sent out by the original consoles varied depending on "
"the game and rarely exactly matched 4:3 or 16:9. Some of the image would be cut off by the "
"edges of the TV, or the image wouldn't fill the TV entirely. By default, Dolphin shows the "
"edges of the TV, or the image wouldn't fill the TV entirely. By default, BaijiSteamVR shows the "
"whole image without distorting its proportions, which means it's normal for the image to "
"not entirely fill your display."
"<br><br><b>Auto</b>: Mimics a TV with either a 4:3 or 16:9 aspect ratio, depending on which "
@@ -26,7 +26,7 @@ void GraphicsModWarningWidget::CreateWidgets()
{
m_text = new QLabel();
m_config_button = new QPushButton(tr("Configure Dolphin"));
m_config_button = new QPushButton(tr("Configure BaijiSteamVR"));
m_config_button->setHidden(true);
auto* const layout = new QHBoxLayout{this};
@@ -6,12 +6,14 @@
#include <fmt/core.h>
#include <QCheckBox>
#include <QComboBox>
#include <QDialogButtonBox>
#include <QFormLayout>
#include <QGroupBox>
#include <QHBoxLayout>
#include <QLabel>
#include <QPushButton>
#include <QSignalBlocker>
#include "DolphinQt/Config/Mapping/IOWindow.h"
#include "DolphinQt/Config/Mapping/MappingButton.h"
@@ -31,6 +33,88 @@
#include "InputCommon/ControllerEmu/Setting/NumericSetting.h"
#include "InputCommon/ControllerEmu/StickGate.h"
#include "InputCommon/ControllerInterface/ControllerInterface.h"
#include "InputCommon/ControllerInterface/MappingCommon.h"
#include "InputCommon/InputConfig.h"
namespace
{
class FrameMappingComboBox final : public QComboBox
{
public:
FrameMappingComboBox(MappingWidget* widget, ControlReference* reference)
: QComboBox(widget), m_reference(reference)
{
setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon);
setMinimumContentsLength(18);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
addItem(tr("Unmapped"), QString{});
connect(widget, &MappingWidget::ConfigChanged, this, [this, widget] {
PopulateControls(widget);
UpdateSelection();
});
}
ControlReference* GetControlReference() const { return m_reference; }
private:
void PopulateControls(MappingWidget* widget)
{
if (m_populated || !widget->GetController())
return;
const auto& default_device = widget->GetController()->GetDefaultDevice();
const auto device = g_controller_interface.FindDevice(default_device);
if (!device)
return;
ciface::Core::DeviceQualifier control_device;
control_device.FromDevice(device.get());
const auto add_control = [this, &control_device, &default_device](
const ciface::Core::Device::Control* control) {
if (control->IsHidden())
return;
const auto expression = ciface::MappingCommon::GetExpressionForControl(
control->GetName(), control_device, default_device, ciface::MappingCommon::Quote::On);
addItem(QString::fromStdString(control->GetName()), QString::fromStdString(expression));
};
if (m_reference->IsInput())
{
for (const auto* input : device->Inputs())
add_control(input);
}
else
{
for (const auto* output : device->Outputs())
add_control(output);
}
m_populated = true;
}
void UpdateSelection()
{
const auto lock = ControllerEmu::EmulatedController::GetStateLock();
const QString expression = QString::fromStdString(m_reference->GetExpression());
QSignalBlocker blocker(this);
int index = findData(expression);
if (index == -1 && !expression.isEmpty())
{
addItem(tr("Current mapping: %1").arg(expression), expression);
index = count() - 1;
}
setCurrentIndex(index);
}
ControlReference* const m_reference;
bool m_populated = false;
};
} // namespace
MappingWidget::MappingWidget(MappingWindow* parent) : m_parent(parent)
{
@@ -403,20 +487,45 @@ void MappingWidget::CreateControl(const ControllerEmu::Control* control, QFormLa
(is_modifier ? ControlType::ModifierInput : ControlType::NormalInput) :
ControlType::Output;
auto* const button = new MappingButton(this, control->control_ref.get(), control_type);
if (control->control_ref->IsInput())
QWidget* mapping_widget = nullptr;
if (m_parent->IsFrameControllerMapping())
{
if (m_previous_mapping_button)
auto* const combo = new FrameMappingComboBox(this, control->control_ref.get());
mapping_widget = combo;
connect(combo, &QComboBox::currentIndexChanged, this, [this, combo] {
auto* const control_reference = combo->GetControlReference();
const auto expression = combo->currentData().toString().toStdString();
auto* const controller = GetController();
{
const auto lock = controller->GetStateLock();
control_reference->SetExpression(expression);
controller->UpdateSingleControlReference(g_controller_interface, control_reference);
controller->GetConfig()->GenerateControllerTextures();
}
emit ConfigChanged();
GetParent()->Save();
});
}
else
{
auto* const button = new MappingButton(this, control->control_ref.get(), control_type);
mapping_widget = button;
if (control->control_ref->IsInput())
{
connect(m_previous_mapping_button, &MappingButton::QueueNextButtonMapping,
[this, button] { m_parent->QueueInputDetection(button); });
if (m_previous_mapping_button)
{
connect(m_previous_mapping_button, &MappingButton::QueueNextButtonMapping,
[this, button] { m_parent->QueueInputDetection(button); });
}
m_previous_mapping_button = button;
}
m_previous_mapping_button = button;
}
button->setMinimumWidth(100);
button->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
mapping_widget->setMinimumWidth(100);
mapping_widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
const bool translate = control->translate == ControllerEmu::Translatability::Translate;
const QString translated_name =
@@ -430,12 +539,12 @@ void MappingWidget::CreateControl(const ControllerEmu::Control* control, QFormLa
auto* const hbox = new QHBoxLayout;
hbox->setSpacing(0);
hbox->addWidget(button_indicator);
hbox->addWidget(button);
hbox->addWidget(mapping_widget);
layout->addRow(translated_name, hbox);
}
else
{
layout->addRow(translated_name, button);
layout->addRow(translated_name, mapping_widget);
}
}
@@ -53,7 +53,6 @@
#include "DolphinQt/Config/Mapping/HotkeyVR.h"
#include "DolphinQt/Config/Mapping/HotkeyWii.h"
#include "DolphinQt/Config/Mapping/MappingCommon.h"
#include "DolphinQt/Config/Mapping/OpenXRWiimoteConfigSessionController.h"
#include "DolphinQt/Config/Mapping/WiimoteEmuExtension.h"
#include "DolphinQt/Config/Mapping/WiimoteEmuExtensionMotionInput.h"
#include "DolphinQt/Config/Mapping/WiimoteEmuExtensionMotionSimulation.h"
@@ -79,9 +78,9 @@
namespace
{
constexpr const char* OPENXR_WIIMOTE_DEFAULT_PROFILE = "OpenXR Wii Remote.ini";
constexpr const char* OPENXR_GCPAD_DEFAULT_PROFILE = "Quest Touch GameCube.ini";
constexpr const char* OPENXR_HOTKEY_DEFAULT_PROFILE = "Quest.ini";
constexpr const char* STEAM_FRAME_WIIMOTE_DEFAULT_PROFILE = "Steam Frame Wii Remote + Nunchuk.ini";
constexpr const char* STEAM_FRAME_GCPAD_DEFAULT_PROFILE = "Steam Frame GameCube.ini";
constexpr const char* STEAM_FRAME_HOTKEY_DEFAULT_PROFILE = "Steam Frame.ini";
constexpr const char* OPENXR_CONTROLLER_DEVICE = "OpenXR/0/OpenXR Controller";
}
@@ -116,32 +115,11 @@ MappingWindow::MappingWindow(QWidget* parent, Type type, int port_num)
const auto lock = GetController()->GetStateLock();
emit ConfigChanged();
#if defined(ENABLE_VR) && defined(HAS_VULKAN)
const bool is_openxr_wiimote_mapper =
m_mapping_type == Type::MAPPING_WIIMOTE_EMU && m_is_openxr_wiimote;
const bool is_gamecube_mapper = m_mapping_type == Type::MAPPING_GCPAD;
const bool is_hotkey_mapper = m_mapping_type == Type::MAPPING_HOTKEYS;
if (is_openxr_wiimote_mapper || is_gamecube_mapper || is_hotkey_mapper)
{
using TargetType = OpenXRWiimoteConfigSessionController::TargetType;
const TargetType target_type = is_openxr_wiimote_mapper ?
TargetType::WiiRemote :
(is_gamecube_mapper ? TargetType::GameCubeController :
TargetType::Hotkeys);
m_openxr_config_session_controller =
new OpenXRWiimoteConfigSessionController(this, m_port, target_type);
if (auto* outer = qobject_cast<QVBoxLayout*>(m_devices_box->layout()))
outer->addWidget(m_openxr_config_session_controller->GetButton(), 0);
UpdateOpenXRConfigButtonVisibility();
}
#endif
#ifdef ENABLE_VR
if (m_is_openxr_wiimote)
{
m_openxr_profile_label = new QLabel(
tr("OpenXR: not connected\n"
"Launch a game or use \"Configure in VR\" to bind VR controller inputs."));
m_openxr_profile_label =
new QLabel(tr("OpenXR: not connected\nLaunch a game to bind VR controller inputs."));
m_openxr_profile_label->setWordWrap(true);
auto* outer = qobject_cast<QVBoxLayout*>(m_devices_box->layout());
if (outer)
@@ -171,7 +149,8 @@ void MappingWindow::CreateDevicesLayout()
m_devices_box = new QGroupBox(tr("Device"));
m_devices_combo = new QComboBox();
auto* const options = new QToolButton();
m_device_options = new QToolButton();
auto* const options = m_device_options;
// Make it more apparent that this is a menu with more options.
options->setPopupMode(QToolButton::ToolButtonPopupMode::MenuButtonPopup);
@@ -309,8 +288,6 @@ void MappingWindow::ConnectWidgets()
connect(&Settings::Instance(), &Settings::DevicesChanged, this, &MappingWindow::ConfigChanged);
connect(this, &MappingWindow::ConfigChanged, this, &MappingWindow::UpdateDeviceList);
connect(m_devices_combo, &QComboBox::currentIndexChanged, this, &MappingWindow::OnSelectDevice);
connect(m_devices_combo, &QComboBox::currentIndexChanged, this,
&MappingWindow::UpdateOpenXRConfigButtonVisibility);
connect(m_reset_clear, &QPushButton::clicked, this, &MappingWindow::OnClearFieldsPressed);
connect(m_reset_default, &QPushButton::clicked, this, &MappingWindow::OnDefaultFieldsPressed);
@@ -483,17 +460,17 @@ void MappingWindow::OnSelectDevice(int)
bool MappingWindow::IsCreateOtherDeviceMappingsEnabled() const
{
return m_other_device_mappings->isChecked();
return !IsFrameControllerMapping() && m_other_device_mappings->isChecked();
}
bool MappingWindow::IsWaitForAlternateMappingsEnabled() const
{
return m_wait_for_alternate_mappings->isChecked();
return !IsFrameControllerMapping() && m_wait_for_alternate_mappings->isChecked();
}
bool MappingWindow::IsIterativeMappingEnabled() const
{
return m_iterative_mapping->isChecked();
return !IsFrameControllerMapping() && m_iterative_mapping->isChecked();
}
void MappingWindow::RefreshDevices()
@@ -513,47 +490,60 @@ void MappingWindow::UpdateDeviceList()
m_devices_combo->clear();
for (const auto& name : g_controller_interface.GetAllDeviceStrings())
if (IsFrameControllerMapping())
{
const auto qname = QString::fromStdString(name);
m_devices_combo->addItem(qname, qname);
}
const auto fixed_device = QString::fromLatin1(OPENXR_CONTROLLER_DEVICE);
m_devices_combo->addItem(tr("Steam Frame Controller"), fixed_device);
m_devices_combo->setCurrentIndex(0);
m_devices_combo->setEnabled(false);
m_device_options->hide();
const auto default_device = m_controller->GetDefaultDevice().ToString();
if (!default_device.empty())
{
const auto default_device_index =
m_devices_combo->findText(QString::fromStdString(default_device));
if (default_device_index != -1)
if (m_controller->GetDefaultDevice().ToString() != OPENXR_CONTROLLER_DEVICE)
{
m_devices_combo->setCurrentIndex(default_device_index);
}
else
{
// Selected device is not currently attached.
m_devices_combo->insertSeparator(m_devices_combo->count());
const auto qname = QString::fromStdString(default_device);
m_devices_combo->addItem(QLatin1Char{'['} + tr("disconnected") + QStringLiteral("] ") + qname,
qname);
m_devices_combo->setCurrentIndex(m_devices_combo->count() - 1);
m_controller->SetDefaultDevice(OPENXR_CONTROLLER_DEVICE);
m_controller->UpdateReferences(g_controller_interface);
}
}
else
{
m_devices_combo->setEnabled(true);
m_device_options->show();
UpdateOpenXRConfigButtonVisibility();
for (const auto& name : g_controller_interface.GetAllDeviceStrings())
{
const auto qname = QString::fromStdString(name);
m_devices_combo->addItem(qname, qname);
}
const auto default_device = m_controller->GetDefaultDevice().ToString();
if (!default_device.empty())
{
const auto default_device_index =
m_devices_combo->findText(QString::fromStdString(default_device));
if (default_device_index != -1)
{
m_devices_combo->setCurrentIndex(default_device_index);
}
else
{
// Selected device is not currently attached.
m_devices_combo->insertSeparator(m_devices_combo->count());
const auto qname = QString::fromStdString(default_device);
m_devices_combo->addItem(QLatin1Char{'['} + tr("disconnected") + QStringLiteral("] ") +
qname,
qname);
m_devices_combo->setCurrentIndex(m_devices_combo->count() - 1);
}
}
}
}
void MappingWindow::UpdateOpenXRConfigButtonVisibility()
bool MappingWindow::IsFrameControllerMapping() const
{
if (!m_openxr_config_session_controller)
return;
const bool visible =
m_mapping_type == Type::MAPPING_WIIMOTE_EMU ||
((m_mapping_type == Type::MAPPING_GCPAD || m_mapping_type == Type::MAPPING_HOTKEYS) &&
m_devices_combo->currentData().toString() == QString::fromLatin1(OPENXR_CONTROLLER_DEVICE));
m_openxr_config_session_controller->GetButton()->setVisible(visible);
return m_mapping_type == Type::MAPPING_WIIMOTE_EMU || m_mapping_type == Type::MAPPING_GCPAD ||
m_mapping_type == Type::MAPPING_HOTKEYS;
}
void MappingWindow::SetMappingType(MappingWindow::Type type)
@@ -666,9 +656,25 @@ void MappingWindow::PopulateProfileSelection()
{
m_profiles_combo->clear();
const auto profile_uses_frame_device = [this](const std::string& path) {
if (!IsFrameControllerMapping())
return true;
Common::IniFile profile;
if (!profile.Load(path))
return false;
std::string device;
return profile.GetOrCreateSection("Profile")->Get("Device", &device, "") &&
device == OPENXR_CONTROLLER_DEVICE;
};
const std::string profiles_path = m_config->GetUserProfileDirectoryPath();
for (const auto& filename : Common::DoFileSearch(profiles_path, ".ini"))
{
if (!profile_uses_frame_device(filename))
continue;
std::string basename;
SplitPath(filename, nullptr, &basename, nullptr);
if (!basename.empty()) // Ignore files with an empty name to avoid multiple problems
@@ -679,9 +685,13 @@ void MappingWindow::PopulateProfileSelection()
for (const auto& filename : Common::DoFileSearch(m_config->GetSysProfileDirectoryPath(), ".ini"))
{
if (!profile_uses_frame_device(filename))
continue;
std::string basename;
SplitPath(filename, nullptr, &basename, nullptr);
if (!basename.empty())
if (!basename.empty() &&
(!IsFrameControllerMapping() || basename.starts_with("Steam Frame")))
{
// i18n: "Stock" refers to input profiles included with Dolphin
m_profiles_combo->addItem(tr("%1 (Stock)").arg(QString::fromStdString(basename)),
@@ -729,25 +739,21 @@ bool MappingWindow::LoadOpenXRDefaultProfile()
switch (m_mapping_type)
{
case Type::MAPPING_WIIMOTE_EMU:
profile_name = OPENXR_WIIMOTE_DEFAULT_PROFILE;
profile_name = STEAM_FRAME_WIIMOTE_DEFAULT_PROFILE;
break;
case Type::MAPPING_GCPAD:
profile_name = OPENXR_GCPAD_DEFAULT_PROFILE;
profile_name = STEAM_FRAME_GCPAD_DEFAULT_PROFILE;
break;
case Type::MAPPING_HOTKEYS:
profile_name = OPENXR_HOTKEY_DEFAULT_PROFILE;
profile_name = STEAM_FRAME_HOTKEY_DEFAULT_PROFILE;
break;
default:
return false;
}
// Dolphin's built-in defaults target a keyboard or physical pad, which is useless once the
// VR controllers are the input device, so "Default" restores the stock OpenXR profile instead.
// The Wii Remote has a dedicated OpenXR source: honour that even before a device is selected.
const bool openxr_selected =
(m_mapping_type == Type::MAPPING_WIIMOTE_EMU && m_is_openxr_wiimote) ||
m_controller->GetDefaultDevice().ToString() == OPENXR_CONTROLLER_DEVICE;
if (!openxr_selected)
// Dolphin's generic defaults target a keyboard or physical pad, so Frame mappings load their
// Steam Frame profiles instead.
if (!IsFrameControllerMapping())
return false;
Common::IniFile ini;
@@ -818,8 +824,7 @@ void MappingWindow::UpdateOpenXRProfileLabel()
if (!snapshot.runtime_active)
{
m_openxr_profile_label->setText(
tr("OpenXR: not connected\n"
"Launch a game or use \"Configure in VR\" to bind VR controller inputs."));
tr("OpenXR: not connected\nLaunch a game to bind VR controller inputs."));
return;
}
@@ -4,7 +4,6 @@
#pragma once
#include <QDialog>
#include <QPointer>
#include <QString>
namespace ControllerEmu
@@ -14,7 +13,6 @@ class EmulatedController;
class InputConfig;
class MappingButton;
class OpenXRWiimoteConfigSessionController;
class QComboBox;
class QDialogButtonBox;
@@ -59,6 +57,7 @@ public:
bool IsCreateOtherDeviceMappingsEnabled() const;
bool IsWaitForAlternateMappingsEnabled() const;
bool IsIterativeMappingEnabled() const;
bool IsFrameControllerMapping() const;
void ShowExtensionMotionTabs(bool show);
void ActivateExtensionTab();
@@ -97,7 +96,6 @@ private:
void UpdateProfileButtonState();
void PopulateProfileSelection();
void UpdateDeviceList();
void UpdateOpenXRConfigButtonVisibility();
void OnDefaultFieldsPressed();
void OnClearFieldsPressed();
@@ -119,6 +117,7 @@ private:
QWidget* m_profile_and_reset_container = nullptr;
QHBoxLayout* m_devices_layout;
QComboBox* m_devices_combo;
QToolButton* m_device_options;
QLabel* m_openxr_profile_label = nullptr;
QAction* m_other_device_mappings;
QAction* m_wait_for_alternate_mappings;
@@ -151,5 +150,4 @@ private:
const int m_port;
bool m_is_openxr_wiimote = false;
InputConfig* m_config;
QPointer<OpenXRWiimoteConfigSessionController> m_openxr_config_session_controller;
};
@@ -43,15 +43,6 @@ void WiimoteEmuMotionControlIMU::CreateMainLayout()
groups_layout->addWidget(
CreateGroupBox(Wiimote::GetWiimoteGroup(GetPort(), WiimoteEmu::WiimoteGroup::IMUGyroscope)));
}
else
{
auto* imu_layout = new QVBoxLayout();
imu_layout->addWidget(
CreateGroupBox(Wiimote::GetWiimoteGroup(GetPort(), WiimoteEmu::WiimoteGroup::IMUGyroscope)));
imu_layout->addWidget(CreateGroupBox(
Wiimote::GetWiimoteGroup(GetPort(), WiimoteEmu::WiimoteGroup::IMUAccelerometer)));
groups_layout->addLayout(imu_layout);
}
m_main_layout = new QVBoxLayout();
if (source != WiimoteSource::OpenXR)
@@ -85,7 +85,7 @@ void SDLHintsWindow::CreateMainLayout()
m_directinput_detection = new ToolTipCheckBox(tr("Enable DirectInput Detection"));
m_directinput_detection->SetDescription(
tr("Controls whether SDL should use DirectInput for detecting controllers. Enabling this "
"fixes hotplug detection issues with DualSense controllers but causes Dolphin to hang up "
"fixes hotplug detection issues with DualSense controllers but causes BaijiSteamVR to hang up "
"on shutdown when using certain 8BitDo controllers.<br><br><dolphin_emphasis>If unsure, "
"leave this checked.</dolphin_emphasis>"));
connect(m_directinput_detection, &ToolTipCheckBox::toggled, [](bool checked) {
@@ -144,7 +144,7 @@ void SDLHintsWindow::CreateMainLayout()
connect(m_tab_widget, &QTabWidget::currentChanged, this, &SDLHintsWindow::TabChanged);
auto* const warning_text =
new QLabel(tr("Dolphin must be restarted for these changes to take effect."));
new QLabel(tr("BaijiSteamVR must be restarted for these changes to take effect."));
warning_text->setWordWrap(true);
// Create main layout
@@ -3,6 +3,8 @@
#include "DolphinQt/Config/ToolTipControls/BalloonTip.h"
#include <algorithm>
#include <cstdlib>
#include <memory>
#include <QApplication>
@@ -16,7 +18,6 @@
#include <QPen>
#include <QPoint>
#include <QRect>
#include <QScreen>
#include <QSize>
#include <QString>
#include <QVBoxLayout>
@@ -39,7 +40,8 @@ QWidget* s_parent = nullptr;
} // namespace
void BalloonTip::ShowBalloon(const QString& title, const QString& message,
const QPoint& target_arrow_tip_position, QWidget* const parent,
const QPoint& target_arrow_tip_position,
const QRect& target_widget_rect_global, QWidget* const parent,
const ShowArrow show_arrow, const int border_width)
{
HideBalloon();
@@ -47,13 +49,16 @@ void BalloonTip::ShowBalloon(const QString& title, const QString& message,
return;
#if defined(__APPLE__)
(void)target_widget_rect_global;
QString the_message = message;
the_message.replace(QStringLiteral("<dolphin_emphasis>"), QStringLiteral("<b>"));
the_message.replace(QStringLiteral("</dolphin_emphasis>"), QStringLiteral("</b>"));
QToolTip::showText(target_arrow_tip_position, the_message, parent);
#else
s_the_balloon_tip = std::make_unique<BalloonTip>(PrivateTag{}, title, message, parent);
s_the_balloon_tip->UpdateBoundsAndRedraw(target_arrow_tip_position, show_arrow, border_width);
s_the_balloon_tip =
std::make_unique<BalloonTip>(PrivateTag{}, title, message, parent, border_width);
s_the_balloon_tip->UpdateBoundsAndRedraw(target_arrow_tip_position, target_widget_rect_global,
show_arrow, border_width);
#endif
}
@@ -70,12 +75,16 @@ void BalloonTip::HideBalloon()
#endif
}
BalloonTip::BalloonTip(PrivateTag, const QString& title, QString message, QWidget* const parent)
BalloonTip::BalloonTip(PrivateTag, const QString& title, QString message, QWidget* const parent,
const int border_width)
: QWidget(nullptr, Qt::ToolTip)
{
s_parent = parent;
setMouseTracking(true);
const QWidget* const owner_window = parent->window();
m_owner_rect = QRect(owner_window->mapToGlobal(QPoint(0, 0)), owner_window->size());
QColor window_color;
QColor text_color;
QColor dolphin_emphasis;
@@ -92,9 +101,19 @@ BalloonTip::BalloonTip(PrivateTag, const QString& title, QString message, QWidge
message.replace(QStringLiteral("</dolphin_emphasis>"), QStringLiteral("</b></font>"));
auto* const balloontip_layout = new QVBoxLayout;
balloontip_layout->setSizeConstraint(QLayout::SetFixedSize);
balloontip_layout->setSizeConstraint(QLayout::SetNoConstraint);
setLayout(balloontip_layout);
const float border_half_width = border_width / 2.0;
const int rounded_corner_margin = border_half_width / 4;
const int horizontal_margin = border_width + rounded_corner_margin + 12;
const int bounded_horizontal_margin =
std::min(horizontal_margin, std::max(0, (m_owner_rect.width() - 1) / 2));
const int max_width = std::max(1, m_owner_rect.width() - 2 * bounded_horizontal_margin);
const int vertical_margin = bounded_horizontal_margin;
balloontip_layout->setContentsMargins(bounded_horizontal_margin, vertical_margin,
bounded_horizontal_margin, vertical_margin);
const auto create_label = [=](const QString& text) {
QLabel* const label = new QLabel;
balloontip_layout->addWidget(label);
@@ -102,7 +121,6 @@ BalloonTip::BalloonTip(PrivateTag, const QString& title, QString message, QWidge
label->setText(text);
label->setTextFormat(Qt::RichText);
const int max_width = label->screen()->availableGeometry().width() / 3;
label->setMaximumWidth(max_width);
if (label->sizeHint().width() > max_width)
@@ -185,37 +203,71 @@ void BalloonTip::paintEvent(QPaintEvent* const event)
}
void BalloonTip::UpdateBoundsAndRedraw(const QPoint& target_arrow_tip_position,
const QRect& target_widget_rect_global,
const ShowArrow show_arrow, const int border_full_width)
{
const float border_half_width = border_full_width / 2.0;
// This should be odd so that the arrow tip is a single pixel wide.
const int arrow_full_width = 35;
const float arrow_half_width = arrow_full_width / 2.0;
// The y distance between the inner edge of the rectangle border and the inner tip of the arrow
// border, and also the distance between the outer edge of the rectangle border and the outer tip
// of the arrow border
const int arrow_height = (1 + arrow_full_width) / 2;
constexpr int preferred_arrow_full_width = 35;
// Distance between the label layout and the inner rectangle border edge
const int balloon_interior_padding = 12;
constexpr int balloon_interior_padding = 12;
// Prevent the corners of the label layout from portruding into the rounded rectangle corners at
// larger border sizes.
const int rounded_corner_margin = border_half_width / 4;
const int horizontal_margin =
const int nominal_horizontal_margin =
border_full_width + rounded_corner_margin + balloon_interior_padding;
const int vertical_margin = horizontal_margin + arrow_height;
const int horizontal_margin =
std::min(nominal_horizontal_margin, std::max(0, (m_owner_rect.width() - 1) / 2));
const int preferred_arrow_height =
show_arrow == ShowArrow::Yes ? (1 + preferred_arrow_full_width) / 2 : 0;
const int vertical_margin = horizontal_margin + preferred_arrow_height;
// Create enough space around the layout containing the title and message to draw the balloon and
// both arrow tips (at most one of which will be visible)
// Reserve space for the chevron only when one is requested.
layout()->setContentsMargins(horizontal_margin, vertical_margin, horizontal_margin,
vertical_margin);
QSize size_hint = sizeHint();
size_hint.setWidth(std::min(size_hint.width(), m_owner_rect.width()));
size_hint.setHeight(std::min(size_hint.height(), m_owner_rect.height()));
// Keep the balloon beside its target, choosing the side with more room if it must be clipped.
const int space_above = std::max(0, target_widget_rect_global.top() - m_owner_rect.top());
const int space_below =
std::max(0, m_owner_rect.bottom() - target_widget_rect_global.bottom());
const bool popup_above_widget =
size_hint.height() <= space_above ||
(size_hint.height() > space_below && space_above >= space_below);
const int available_height = popup_above_widget ? space_above : space_below;
size_hint.setHeight(std::min(size_hint.height(), std::max(1, available_height)));
// The content layout may prefer a larger size, but the visible tooltip is always bounded by its
// owning window.
setMaximumSize(m_owner_rect.size());
resize(size_hint);
// Reduce the arrow with the available height/width so even unusually small windows have a
// non-negative rounded-rectangle area.
int arrow_full_width =
show_arrow == ShowArrow::Yes ?
std::min(preferred_arrow_full_width, size_hint.width() - border_full_width) :
0;
if (arrow_full_width > 0 && arrow_full_width % 2 == 0)
--arrow_full_width;
const int max_arrow_height = std::max(0, (size_hint.height() - border_full_width - 1) / 2);
const int max_arrow_width = max_arrow_height > 0 ? 2 * max_arrow_height - 1 : 0;
arrow_full_width = std::max(0, std::min(arrow_full_width, max_arrow_width));
const float arrow_half_width = arrow_full_width / 2.0;
// The y distance between the inner edge of the rectangle border and the inner tip of the arrow
// border, and also the distance between the outer edge of the rectangle border and the outer tip
// of the arrow border.
const int arrow_height = (1 + arrow_full_width) / 2;
// These positions represent the middle of each edge of the BalloonTip's rounded rectangle
const float rect_width = size_hint.width() - border_full_width;
const float rect_height = size_hint.height() - border_full_width - 2 * arrow_height;
const float rect_width = std::max(0, size_hint.width() - border_full_width);
const float rect_height =
std::max(0, size_hint.height() - border_full_width - 2 * arrow_height);
const float rect_top = border_half_width + arrow_height;
const float rect_bottom = rect_top + rect_height;
const float rect_left = border_half_width;
@@ -240,22 +292,29 @@ void BalloonTip::UpdateBoundsAndRedraw(const QPoint& target_arrow_tip_position,
// the left edge of the arrow interior; otherwise the distance between the right edges.
const int arrow_nearest_edge_x_offset =
std::min(adjusted_arrow_x_offset, centered_arrow_x_offset);
const int arrow_tip_x_offset = arrow_nearest_edge_x_offset + arrow_half_width;
// The BalloonTip should be contained entirely within the screen that contains the target
// position.
QScreen* screen = QGuiApplication::screenAt(target_arrow_tip_position);
if (screen == nullptr)
{
// If the target position isn't on any screen (which can happen if the window is partly off the
// screen and the user hovers over the label) then use the screen containing the cursor instead.
screen = QGuiApplication::screenAt(QCursor::pos());
}
const QRect screen_rect = screen->geometry();
const int left_arrow_tip_x = static_cast<int>(arrow_nearest_edge_x_offset + arrow_half_width);
const int right_arrow_tip_x =
static_cast<int>(size_hint.width() - arrow_nearest_edge_x_offset - arrow_full_width +
arrow_half_width);
const int rightmost_valid_x =
std::max(m_owner_rect.left(), m_owner_rect.right() - size_hint.width() + 1);
const int left_arrow_window_x = std::clamp(target_arrow_tip_position.x() - left_arrow_tip_x,
m_owner_rect.left(), rightmost_valid_x);
const int right_arrow_window_x = std::clamp(target_arrow_tip_position.x() - right_arrow_tip_x,
m_owner_rect.left(), rightmost_valid_x);
const int left_arrow_error =
std::abs(left_arrow_window_x + left_arrow_tip_x - target_arrow_tip_position.x());
const int right_arrow_error =
std::abs(right_arrow_window_x + right_arrow_tip_x - target_arrow_tip_position.x());
const bool arrow_at_left = left_arrow_error <= right_arrow_error;
const int actual_balloontip_global_x = arrow_at_left ? left_arrow_window_x : right_arrow_window_x;
QPainterPath rect_path;
rect_path.addRoundedRect(rect_left, rect_top, rect_width, rect_height, corner_outer_radius,
corner_outer_radius);
if (rect_width > 0 && rect_height > 0)
{
rect_path.addRoundedRect(rect_left, rect_top, rect_width, rect_height, corner_outer_radius,
corner_outer_radius);
}
// The default pen cap style Qt::SquareCap extends drawn lines one half width before the starting
// point and one half width after the ending point such that the starting and ending points are
@@ -290,25 +349,18 @@ void BalloonTip::UpdateBoundsAndRedraw(const QPoint& target_arrow_tip_position,
mask_painter.setBrush(QBrush(Qt::color1));
mask_painter.drawPath(rect_path);
const bool arrow_at_bottom =
target_arrow_tip_position.y() - size_hint.height() + arrow_height >= 0;
const bool arrow_at_left =
target_arrow_tip_position.x() + size_hint.width() - arrow_tip_x_offset < screen_rect.width();
const float arrow_base_y =
arrow_at_bottom ? rect_bottom - border_half_width : rect_top + border_half_width;
popup_above_widget ? rect_bottom - border_half_width : rect_top + border_half_width;
const float arrow_tip_vertical_offset = arrow_at_bottom ? arrow_height : -arrow_height;
const float arrow_tip_vertical_offset = popup_above_widget ? arrow_height : -arrow_height;
const float arrow_tip_interior_y = arrow_base_y + arrow_tip_vertical_offset;
const float arrow_tip_exterior_y =
arrow_tip_interior_y + (arrow_at_bottom ? border_full_width : -border_full_width);
const float arrow_base_left_edge_x =
arrow_at_left ? arrow_nearest_edge_x_offset :
size_hint.width() - arrow_nearest_edge_x_offset - arrow_full_width;
const float arrow_base_right_edge_x = arrow_base_left_edge_x + arrow_full_width;
const float arrow_tip_x = arrow_base_left_edge_x + arrow_half_width;
if (show_arrow == ShowArrow::Yes)
if (show_arrow == ShowArrow::Yes && arrow_full_width > 0)
{
// Drawing diagonal lines in Qt is filled with edge cases and inexplicable behavior. Getting it
// to do what you want at one border size is simple enough, but doing so flexibly is an exercise
@@ -324,14 +376,14 @@ void BalloonTip::UpdateBoundsAndRedraw(const QPoint& target_arrow_tip_position,
QPainterPath arrow_border_path;
QPainterPath arrow_interior_fill_path;
const float y_end_offset = arrow_at_bottom ? border_full_width : -border_full_width;
const float y_end_offset = popup_above_widget ? border_full_width : -border_full_width;
// Draw the arrow border and interior lines from the outside inward. Each loop iteration draws
// one pair of border lines and one pair of interior lines.
for (int i = 1; i <= arrow_half_width; i++)
{
const float x_offset_from_arrow_base_edge = i - 0.5;
const float border_y_start = arrow_base_y + (arrow_at_bottom ? i : -i);
const float border_y_start = arrow_base_y + (popup_above_widget ? i : -i);
const float border_y_end = border_y_start + y_end_offset;
const float interior_y_start = arrow_base_y;
const float interior_y_end = border_y_start;
@@ -377,22 +429,15 @@ void BalloonTip::UpdateBoundsAndRedraw(const QPoint& target_arrow_tip_position,
setMask(mask_bitmap);
// Place the arrow tip at the target position whether the arrow tip is drawn or not
const int target_balloontip_global_x =
target_arrow_tip_position.x() - static_cast<int>(arrow_tip_x);
const int rightmost_valid_balloontip_global_x =
screen_rect.left() + screen_rect.width() - size_hint.width();
// If the balloon would extend off the screen, push it left or right until it's not
const int actual_balloontip_global_x =
std::max(screen_rect.left(),
std::min(rightmost_valid_balloontip_global_x, target_balloontip_global_x));
// The tip pixel should be in the middle of the control, and arrow_tip_exterior_y is at the bottom
// of that pixel. When arrow_at_bottom is true the arrow is above arrow_tip_exterior_y and so the
// tip pixel is in the right place, but when it's false the arrow is below arrow_tip_exterior_y
// so the tip pixel would be the one below that. Make this adjustment to fix that.
const int tip_pixel_adjustment = arrow_at_bottom ? 0 : 1;
// Anchor the popup edge to the source widget edge selected for this side, so its border doesn't
// cut through the widget.
const int preferred_balloontip_global_y =
popup_above_widget ? target_widget_rect_global.top() - size_hint.height() :
target_widget_rect_global.bottom() + 1;
const int lowest_valid_y =
std::max(m_owner_rect.top(), m_owner_rect.bottom() - size_hint.height() + 1);
const int actual_balloontip_global_y =
target_arrow_tip_position.y() - arrow_tip_exterior_y - tip_pixel_adjustment;
std::clamp(preferred_balloontip_global_y, m_owner_rect.top(), lowest_valid_y);
move(actual_balloontip_global_x, actual_balloontip_global_y);
@@ -5,6 +5,7 @@
#include <QColor>
#include <QPixmap>
#include <QRect>
#include <QWidget>
class QEnterEvent;
@@ -29,14 +30,15 @@ public:
No
};
static void ShowBalloon(const QString& title, const QString& message,
const QPoint& target_arrow_tip_position, QWidget* parent,
const QPoint& target_arrow_tip_position,
const QRect& target_widget_rect_global, QWidget* parent,
ShowArrow show_arrow = ShowArrow::Yes, int border_width = 1);
static void HideBalloon();
static bool IsCursorInsideWidgetBoundingBox(const QWidget& widget);
static bool IsCursorOnBalloonTip();
static bool IsWidgetBalloonTipActive(const QWidget& widget);
BalloonTip(PrivateTag, const QString& title, QString message, QWidget* parent);
BalloonTip(PrivateTag, const QString& title, QString message, QWidget* parent, int border_width);
protected:
void enterEvent(QEnterEvent* event) override;
@@ -45,9 +47,11 @@ protected:
void paintEvent(QPaintEvent* event) override;
private:
void UpdateBoundsAndRedraw(const QPoint& target_arrow_tip_position, ShowArrow show_arrow,
void UpdateBoundsAndRedraw(const QPoint& target_arrow_tip_position,
const QRect& target_widget_rect_global, ShowArrow show_arrow,
int border_width);
QColor m_border_color;
QPixmap m_pixmap;
QRect m_owner_rect;
};
@@ -60,8 +60,11 @@ private:
this->killTimer(*m_timer_id);
m_timer_id.reset();
BalloonTip::ShowBalloon(m_title, m_description,
this->parentWidget()->mapToGlobal(GetToolTipPosition()), this);
const QPoint target_position = this->parentWidget()->mapToGlobal(GetToolTipPosition());
const QRect target_widget_rect_global(this->mapToGlobal(this->rect().topLeft()),
this->rect().size());
BalloonTip::ShowBalloon(m_title, m_description, target_position, target_widget_rect_global,
this, BalloonTip::ShowArrow::No);
Derived::timerEvent(event);
}
+83 -13
View File
@@ -323,8 +323,47 @@ void VRConfigWidget::CreateWidgets()
auto* openxr_group = new QGroupBox(tr("OpenXR"));
auto* openxr_layout = new QGridLayout(openxr_group);
openxr_layout->addWidget(make_bool(tr("Enable VR"), Config::GFX_VR_ENABLE_OPENXR), 0, 0, 1, 3);
add_float(
const auto get_game_or_base = [layer, this](const auto& setting) {
if (layer->Exists(setting.GetLocation()))
return layer->Get(setting);
if (m_global_layer->Exists(setting.GetLocation()))
return m_global_layer->Get(setting);
return Config::GetBase(setting);
};
QString legacy_mode_name = tr("Use existing settings");
if (!get_game_or_base(Config::GFX_VR_ENABLE_OPENXR))
legacy_mode_name += tr(" (Vulkan flat display)");
else if (get_game_or_base(Config::GFX_VR_FLAT_SCREEN))
legacy_mode_name += tr(" (2D screen in VR)");
else if (get_game_or_base(Config::GFX_VR_STEREO_SCREEN))
legacy_mode_name += tr(" (stereo 3D screen)");
else
legacy_mode_name += tr(" (immersive VR)");
auto* presentation_mode = mark_default(new ConfigChoiceMap<OpenXRPresentationMode>(
{{legacy_mode_name, OpenXRPresentationMode::Legacy},
{tr("Flat Display (Vulkan)"), OpenXRPresentationMode::Vulkan},
{tr("Immersive VR"), OpenXRPresentationMode::Immersive},
{tr("Stereo 3D Screen"), OpenXRPresentationMode::StereoScreen}},
Config::GFX_VR_PRESENTATION_MODE, layer, m_global_layer.get()));
presentation_mode->setToolTip(
tr("Selects standard Vulkan flat output, BaijiSteamVR immersive VR, or a stereoscopic 3D "
"screen in the headset."));
connect(presentation_mode, &QComboBox::currentIndexChanged, this, [layer] {
const OpenXRPresentationMode mode = layer->Get(Config::GFX_VR_PRESENTATION_MODE);
if (mode == OpenXRPresentationMode::Legacy)
return;
layer->Set(Config::GFX_VR_ENABLE_OPENXR.GetLocation(),
mode != OpenXRPresentationMode::Vulkan);
layer->Set(Config::GFX_VR_FLAT_SCREEN.GetLocation(), false);
layer->Set(Config::GFX_VR_STEREO_SCREEN.GetLocation(),
mode == OpenXRPresentationMode::StereoScreen);
Config::OnConfigChanged();
});
openxr_layout->addWidget(new QLabel(tr("Presentation Mode:")), 0, 0);
openxr_layout->addWidget(presentation_mode, 0, 1, 1, 2);
auto* units_per_meter = add_float(
openxr_layout, 1, tr("Units per Meter:"), Config::GFX_VR_UNITS_PER_METER_MIN,
Config::GFX_VR_UNITS_PER_METER_MAX, Config::GFX_VR_UNITS_PER_METER,
Config::GFX_VR_UNITS_PER_METER_STEP,
@@ -333,18 +372,35 @@ void VRConfigWidget::CreateWidgets()
value);
},
ConfigFloatSlider::ScaleMode::Exponential);
units_per_meter->setToolTip(
tr("Default: 1.0. Sets game-world units per real meter. "
"Higher values make the world smaller and "
"increase effective stereo depth relative to game geometry; lower values make it "
"larger and reduce depth. Use Stereo Separation to adjust depth without changing "
"world scale."));
auto* stereo_separation = add_float(
openxr_layout, 2, tr("Stereo Separation (%):"),
Config::GFX_VR_STEREO_SEPARATION_MIN, Config::GFX_VR_STEREO_SEPARATION_MAX,
Config::GFX_VR_STEREO_SEPARATION, Config::GFX_VR_STEREO_SEPARATION_STEP,
[](float value) { return QString::asprintf("%.0f%%", value); });
stereo_separation->setToolTip(
tr("Scales the virtual left/right eye offset while leaving world scale and head movement "
"unchanged. 100% preserves the current OpenXR eye spacing; lower values reduce stereo "
"depth and 0% approaches mono. Lower separation may make strong near-field pop-out "
"easier to fuse and may ease eye strain, but comfort varies. Higher values increase "
"depth and may increase strain. This affects Immersive VR; Stereo 3D Screen uses the "
"Stereoscopic Depth setting instead."));
#ifndef BAIJI_STEAMVR
auto* mirror_view = mark_default(new ConfigChoiceMap<OpenXRMirrorView>(
{{tr("Both Eyes"), OpenXRMirrorView::BothEyes},
{tr("Left Eye"), OpenXRMirrorView::LeftEye},
{tr("Right Eye"), OpenXRMirrorView::RightEye},
{tr("None"), OpenXRMirrorView::None}},
Config::GFX_VR_MIRROR_VIEW, layer, m_global_layer.get()));
openxr_layout->addWidget(new QLabel(tr("Desktop Mirror View:")), 2, 0);
openxr_layout->addWidget(mirror_view, 2, 1, 1, 2);
openxr_layout->addWidget(make_bool(tr("Flat Screen (2D, no stereo)"), Config::GFX_VR_FLAT_SCREEN),
3, 0, 1, 3);
openxr_layout->addWidget(new QLabel(tr("Desktop Mirror View:")), 3, 0);
openxr_layout->addWidget(mirror_view, 3, 1, 1, 2);
#endif
auto* camera_group = new QGroupBox(tr("Camera"));
auto* camera_layout = new QGridLayout(camera_group);
camera_layout->addWidget(
@@ -383,10 +439,15 @@ void VRConfigWidget::CreateWidgets()
virtual_screen_layout->addWidget(
make_bool(tr("Auto-Exclude EFB Effects"), Config::GFX_VR_AUTO_NATIVE_EFB_EFFECTS), 2, 0, 1,
3);
add_float(virtual_screen_layout, 3, tr("Screen Distance (m):"),
Config::GFX_VR_SCREEN_DISTANCE_MIN, Config::GFX_VR_SCREEN_DISTANCE_MAX,
Config::GFX_VR_SCREEN_DISTANCE, Config::GFX_VR_SCREEN_DISTANCE_STEP,
[](float value) { return QString::asprintf("%.1f", value); });
auto* screen_distance = add_float(
virtual_screen_layout, 3, tr("Screen Distance (m):"), Config::GFX_VR_SCREEN_DISTANCE_MIN,
Config::GFX_VR_SCREEN_DISTANCE_MAX, Config::GFX_VR_SCREEN_DISTANCE,
Config::GFX_VR_SCREEN_DISTANCE_STEP,
[](float value) { return QString::asprintf("%.1f", value); });
screen_distance->setToolTip(
tr("Default: 2.0 m. Distance in meters to the virtual screen used for 2D content (menus, "
"FMV, and HUD). The screen is fixed in space like a TV; it stays in place when you turn "
"your head."));
add_float(virtual_screen_layout, 4, tr("Screen Size (m):"), Config::GFX_VR_SCREEN_SIZE_MIN,
Config::GFX_VR_SCREEN_SIZE_MAX, Config::GFX_VR_SCREEN_SIZE,
Config::GFX_VR_SCREEN_SIZE_STEP,
@@ -467,8 +528,17 @@ void VRConfigWidget::CreateWidgets()
Config::GFX_VR_FORCED_VBI_FREQUENCY, layer, m_global_layer.get()));
framerate_layout->addWidget(new QLabel(tr("Forced VBI Frequency:")), 0, 0);
framerate_layout->addWidget(forced_vbi, 0, 1);
auto* requested_refresh_rate = mark_default(new ConfigChoiceMap<int>(
{{tr("Auto"), Config::GFX_VR_REQUESTED_REFRESH_RATE_AUTO},
{tr("60 Hz"), Config::GFX_VR_REQUESTED_REFRESH_RATE_60},
{tr("72 Hz"), Config::GFX_VR_REQUESTED_REFRESH_RATE_72},
{tr("90 Hz"), Config::GFX_VR_REQUESTED_REFRESH_RATE_90},
{tr("120 Hz"), Config::GFX_VR_REQUESTED_REFRESH_RATE_120}},
Config::GFX_VR_REQUESTED_REFRESH_RATE, layer, m_global_layer.get()));
framerate_layout->addWidget(new QLabel(tr("Requested Refresh Rate:")), 1, 0);
framerate_layout->addWidget(requested_refresh_rate, 1, 1);
framerate_layout->addWidget(
make_bool(tr("Eager Frame Heartbeat"), Config::GFX_VR_EAGER_HEARTBEAT), 1, 0, 1, 2);
make_bool(tr("Eager Frame Heartbeat"), Config::GFX_VR_EAGER_HEARTBEAT), 2, 0, 1, 2);
auto* shaders_group = new QGroupBox(tr("Shaders"));
auto* shaders_layout = new QVBoxLayout(shaders_group);
@@ -555,7 +625,7 @@ void VRConfigWidget::CreateWidgets()
const QString help_message =
tr("Italics mark default game settings and bold marks user settings. "
"Right-click a control to remove its user setting.");
auto* help_label = new QLabel(tr("These VR settings override core Dolphin settings."));
auto* help_label = new QLabel(tr("These VR settings override core BaijiSteamVR settings."));
auto* help_widget = QtUtils::CreateIconWarning(this, QStyle::SP_MessageBoxQuestion, help_label);
help_widget->setToolTip(help_message);
@@ -287,6 +287,15 @@ void WiimoteControllersWidget::CreateLayout()
m_wiimote_layout->addWidget(wm_label, wm_row, 1);
m_wiimote_layout->addWidget(wm_box, wm_row, 2);
m_wiimote_layout->addWidget(wm_button, wm_row, 3);
// Baiju exposes the one controller set on the Frame; keep the other emulation slots in
// configuration/core for upstream compatibility, but remove them from this fork's UI.
if (i != 0)
{
wm_label->hide();
wm_box->hide();
wm_button->hide();
}
}
m_wiimote_layout->addWidget(m_wiimote_real_balance_board, m_wiimote_layout->rowCount(), 1, 1, -1);
+7 -7
View File
@@ -73,13 +73,13 @@ ConvertDialog::ConvertDialog(QList<std::shared_ptr<const UICommon::GameFile>> fi
auto* const info_text = new QLabel(
tr("ISO: A simple and robust format which is supported by many programs. It takes up more "
"space than any other format.\n\n"
"GCZ: A basic compressed format which is compatible with most versions of Dolphin and "
"GCZ: A basic compressed format which is compatible with most versions of BaijiSteamVR and "
"some other programs. It can't efficiently compress junk data (unless removed) or "
"encrypted Wii data.\n\n"
"WIA: An advanced compressed format which is compatible with Dolphin 5.0-12188 and later, "
"WIA: An advanced compressed format which is compatible with BaijiSteamVR 5.0-12188 and later, "
"and a few other programs. It can efficiently compress encrypted Wii data, but not junk "
"data (unless removed).\n\n"
"RVZ: An advanced compressed format which is compatible with Dolphin 5.0-12188 and later. "
"RVZ: An advanced compressed format which is compatible with BaijiSteamVR 5.0-12188 and later. "
"It can efficiently compress both junk data and encrypted Wii data."));
info_text->setWordWrap(true);
info_text->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
@@ -162,7 +162,7 @@ void ConvertDialog::OnFormatChanged()
if (!block_size_ok(DiscIO::GCZ_FALLBACK_BLOCK_SIZE))
{
ERROR_LOG_FMT(MASTER_LOG, "Failed to find a block size which does not cause problems "
"when decompressing using an old version of Dolphin");
"when decompressing using an old version of BaijiSteamVR");
}
AddToBlockSizeComboBox(DiscIO::GCZ_FALLBACK_BLOCK_SIZE);
}
@@ -311,8 +311,8 @@ void ConvertDialog::Convert()
if (std::ranges::any_of(m_files, &UICommon::GameFile::IsNKit))
{
if (!ShowAreYouSureDialog(
tr("Dolphin can't convert NKit files to non-NKit files. Converting an NKit file in "
"Dolphin will result in another NKit file.\n"
tr("BaijiSteamVR can't convert NKit files to non-NKit files. Converting an NKit file in "
"BaijiSteamVR will result in another NKit file.\n"
"\n"
"If you want to convert an NKit file to a non-NKit file, you can use the same "
"program as you originally used when converting the file to the NKit format.\n"
@@ -511,7 +511,7 @@ void ConvertDialog::Convert()
if (!success.get())
{
ModalMessageBox::critical(this, tr("Error"),
tr("Dolphin failed to complete the requested action."));
tr("BaijiSteamVR failed to complete the requested action."));
return;
}
@@ -734,7 +734,7 @@ void BranchWatchDialog::OnHelp()
"\n\n"
"Press the \"Start Branch Watch\" button to activate Branch Watch. Branch Watch persists "
"across emulation sessions, and a snapshot of your progress can be saved to and loaded "
"from the User Directory to persist after Dolphin Emulator is closed. \"Save As...\" and "
"from the User Directory to persist after BaijiSteamVR is closed. \"Save As...\" and "
"\"Load From...\" actions are also available, and auto-saving can be enabled to save a "
"snapshot at every step of a search. The \"Pause Branch Watch\" button will halt Branch "
"Watch from tracking further branch hits until it is told to resume. Press the \"Clear "
Loaded 100 of 177 files, more files were not shown because too many files have changed in this diff. Show more