Compare commits

...

200 Commits

Author SHA1 Message Date
Gliniak e9b2464254 [XAM] Fixed issue with Content not being close due to upper-lower characters difference.
- Added string_key_insensitive
2025-08-06 22:46:20 +02:00
Margen67 10f2b5ebfc Imgui stuff 2025-08-03 19:51:32 -07:00
Margen67 833f938a64 [premake] Formatting, cleanup 2025-08-03 19:51:32 -07:00
Gliniak 37e3fe9eb6 [D3D12] Default to RTV on Intel ARC GPUs 2025-08-03 22:26:39 +02:00
Gliniak ada971aefc [Emulator] Resume should resume threads that are paused, not running 2025-08-03 20:40:30 +02:00
Gliniak e7e3cfc7fb [XThread] Fixed issue with incorrect thread state caused by invalid suspend count 2025-08-03 20:40:30 +02:00
Gliniak 2969a04145 [Kernel] Added support for loading modules before main 2025-08-03 20:40:30 +02:00
Gliniak 70364e73ae [XAM] Added option to remove titles with 0 achievements unlocked 2025-08-03 19:29:02 +02:00
The-Little-Wolf 4e8e789876 [XAM/UI] - Stubbed XamShowSigninUIEx and XamShowNuiSigninUI
- Add XTT file header
- partially implemented XamShowSigninUIEx & XamShowNuiSigninUI
- add flags for XamShowCreateProfileUI, exXamShowSigninUI, and XamUserLogon
- Define sign in states
- Add undefined params
2025-08-01 08:06:10 +02:00
Margen67 43d206d2e9 [premake] More cleanup 2025-07-29 12:02:49 -07:00
Margen67 3b3c41ab2a [tools/build/premake.py] Formatting 2025-07-29 01:46:45 -07:00
Margen67 7f7e4fd381 chmod +x 2025-07-29 00:08:50 -07:00
Margen67 ff29ceabb4 [CI] Windows is stupid 2025-07-28 23:58:17 -07:00
Margen67 4a5f63650d Add .py file extension to Python 2025-07-28 23:54:52 -07:00
Margen67 03c0e70f8b [premake] Remove unneeded defines 2025-07-28 17:26:06 -07:00
Margen67 6b384dfe52 [xb] Fix xb.bat 2025-07-28 16:47:35 -07:00
Margen67 a10ca517a6 [CI] Run xenia-build directly 2025-07-28 11:29:57 -07:00
Margen67 0b81604633 [xb] Remove useless version check
The version is already checked in xenia-build.
Add an actually useful 64-bit check.
2025-07-28 11:02:01 -07:00
Gliniak fe0e18466f [XThread] Changed behaviour for threads requesting Yield with non-alertable state 2025-07-27 19:20:44 +02:00
Adrian 4702bfb94c [XBDM] Cleanup Stubs 2025-07-27 18:57:19 +02:00
Adrian a717c0cd9f [Kernel] Implemented RtlDowncaseUnicodeChar 2025-07-27 18:05:58 +02:00
Margen67 c3e4a93c0a [xb] Get latest fxc, fix clang-format version 2025-07-27 02:46:43 -07:00
Margen67 f36dbd2b33 [3PP] Switch to zlib-ng 2025-07-27 02:46:43 -07:00
Margen67 4b9509391a [3PP] Upgrade snappy to 1.2.2 2025-07-27 02:46:43 -07:00
Margen67 25d6f8269a [premake] Cleanup 2025-07-27 02:46:43 -07:00
Adrian 7fec549552 [XAM] Implemented XamTaskCloseHandle 2025-07-27 00:35:10 +02:00
Gliniak 8a1188090f [Kernel] Fixed compilation 2025-07-26 22:35:47 +02:00
The-Little-Wolf 39621ddec8 [KERNEL] - Replacing Unk
- Changes here are from Chrispy's Nukernel
2025-07-26 22:27:21 +02:00
The-Little-Wolf 31173107bc kXNotification - adding more
- Added more kXNotification ids
- Added missing Notification to XMPCreateTitlePlaylist
2025-07-26 21:58:57 +02:00
Gliniak 4182852a4b [Base] Split of xbox.h file
- Splitted into: kernel.h and xam.h
- Removed UpdateSpaData from KernelState into ContentManager
2025-07-26 21:25:32 +02:00
Adrian c4e86cfd2b [XAM] Cleanup XamGetOverlappedResult 2025-07-24 23:29:46 +02:00
Adrian f66ab091c1 [XAM] Implemented XamGetCachedTitleName 2025-07-24 20:45:00 +02:00
Adrian d9092fb232 [XAM] Cleanup XEnumerateCrossTitle 2025-07-23 23:05:35 +02:00
The-Little-Wolf c83522060e [XBOXKRNL/XCONFIG] - Properly set PC values
- Adding PC Related flags
- set correct size of XCONFIG_USER_PC_HINT
2025-07-23 21:46:49 +02:00
Adrian 01d46c20ff [XAM] Cleanup XamUserAreUsersFriends 2025-07-21 08:11:54 +02:00
Margen67 5e4a04f383 [CI] Remove Clang 19 build 2025-07-19 14:42:21 -07:00
Margen67 3eef564ff8 [format] Require EOF newline 2025-07-19 14:42:21 -07:00
Margen67 45ca1c352d [CI] Add --no_premake to build 2025-07-19 14:42:21 -07:00
Margen67 4cb783bf22 Header cleanup 2025-07-19 14:42:21 -07:00
Margen67 d01c35f506 [Docs] Better Linux build instructions 2025-07-19 14:42:21 -07:00
Margen67 d8137a23ea [CI, premake] GCC "progress"
Also move "NoBufferSecurityCheck" outside of Windows to improve performance for Linux. (linktimeoptimization leads to build errors)
2025-07-19 14:42:21 -07:00
Margen67 5e820b09c3 [tools/diff] Formatting 2025-07-19 14:42:21 -07:00
Margen67 032dc8437b [CI] Get UBUNTU_BASE from lsb_release 2025-07-19 14:42:21 -07:00
Margen67 108fa002f9 [xb] Cleanup, use maintained version of cpplint
https://github.com/google/styleguide/pull/837
2025-07-19 14:42:21 -07:00
The-Little-Wolf 6314388c51 [XAM] - Replacing Unk
- Replacing unk parameters
- Naming unk xmp calls
- Added missing xmp structs
- Added missing messenger structs
- Added missing XamProfileCreate related structs
2025-07-19 20:37:23 +02:00
Margen67 fd82727be6 [premake] Remove <VS2022 remnants 2025-07-11 23:45:56 -07:00
Margen67 235978018c Delete xeniarc 2025-07-11 21:55:33 -07:00
Margen67 3b49edc3c6 Require specific clang-format version
Also update ancient Linux building instructions.
2025-07-11 21:55:33 -07:00
Margen67 f2a2812c67 Require Visual Studio 2022
https://github.com/actions/runner-images/issues/12045
2025-07-11 21:55:33 -07:00
Margen67 12a7e4c9c2 [xb, premake] Cleanup 2025-07-11 21:55:33 -07:00
David Hummel 3ab5ba5d81 Allow premake5 --cc argument to be optional 2025-07-10 02:32:46 -07:00
Margen67 7835f92d8c [CI] Fix release creation 2025-07-08 00:47:02 -07:00
The-Little-Wolf 0f804c3690 [SMC] - add structs and enum for poweron and standby messages
- add structs for poweron and standby messages
- add enum for poweron and standby messages
- add enum for HalReturnToFirmware and log
2025-07-07 15:40:48 +02:00
Margen67 0aeac841b8 Fix building with Clang 20
date: 3.0.4
tomlplusplus: Latest master as of writing since there's no stable release with the build fixes.
2025-07-07 04:27:38 -07:00
Margen67 79509828f0 [CI] Add LLVM/Clang 20 2025-07-07 04:27:38 -07:00
Margen67 3be371a4a3 [CI] Deduplicate UBUNTU_BASE and LLVM_VERSION 2025-07-07 04:27:38 -07:00
Margen67 20106f8cd5 [xb] Fix typo 2025-07-07 00:37:44 -07:00
Margen67 f3de3ad3f6 [xb] Add clang-format-20, raise minimum version 2025-07-06 20:06:56 -07:00
Margen67 54055a2271 [xb] Remove redundant Python path 2025-07-06 19:04:27 -07:00
Adrian b6884ba10b [XAM] Added back sleep in CompleteOverlappedDeferred
Revert change from 31ce3e0c71

This fixes accessing RDR free roam in netplay.
2025-07-01 21:36:46 +02:00
Adrian f819f23854 [BUILD] Check if building failed from build script
Useful when using git rebase --exec
2025-06-24 20:19:08 +02:00
Adrian c5d6db2840 [XAM/UI] Cast gamercard ImGUI string size to int 2025-06-22 20:37:15 +02:00
Adrian f6323beb20 [XGI] Restrict XSessionCreate to offline sessions
Fixed Peggle from crashing after completing a level.
2025-06-22 20:04:09 +02:00
The-Little-Wolf 20d3ac4ca9 [XAM/USER] - Implement Multiple Functions
- Implement XamUserGetCachedUserFlags, XamIsChildAccountSignedIn, XamUserGetOnlineLanguageFromXUID and XamUserGetOnlineCountryFromXUID
- add IsParentalControlled()
2025-06-22 18:15:41 +02:00
Adrian fd1abfe6aa [Lint/CI] Use LLVM v19 for Linux & Lint 2025-06-21 00:25:27 +02:00
The-Little-Wolf f91be22742 [KERNEL/KERNEL_STATE] - Startup kXNotifyLive
- Notify game user is not connect to live
2025-06-20 23:40:35 +02:00
The-Little-Wolf f65f044ee5 [XAM/UI] - XamShowMarketplaceUI Improvements
- Replacing magic numbers
- Replacing unknown parameters
- Adding more xnotification ids
2025-06-13 22:10:06 +02:00
Binh Nguyen 1d7973aea5
Fixed git checkout to canary-experimental instead of canary_experimental (#644) 2025-06-10 08:04:21 -07:00
NicknineTheEagle 422517c673 [XAM] Only show license_mask instructions for XBLA game unlock offer ids 2025-06-06 19:25:49 +02:00
Margen67 15008ccecc [CI] Check binary size 2025-06-02 00:41:30 -07:00
Gliniak b864149575 [Misc] Cleanup in Kernel 2025-05-31 12:00:47 +02:00
Gliniak 50492a951e [Misc] Moved pe_image to base from 3pp and cut unnecessary parts 2025-05-31 10:05:00 +02:00
Gliniak 31ce3e0c71 [XAM] Added overlap to XamUserReadProfileSettings
- Removed delay on CompleteOverlappedDeferredEx
2025-05-30 23:39:17 +02:00
Gliniak 96c2fb13f7 [Kernel] NtReadFile: Add APC call only for successful executions 2025-05-30 20:08:26 +02:00
Gliniak 97be6ebf51 [Kernel] XFile: Override file position if offset is provided 2025-05-30 19:12:39 +02:00
Gliniak 6173cedde7 [XAM] Changed behaviour of XamUserReadProfileSettings for invalid settings 2025-05-30 18:56:46 +02:00
Gliniak e601b5ab87 [UI] Added modify profile UI
- Changed default icons size from 75x75 to 64x64 to match console icons size
- Added png_utils
- Removed all dialogs from xam_ui.cc into separate entities under xam/ui
- Added option to return INT32 and WSTRING type settings to host
- Added multiple enums related to user settings
- Added code to handle changing user pfp
- Fixed bug with system app being added to GPD played list
- Changed logic in: XamUserGetUserFlagsFromXUID
- Implemented: XamUserIsOnlineEnabled
- Implemented: XamUserGetMembershipTier
- Implemented: XamUserGetMembershipTierFromXUID
- Implemented: XamUserGetUserTenure
- Partially Implemented: XamUserGetSubscriptionType
2025-05-29 09:00:14 +02:00
Gliniak 270e88a7a7 [Emulator] Removed marking extracted games as booted from disc 2025-05-27 22:26:34 +02:00
Gliniak bb20633c52 [Kernel] Fixed bug in IsOriginalXboxTitle and IsAppTitle function
- Added static assertions to functions: IsXblaTitle, IsSystemTitle, IsOriginalXboxTitle
2025-05-27 09:12:13 +02:00
The-Little-Wolf 9308a35624 [XAM/VOICE] - Stub XamVoiceGetMicArrayStatus
- Stub XamVoiceGetMicArrayStatus
2025-05-25 22:02:03 +02:00
seven7000 de10b9ef91 [Kernel] Updated XAM loader to add '$flash_xam.xex' 2025-05-22 07:42:00 +02:00
Gliniak f4b854e484 [Kernel] Added option to load provided XAM for resource usage
- Added XEX1 key
- Removed annoying assertion from xeXamEnumerate
- Added returning hmodule_ptr for resource locator
2025-05-20 23:14:22 +02:00
Gliniak 97a45315e3 [XConfig] Added enum for all config settings 2025-05-20 22:41:27 +02:00
Gliniak a79c00f67a [XConfig] Changed raw category values into enum 2025-05-20 22:13:53 +02:00
Peter Wright 63c2d94a98 Implement LaunchFileExplorer the same as LaunchWebBrowser. 2025-05-20 20:37:26 +02:00
Gliniak b43cb2ed8e [XAM] Added stub for: XamDoesOmniNeedConfiguration
- XamFirstRunExperienceShouldRun
2025-05-18 23:14:47 +02:00
Gliniak d211130c6c [Kernel] Fixed incorrect behaviour of IsSystemTitle util
- Added missing symlinks
2025-05-17 22:28:22 +02:00
Radosław Gliński 5e9019309e
[Misc] Removed dead link 2025-05-17 17:52:07 +02:00
Gliniak b447699a5b [GPU] Occlusion query faking extension 2025-05-17 16:00:41 +02:00
imaginebeingatcomputers fb3c12d362 [Kernel] Toggle DmIsDebuggerPresent when debug = true 2025-05-15 21:17:59 +02:00
Gliniak fe739208b6 [VFS] Rewrote STFS to use memory mapping
- Replaced old-style buffer, buffer_length with std::span
- Added STFS and SVOD specific Entry and File classes
- Other smaller improvements
2025-05-14 21:38:02 +02:00
Gliniak e85c2392ba [Kernel] Implemented: KeSetPriorityThread 2025-05-12 21:10:35 +02:00
imaginebeingatcomputers 2c8acf7b96 [CI] use gzip in tar compression 2025-05-10 09:42:49 +02:00
Gliniak de3b49e356 [XAM] Added overlap to XamReadTile 2025-05-07 20:41:34 +02:00
Gliniak f6d9e76fca [XAM] Fixed assertion related to incorrect casting
This should fix crash in 12xxx dashboard while browsing achievements

- Fixed issue with invalid time being presented for some achievements
- Added stub for: XampWebInstrumentationSetProfileCounts
2025-05-07 20:05:29 +02:00
Gliniak dd112ed462 [XAM] Multiple Profile/Dashboard related changes.
- Replaced multiple unknown parameters with proper named ones
- Added code to support creation of profile from dashboard initial run
- Added flag to remove ODD from being enumerated in devices (probably valid but not sure)
2025-05-06 23:10:18 +02:00
Gliniak d18f80457d [XAM] Implemented: XamReadTile(Ex)
- Added missing param to XamContentAggregateCreateEnumerator
2025-05-05 23:47:11 +02:00
Gliniak c15dde52d6 [Kernel/Video] Removed unknown fields from X_VIDEO_MODE structure
- Additionally changed some messages level to more reasonable one
2025-05-05 21:30:40 +02:00
Gliniak 9434cc89c9 [XAM] Fixed specific edge-case when DLCs or Installed Data wouldn't be visible
This was caused by including flag "exclude common" for enumerations without xuid

- Added enum XContentFlag
2025-05-05 19:53:36 +02:00
Adrian 6b055f1f74 [XAM] Assert struct sizes and misc struct adjustments 2025-05-05 19:26:34 +02:00
The-Little-Wolf 8cf15a8d54 [XAM/INFO] - Implement XamSetActiveDashAppInfo and XamGetActiveDashAppInfo
- Implement XamGetActiveDashAppInfo and XamSetActiveDashAppInfo
2025-05-05 12:12:20 +02:00
Gliniak 3ba31d9f9a Revert "[D3D12] Changed default resource state based on GPU Validation"
This causes unexpected artifacts on 10 series Nvidia GPUs

This reverts commit 7566871220.
2025-05-04 08:57:42 +02:00
Gliniak bc6bce780a [XAM/XMP] Added missing nullptr check in: XMPGetStatus 2025-05-03 21:29:37 +02:00
Gliniak 2a4ca1a1b7 [VFS] Added fallback if conversion of 1252->UTF8 fails 2025-05-03 20:58:14 +02:00
Stefan Schmidt 9f8fad7551 [3PP] Update Vulkan-Headers to v1.4.313 2025-04-30 20:07:34 +02:00
Stefan Schmidt 8273e8928a [3PP] Update VulkanMemoryAllocator to v3.2.1 2025-04-30 20:07:34 +02:00
Gliniak 674870d881 [D3D12] Fixed stability issues (Graphics lost) on AMD GPUs
- This includes infamous 6000 series crashes and crashes on newer drivers for 7000 and 9000 series

Issue was caused by returning invalid (negative) address from MaxAs opcode.

Currently it is unknown if this behaviour is correct and should be checked on console, so slight graphical issues might be present
2025-04-28 23:34:17 +02:00
Adrian 900a02efff [XAM] Added property deserialization 2025-04-27 23:39:46 +02:00
Gliniak be715f76fa [Linux] Resolved issue with huge executable file under linux
- Fixed compilation issues
2025-04-27 18:42:41 +02:00
Gliniak 03571ac4c1 [XAM] Added space reporting from "content" storage drive.
Fixed warning related to uninitialized license
2025-04-27 16:34:13 +02:00
Gliniak b8296a9bc9 [XAM] Partial implementation of: XamContentResolve and Listing of ODD content packages
It's not perfect as it doesn't take internal package name or data, but it should be good enough for most titles
2025-04-26 17:49:22 +02:00
Adrian 418de9b7f2 [XAM] Increase free space on HDD device
Defiance requires at least 5 GB of free space to install.
2025-04-26 15:45:14 +02:00
Gliniak 7797adf5f2 [UI] Fixed issue with freezing/crashing (BSOD) UI caused by incorrect fence 2025-04-26 11:17:27 +02:00
The-Little-Wolf be44b9ba33 [XAM/INFO] - Implement multiple functions
- Implement XamIsSystemExperienceTitleId, XamIsSystemTitleId, XamIsXbox1TitleId
- Replaced is_title_system_type
- Changed XamIsCurrentTitleDash
- Reduced magic numbers
2025-04-25 11:06:06 +02:00
Gliniak afe74e3d72 [UI] Fixed issue with multiple ImGui windows having the same ID 2025-04-24 22:24:54 +02:00
Gliniak 8f647c548d [D3D12] Removed GBV warning related to incorrect blend setup in specific conditions 2025-04-24 19:30:57 +02:00
Adrian 2941b672d6 [Kernel] Implemented NtFreeEncryptedMemory 2025-04-23 07:56:28 +02:00
Gliniak 7566871220 [D3D12] Changed default resource state based on GPU Validation
- This prevents GBV from spamming warnings
2025-04-22 19:31:31 +02:00
Adrian 179591c8bc [UI] Include null terminator in MessageBoxDialog 2025-04-20 22:53:40 +02:00
Gliniak 8197881803 [UI] Added detailed installation state to "Install Content" option 2025-04-19 21:13:46 +02:00
Gliniak 5ba6c2b840 [VFS] Improved initial loading time during "Install Content" 2025-04-19 16:54:25 +02:00
Gliniak 56703e52e2 [UI] Redesigned "Install Content" window
- Added ID for each ImGui window
- Added filesystem::CreateFolder function
2025-04-18 21:55:58 +02:00
Xphalnos 5d5eb03127 [GPU] Adding Registers from Xenon 2025-04-17 13:18:52 +02:00
Marco Rodolfi 066391fb59 [main ui] Properly handle XDG format specifications for Linux systems.
The issue was stemming from the fact that by default Xenia is running in portable mode, as in use the same root directory as the executable for its datafiles.

This default is an issue when using this software from a POSIX platform, since a lot of the times the location where the binary resides is not writable by default.

Therefore, force portable mode to be disabled on non Windows platforms.
2025-04-17 07:41:30 +02:00
Adrian bde7d5579a [Kernel] Fixed xex2_version 2025-04-15 20:37:20 +02:00
Gliniak 31d715d100 [Premake] Removed unused/unnecessary subprojects.
- Testing currently doesn't work
- VFS Dump is unused. You can use internal function for it
- Demos are only for fun
- Trace Dump & Trace Viewer (unsure, but ok)

You can re-enable them by changing values: enableTests and enableMiscSubprojects in main premake file.

In the future there should be xb command support to overwrite them
2025-04-15 09:04:16 +02:00
Gliniak 7298536d46 [HID] Added support for Xbox 360 Skylanders Portal
- This requires Zadig for installation of WinUSB driver for portal
2025-04-14 21:44:49 +02:00
Gliniak 7667958556 [3PP] Added Libusb 2025-04-14 21:44:49 +02:00
The-Little-Wolf d2b265e251 [XAM/NUI] - Implement More Functions
- Implement XamNuiIsDeviceReady, XamNuiIdentityGetSessionId, XamNuiHudGetInitializeFlags, XamIsNuiUIActive, XamUserNuiGetUserIndexForSignin and XamNuiHudGetVersions
- Stub XamIsNuiAutomationEnabled/XamIsNatalPlaybackEnabled, XamUserNuiGetUserIndex, XamUserNuiEnableBiometric, XamNuiGetDepthCalibration, XamNuiSkeletonGetBestSkeletonIndex, XamNuiIsChatMicEnabled, XamNuiPlayerEngagementUpdate, XamNuiCameraTiltGetStatus, XamNuiCameraElevationGetAngle, XamNuiCameraGetTiltControllerType, XamNuiCameraSetFlags,  XamShowNuiGuideUI, XamNuiHudIsEnabled, XamNuiIdentityEnrollForSignIn , XamNuiIdentityAbort and XamNuiHudSetEngagedTrackingID
- According to Xam XamIsNuiAutomationEnabled, and XamIsNatalPlaybackEnabled are the same function.
- Left Notes for future reference
2025-04-14 09:17:52 +02:00
Adrian 02c95bee06 [XAM] Implemented XamShowCreateProfileUI 2025-04-13 21:52:11 +02:00
Michael Oliver 1a356f7344 [Kernel] Add option to ignore incompatible title updates with mismatched signatures 2025-04-12 22:16:41 +02:00
Xphalnos 47f327e848 [Misc] Replaced const with constexpr where possible 2025-04-08 19:32:17 +02:00
Michael Oliver c4f1bf27ef [UI] Add paste functionality to keyboard input dialog 2025-04-06 18:08:06 +02:00
The-Little-Wolf 0771938db6 [Kernel] - Implemented SystemManagementController Class
- Added handling (partial or dummy) for SMC actions:
 - QUERY_TEMP_SENSOR, QUERY_TRAY, QUERY_AV_PACK, QUERY_SMC_VERSION, QUERY_IR_ADDRESS, QUERY_TILT_SENSOR
 - SET_FAN_SPEED_CPU, SET_FAN_SPEED_GPU, SET_DVD_TRAY, SET_IR_ADDRESS, SET_POWER_LED, SET_LEDS

- Stub HalOpenCloseODDTray, XamLoaderGetMediaInfo, XamLoaderGetMediaInfoEx
- Partially Implement HalSendSMCMessage
- Implement XamLoaderGetDvdTrayState
- HalOpenCloseODDTray is used by dash and HalSendSMCMessage can be used by custom dashboards
2025-04-06 17:30:56 +02:00
The-Little-Wolf 4b24f128f6 [XBOXKRNL & XAM] - Video, Hal, And XConfig
- Properly implement HalGetCurrentAVPack, and XGetAudioFlags.
- Return proper flags for AV Component, AV Composite, and VGA from xconfig.
- Set to HD to proper value.
- Correct wrong widescreen flag.
2025-04-01 07:59:22 +02:00
Gliniak 86a25791d0 [Base] Fixed possible compilation failure 2025-04-01 00:00:03 +02:00
Gliniak 30dcc09714 [3PP] Uplifted Premake to 5.0-beta6 and cleaned up premake file 2025-04-01 00:00:03 +02:00
Gliniak a0d199cd35 [XAM/UI] Fixed crashing on Titles & Achievements menu 2025-03-31 21:32:41 +02:00
Gliniak 7a2f53bf20 [XAM] Added default value for controller vibration.
- Added notification broadcast while changing controller vibration state
2025-03-30 21:36:47 +02:00
Xphalnos 7479ccc292 [Misc] Fix Some Warnings on Clang Build with Windows + Adding constexpr 2025-03-27 17:52:18 +01:00
Xphalnos 5f918ef28d [Misc] Replaced const with constexpr where possible 2025-03-25 19:50:37 +01:00
Margen67 d20620eb5e [CI] Linux: Add bat+ps1 2025-03-23 14:22:16 -07:00
Margen67 0ee39400fe [xb] Use WINDIR env var 2025-03-23 12:20:48 -07:00
Gliniak a45a9d8704 [UI] Resolved issues caused by ImGui uplift.
- Fixed size of default font size
- Added logic to not load nullptr texture to prevent unexpected issues
- Commited out some trace viewer UI logic for now. It should be redesigned with tables in mind
2025-03-19 22:51:04 +01:00
Gliniak f61d52dc46 [3PP] Uplifted ImGui 2025-03-19 22:47:20 +01:00
Gliniak 40bd0080f1 [Kernel] Fixed TU loading on Linux 2025-03-18 22:37:34 +01:00
Gliniak b7066c7a15 [VFS] Fixed "Install Content" option on Linux 2025-03-18 22:37:34 +01:00
Adrian 1e2f903a4a [XAM] Improved XContentQueryVolumeDeviceType 2025-03-16 20:55:39 +01:00
Gliniak 6ae45effd0 [XAM] Fixed issue with profile creation introduced in previous version 2025-03-16 20:05:12 +01:00
Gliniak 8926bdcdd6 [XAM] Fixed issue with achievements saving in Forza series.
Remove this ducktape asap and remove hardcodes
2025-03-15 23:59:34 +01:00
Gliniak 9132035a51 [UI] Fixed issue with games list UI crashing on close on Vulkan 2025-03-15 23:11:36 +01:00
Gliniak ae1c1e017d [UI] Fixed issue with font not being loaded in certain conditions 2025-03-15 23:10:46 +01:00
Gliniak d801e047dc [Kernel] Adjusted threshold of delay triggering for threads from all with Normal priority to Below Normal.
This should resolve slowdowns introduced in one of the latests build
2025-03-15 18:48:28 +01:00
Gliniak 23d1f7a308 [XAM] Added overlap to XamUserWriteProfileSettings
This fixes saving in Earthworm Jim

Additionally fixed issue with not setting xuid to -1 when not provided
2025-03-13 22:54:02 +01:00
Gliniak c4867250e4 [XAM] Fixed issue with invalid settings in UE games 2025-03-12 22:53:27 +01:00
Adrian 25b3540480 [XAM] Added XEnableGuestSignin 2025-03-12 15:10:35 +01:00
Gliniak 570d30f06d [XAM/Input] Fixed issue with abnormal input in Aurora 2025-03-10 23:56:14 +01:00
Gliniak 763a3da6ea [Threading] Change behaviour when provided timeout is 0 for Normal priority or less threads 2025-03-10 23:17:37 +01:00
Gliniak 27d9cb8cfc [XAM] Added missing nullptr check.
This partially fixes Fable 2 main menu crashes.
Figure out why game tries to save invalid data.
2025-03-10 19:25:00 +01:00
Gliniak f833effd07 [XAM] Implemented XamParseGamerTileKey 2025-03-10 18:33:45 +01:00
Gliniak b9ecfd5d78 [XAM] Fixed incorrect setting order being used.
Instead of: Title->Profile->Default
It used: Title->Default
2025-03-10 18:32:39 +01:00
Gliniak 0d06cdd649 [XAM] Removed overlap from XamUserReadProfileSettings. It currently breaks games for whatever reason.
- Updated params for: XamParseGamerTileKey, XamWriteGamerTile
2025-03-09 23:50:54 +01:00
Gliniak 1544349499 [XAM] Settings: Added specific default settings list 2025-03-09 23:33:13 +01:00
Gliniak 01fc219fc2 [HID] Fixed issue with controller spamming message.
This was caused by not ignoring cases when title provides unsupported flags.
For example support for big button controller.
2025-03-08 22:52:50 +01:00
The-Little-Wolf 34b7085ed3 [XAM/USER] - Implement XamUserCreateTitlesPlayedEnumerator
Implement of XamUserCreateTitlesPlayedEnumerator
2025-03-08 21:11:53 +01:00
Gliniak 5979274998 [HID/SDL] Return controller subtype instead of forcing gamepad 2025-03-08 20:44:43 +01:00
Gliniak 5af7e1540b [Emulator] Added extended logging on initialization 2025-03-08 19:20:08 +01:00
Gliniak d2f350d0d3 [XAM] UserTracker: Added option to return user specific list of contexts and properties 2025-03-08 18:12:36 +01:00
Gliniak da89b6a0c3 [XAM] Added missing is_empty check while reading setting data 2025-03-08 17:31:30 +01:00
Gliniak 6666b803fd [XAM] Added missing nullptr check during Spa loading 2025-03-07 20:58:45 +01:00
Gliniak 523a2dc6e3 [3PP] Uplifted SDL2 to 2.32.2. Possibly next update to 3.0 2025-03-07 18:39:45 +01:00
Gliniak 1110cdd372 [Kernel] Added support for writing/reading GPD files
This breaks settings in games that are using them and savefiles in games that use settings to store progress
2025-03-07 11:59:48 +01:00
The-Little-Wolf ccf7adf015 [XAM/APP] Recording more Xam app messages
- Recording more xam app messages for future reference
- Removed mistakes from messenger_app.h
- Added missing buffer_ptr, buffer_length to unknown message id logs
2025-03-06 18:32:16 +01:00
Adrian 60318a5db6 [Module] Include XEX_SYSTEM_FLAGS in the log 2025-02-26 19:22:43 +01:00
Michael Oliver 9555e7bde4 [Patcher] Ensure hash is checked when loading title plugins
Fixes bug where plugin loader would load all defined plugins if at least one was valid
2025-02-26 15:25:26 +01:00
The-Little-Wolf ac6692fc65 [Xbox] - More Notification IDs
- Removed unknown ids
- Removed assumed total
- Added notes
- Added kXNotificationSystemXLiveTitleUpdate
- Corrected multiple ids to include their version number
- Fixed Typo
2025-02-26 08:35:10 +01:00
Gliniak c373208c97 [UI] Disable showing notifications while making screenshot 2025-02-25 21:38:45 +01:00
Gliniak 78f97f8ff3 [Memory] Added allocation of 40k at the start of xex range.
Titles can access it and take value from it.
2025-02-22 19:32:10 +01:00
Gliniak b3d345610a [Premake] Added ASAN to Checked configuration.
There is issue with ImGui dialogs desctruction that always triggers ASAN
2025-02-17 18:47:49 +01:00
Margen67 75d49df2c5 [xb] Add Python 3.14 2025-02-13 00:28:55 -08:00
Radosław Gliński d0e6f3638e
Fixed incorrect link to releases in README file 2025-02-10 16:23:06 +01:00
The-Little-Wolf fbacd3c12d [Xam/Xam_NUI] - Implement XamShowNuiHardwareRequiredUI
- Implement XamShowNuiHardwareRequiredUI
- Add notes to XamShowNuiTroubleshooterUI
2025-02-07 09:02:45 +01:00
The-Little-Wolf 180be3664e [Xboxkrnl/Xconfig] - add xboxkrnl_xconfig.h
- Add xboxkrnl_xconfig.h to hold known Xconfig flags
- Implement more xeExGetXConfigSetting cases
2025-02-07 08:29:13 +01:00
Adrian b7b707ddd2 [3PP] Uplift utfcpp 2025-02-01 23:43:49 +01:00
Margen67 4cc074df63 [CI] Fix release title 2025-01-28 04:59:33 -08:00
Margen67 54610b939f [xb] Fall back to normal clone if shallow fails 2025-01-27 20:41:06 -08:00
Margen67 787c8d0edc [xb] "Fix" submodule update 2025-01-27 19:10:17 -08:00
nikolay-kyosev 9a0ed48168 A fix for the release build crash on linux. 2025-01-27 18:21:14 +01:00
Margen67 b7b6b860a9 [CI] Move releases to separate repository 2025-01-27 01:12:22 -08:00
Margen67 dbe645e16e [CI] Linux lint 2025-01-27 01:12:22 -08:00
Margen67 6f0a736c6c [xb] Print clang-format version 2025-01-27 01:12:22 -08:00
Adrian a4412ad40d [APP] Fixed potential string corruption 2025-01-26 17:16:00 +01:00
Gliniak 403c9500bb [CI] Store Linux artifact
There is still no code to add it to release.
In my opinion release creation must be removed from windows pipeline, but I cannot make it work
2025-01-22 21:39:21 +01:00
Marco Rodolfi 00202f938d [build] Fix Linux CI
This changes the Gnumake build to CMake + Ninja builds in order to fix linker issues in the CI.
2025-01-20 19:08:40 +01:00
Gliniak 08537f0a80 [3PP] Uplifted FFMPEG 2025-01-20 18:38:50 +01:00
Marco Rodolfi de1ad7aaf5 [build] Add missing linker libraries to xenia-ui 2025-01-20 18:03:23 +01:00
Marco Rodolfi d90c320dda [filesystem] Moved generic methods to platform independent code 2025-01-20 18:03:23 +01:00
Marco Rodolfi 753698ea20 [linux_platform] Implement a bunch of missing functions necessaries to make Xenia build correctly under Linux
With this part fixed and a function readapted from the original codebase to fix the different signature, we should have a compiling Linux build now.
2025-01-20 18:03:23 +01:00
The-Little-Wolf 3f196f4b62 [CPU/CPU_FLAGS] - Display known PVR values to user in config
- Add known PVR values to config.toml
2025-01-19 23:02:59 +01:00
Marco Rodolfi 00c94f28a1 [memory] Rebase of xenia#2230 on latest canary.
See xenia-project#2230 for an explanation of the changes. I've added additional cleanups as requested and clang-tidy additional suggestions.
2025-01-19 22:40:01 +01:00
514 changed files with 20233 additions and 16321 deletions

View File

@ -3,6 +3,9 @@ BasedOnStyle: Google
DerivePointerAlignment: false DerivePointerAlignment: false
PointerAlignment: Left PointerAlignment: Left
SortIncludes: true SortIncludes: true
KeepEmptyLines:
AtStartOfFile: false
InsertNewlineAtEOF: true
# Regroup causes unnecessary noise due to clang-format bug. # Regroup causes unnecessary noise due to clang-format bug.
IncludeBlocks: Preserve IncludeBlocks: Preserve

64
.github/workflows/Create_release.yml vendored Normal file
View File

@ -0,0 +1,64 @@
name: Create release
on:
workflow_call:
inputs:
os:
required: true
type: string
secrets:
RELEASE_TOKEN:
required: true
jobs:
release:
name: Release
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@main
- name: Release
env:
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
GH_REPO: ${{ github.repository_owner }}/xenia-canary-releases
notes: ${{ github.event.head_commit.message }}
run: |
rm -rf **/*.pdb
case ${{ inputs.os }} in
windows)
assets=xenia_canary_windows.zip
7z a $assets './xenia_canary_windows/*'
;;
linux)
for dir in xenia_canary_${{ inputs.os }}*; do
cd $dir
chmod +x xenia_canary
asset=${dir}.tar.gz
assets+=($asset)
tar -czvpf ../${asset} *
cd -
done
;;
esac
for asset in ${assets[@]}; do
if [ ! -f $asset ]; then
echo "::error::$asset doesn't exist!"
exit 1
fi
if [ $(stat -c%s $asset) -lt 100000 ]; then
echo "::error::$asset is too small!"
exit 1
fi
done
create_or_edit_release() {
local tag=$1
local title=$2
if gh release view $tag; then
gh release edit $tag -t $title -n "$notes"
gh release upload $tag ${assets[@]} --clobber
else
gh release create $tag ${assets[@]} --target 925ed98d5dce604b651027c36fb522dc1ff0fa55 -t $title -n "$notes"
fi
}
tag=${GITHUB_SHA::7}
create_or_edit_release $tag ${tag}_$GITHUB_REF_NAME
create_or_edit_release $GITHUB_REF_NAME $tag

View File

@ -7,13 +7,14 @@ on:
- '.drone.star' - '.drone.star'
- '.gitattributes' - '.gitattributes'
- '.gitignore' - '.gitignore'
- '.gdbinit'
- '.github/*' - '.github/*'
- '.github/workflows/Windows_build.yml' - '.github/workflows/Windows_build.yml'
- '.github/*_TEMPLATE/**' - '.github/*_TEMPLATE/**'
- '*.bat'
- '*.md' - '*.md'
- '*.yml' - '*.ps1'
- '*.txt' - '*.txt'
- '*.yml'
- 'docs/**' - 'docs/**'
- 'src/**/*_windows.*' - 'src/**/*_windows.*'
- 'src/**/*_android.*' - 'src/**/*_android.*'
@ -25,13 +26,14 @@ on:
- '.drone.star' - '.drone.star'
- '.gitattributes' - '.gitattributes'
- '.gitignore' - '.gitignore'
- '.gdbinit'
- '.github/*' - '.github/*'
- '.github/workflows/Windows_build.yml' - '.github/workflows/Windows_build.yml'
- '.github/*_TEMPLATE/**' - '.github/*_TEMPLATE/**'
- '*.bat'
- '*.md' - '*.md'
- '*.yml' - '*.ps1'
- '*.txt' - '*.txt'
- '*.yml'
- 'docs/**' - 'docs/**'
- 'src/**/*_windows.*' - 'src/**/*_windows.*'
- 'src/**/*_android.*' - 'src/**/*_android.*'
@ -42,36 +44,117 @@ on:
jobs: jobs:
lint: lint:
name: Lint name: Lint
runs-on: windows-latest runs-on: ubuntu-24.04
outputs:
#LLVM_VERSION: ${{ steps.setup.outputs.LLVM_VERSION }}
UBUNTU_BASE: ${{ steps.setup.outputs.UBUNTU_BASE }}
steps: steps:
- uses: actions/checkout@main - uses: actions/checkout@main
- name: Check Clang-Format Version - name: Setup
run: clang-format --version id: setup
env:
LLVM_VERSION: 19 # Same as Windows
run: |
UBUNTU_BASE=$(lsb_release -cs)
#echo "LLVM_VERSION=$LLVM_VERSION" >> "$GITHUB_OUTPUT"
echo "UBUNTU_BASE=$UBUNTU_BASE" >> "$GITHUB_OUTPUT"
wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc
sudo apt-add-repository "deb http://apt.llvm.org/${UBUNTU_BASE}/ llvm-toolchain-${UBUNTU_BASE}-$LLVM_VERSION main"
sudo apt-get -y update
sudo apt-get -y install clang-format-$LLVM_VERSION
- name: Lint - name: Lint
run: ./xb lint --all run: ./xenia-build.py lint --all
build-linux: build-clang:
name: Build (Linux) # runner.os can't be used here name: Build (Clang ${{ matrix.LLVM_VERSION }})
needs: lint needs: lint
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
LLVM_VERSION: [20] # '${{ needs.lint.outputs.LLVM_VERSION }}'
steps: steps:
- uses: actions/checkout@main - uses: actions/checkout@main
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Set environment variables
run: |
LLVM_VERSION=19
echo "LLVM_VERSION=$LLVM_VERSION" >> $GITHUB_ENV
echo "UBUNTU_BASE=jammy" >> $GITHUB_ENV
echo "CC=clang-${LLVM_VERSION}" >> $GITHUB_ENV
echo "CXX=clang++-${LLVM_VERSION}" >> $GITHUB_ENV
echo "AR=llvm-ar-${LLVM_VERSION}" >> $GITHUB_ENV
- name: Setup - name: Setup
env:
UBUNTU_BASE: ${{ needs.lint.outputs.UBUNTU_BASE }}
run: | run: |
wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc
sudo apt-add-repository "deb http://apt.llvm.org/${UBUNTU_BASE}/ llvm-toolchain-${UBUNTU_BASE}-$LLVM_VERSION main" sudo apt-add-repository "deb http://apt.llvm.org/${UBUNTU_BASE}/ llvm-toolchain-${UBUNTU_BASE}-${{ matrix.LLVM_VERSION }} main"
sudo apt-get -y update sudo apt-get -y update
sudo apt-get -y install mesa-vulkan-drivers valgrind libc++-dev libc++abi-dev libgtk-3-dev libsdl2-dev libvulkan-dev libx11-dev libx11-xcb-dev clang-$LLVM_VERSION clang-format-$LLVM_VERSION llvm-$LLVM_VERSION sudo apt-get -y install mesa-vulkan-drivers valgrind libc++-dev libc++abi-dev libgtk-3-dev libsdl2-dev libvulkan-dev libx11-xcb-dev clang-${{ matrix.LLVM_VERSION }} ninja-build
./xb setup ./xenia-build.py setup
- name: Build - name: Build
run: ./xb build --config=Release env:
CC: clang-${{ matrix.LLVM_VERSION }}
CXX: clang++-${{ matrix.LLVM_VERSION }}
run: ./xenia-build.py build --config=Release
- name: Prepare artifacts
id: prepare_artifacts
run: |
if [ $(stat -c %s build/bin/Linux/Release/xenia_canary) -le 100000 ]; then
echo "::error::Binary is too small."
fi
mkdir -p artifacts
cp -r build/bin/Linux/Release/xenia_canary LICENSE artifacts
- name: Upload xenia canary artifacts
if: steps.prepare_artifacts.outcome == 'success'
uses: actions/upload-artifact@main
with:
name: xenia_canary_linux
path: artifacts
if-no-files-found: error
# build-gcc:
# name: Build (GCC ${{ matrix.GCC_VERSION }})
# needs: lint
# runs-on: ubuntu-24.04
# strategy:
# fail-fast: false
# matrix:
# GCC_VERSION: [14]
# steps:
# - uses: actions/checkout@main
# with:
# fetch-depth: 0
# - name: Setup
# run: |
# sudo apt-get -y update
# sudo apt-get -y install mesa-vulkan-drivers valgrind libc++-dev libc++abi-dev libgtk-3-dev libsdl2-dev libvulkan-dev libx11-xcb-dev g++-${{ matrix.GCC_VERSION }}
# ./xenia-build.py setup
# - name: Build
# env:
# CC: gcc-${{ matrix.GCC_VERSION }}
# CXX: g++-${{ matrix.GCC_VERSION }}
# # AR: ar
# run: ./xenia-build.py build --config=Release
# - name: Prepare artifacts
# id: prepare_artifacts
# run: |
# if [ $(stat -c %s build/bin/Linux/Release/xenia_canary) -le 100000 ]; then
# echo "::error::Binary is too small."
# fi
# mkdir -p artifacts
# cp -r build/bin/Linux/Release/xenia_canary LICENSE artifacts
# - name: Upload xenia canary artifacts
# if: steps.prepare_artifacts.outcome == 'success'
# uses: actions/upload-artifact@main
# with:
# name: xenia_canary_linux_gcc
# path: artifacts
# if-no-files-found: error
create-release:
name: Create release
needs: [lint, build-clang] #build-gcc
if: |
github.repository == 'xenia-canary/xenia-canary' &&
github.event.action != 'pull_request' &&
github.ref == 'refs/heads/canary_experimental'
uses: ./.github/workflows/Create_release.yml
with:
os: linux
secrets:
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}

View File

@ -51,21 +51,17 @@ jobs:
lint: lint:
name: Lint name: Lint
runs-on: windows-latest runs-on: windows-latest
env:
POWERSHELL_TELEMETRY_OPTOUT: 1
steps: steps:
- uses: actions/checkout@main - uses: actions/checkout@main
- name: Check Clang-Format Version
run: clang-format --version
- name: Lint - name: Lint
run: .\xb lint --all run: python xenia-build.py lint --all
build-windows: build:
name: Build (Windows, VS${{ matrix.vsver }}) # runner.os can't be used here name: Build
needs: lint needs: lint
strategy: runs-on: windows-2025
fail-fast: false
matrix:
vsver: [2022]
runs-on: windows-${{ matrix.vsver }}
env: env:
POWERSHELL_TELEMETRY_OPTOUT: 1 POWERSHELL_TELEMETRY_OPTOUT: 1
steps: steps:
@ -73,45 +69,37 @@ jobs:
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Setup - name: Setup
run: .\xb setup run: python xenia-build.py setup
- name: Build - name: Build
run: .\xb build --config=Release --target=src\xenia-app run: python xenia-build.py build --no_premake --config=Release --target=src\xenia-app
- name: Prepare artifacts - name: Prepare artifacts
id: prepare_artifacts id: prepare_artifacts
run: | run: |
foreach ($file in 'build\bin\Windows\Release\xenia_canary.exe','build\bin\Windows\Release\xenia_canary.pdb') {
if ((get-item $file).Length -le 100000) {
echo "::error::$file is too small."
}
}
robocopy . build\bin\Windows\Release LICENSE /r:0 /w:0 robocopy . build\bin\Windows\Release LICENSE /r:0 /w:0
robocopy build\bin\Windows\Release artifacts\xenia_canary xenia_canary.exe xenia_canary.pdb LICENSE /r:0 /w:0 robocopy build\bin\Windows\Release artifacts\xenia_canary xenia_canary.exe xenia_canary.pdb LICENSE /r:0 /w:0
If ($LastExitCode -le 7) { echo "LastExitCode = $LastExitCode";$LastExitCode = 0 } If ($LastExitCode -le 7) { echo "LastExitCode = $LastExitCode";$LastExitCode = 0 }
- name: Upload xenia canary artifacts - name: Upload xenia canary artifacts
if: steps.prepare_artifacts.outcome == 'success' if: steps.prepare_artifacts.outcome == 'success'
id: upload_artifacts
uses: actions/upload-artifact@main uses: actions/upload-artifact@main
with: with:
name: xenia_canary_vs${{ matrix.vsver }} name: xenia_canary_windows
path: artifacts\xenia_canary path: artifacts\xenia_canary
if-no-files-found: error if-no-files-found: error
- name: Create release
if: | create-release:
github.repository == 'xenia-canary/xenia-canary' && name: Create release
github.event.action != 'pull_request' && needs: [lint, build]
github.ref == 'refs/heads/canary_experimental' && if: |
steps.upload_artifacts.outcome == 'success' github.repository == 'xenia-canary/xenia-canary' &&
env: github.event.action != 'pull_request' &&
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} github.ref == 'refs/heads/canary_experimental'
run: | uses: ./.github/workflows/Create_release.yml
$asset="xenia_canary.zip" with:
rm -recurse -force artifacts\xenia_canary\*.pdb # Ideally this would use xr, but I can't get it to work os: windows
7z a $asset .\artifacts\xenia_canary\* secrets:
If ($(Get-Item $asset).length -le 100000) { RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
Throw "Error: Archive $asset too small!"
}
$tag=$env:GITHUB_SHA.SubString(0,7)
$branch=$($env:GITHUB_REF -replace 'refs/heads/')
$title="${tag}_$branch"
gh release create $tag $asset --target $env:GITHUB_SHA -t $title
# Remove canary_ to prevent conflicts from tag
$tag=$($branch -replace 'canary_')
gh release delete $tag -y
git push --delete origin $tag
git tag -d $tag
gh release create $tag $asset --target $env:GITHUB_SHA -t $branch

18
.gitmodules vendored
View File

@ -15,7 +15,8 @@
url = https://github.com/premake/premake-core.git url = https://github.com/premake/premake-core.git
[submodule "third_party/snappy"] [submodule "third_party/snappy"]
path = third_party/snappy path = third_party/snappy
url = https://github.com/xenia-project/snappy.git url = https://github.com/google/snappy.git
ignore = dirty
[submodule "third_party/premake-export-compile-commands"] [submodule "third_party/premake-export-compile-commands"]
path = third_party/premake-export-compile-commands path = third_party/premake-export-compile-commands
url = https://github.com/xenia-project/premake-export-compile-commands.git url = https://github.com/xenia-project/premake-export-compile-commands.git
@ -42,7 +43,7 @@
url = https://github.com/libsdl-org/SDL.git url = https://github.com/libsdl-org/SDL.git
[submodule "third_party/utfcpp"] [submodule "third_party/utfcpp"]
path = third_party/utfcpp path = third_party/utfcpp
url = https://github.com/xenia-project/utfcpp.git url = https://github.com/nemtrif/utfcpp.git
[submodule "third_party/fmt"] [submodule "third_party/fmt"]
path = third_party/fmt path = third_party/fmt
url = https://github.com/fmtlib/fmt.git url = https://github.com/fmtlib/fmt.git
@ -97,9 +98,16 @@
[submodule "third_party/rapidcsv"] [submodule "third_party/rapidcsv"]
path = third_party/rapidcsv path = third_party/rapidcsv
url = https://github.com/d99kris/rapidcsv.git url = https://github.com/d99kris/rapidcsv.git
[submodule "third_party/zlib"] [submodule "third_party/zlib-ng"]
path = third_party/zlib path = third_party/zlib-ng
url = https://github.com/madler/zlib.git url = https://github.com/zlib-ng/zlib-ng.git
ignore = dirty
[submodule "third_party/pugixml"] [submodule "third_party/pugixml"]
path = third_party/pugixml path = third_party/pugixml
url = https://github.com/zeux/pugixml.git url = https://github.com/zeux/pugixml.git
[submodule "third_party/libusb"]
path = third_party/libusb
url = https://github.com/libusb/libusb.git
[submodule "third_party/cpplint"]
path = third_party/cpplint
url = https://github.com/cpplint/cpplint.git

View File

@ -20,7 +20,7 @@ Discussing illegal activities will get you banned.
Buildbot | Status | Releases Buildbot | Status | Releases
-------- | ------ | -------- -------- | ------ | --------
Windows | [![CI](https://github.com/xenia-canary/xenia-canary/actions/workflows/Windows_build.yml/badge.svg?branch=canary_experimental)](https://github.com/xenia-canary/xenia-canary/actions/workflows/Windows_build.yml) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/cd506034fd8148309a45034925648499)](https://app.codacy.com/gh/xenia-canary/xenia-canary/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade) | [Latest](https://github.com/xenia-canary/xenia-canary/releases/latest) ◦ [All](https://github.com/xenia-canary/xenia-canary/releases) Windows | [![CI](https://github.com/xenia-canary/xenia-canary/actions/workflows/Windows_build.yml/badge.svg?branch=canary_experimental)](https://github.com/xenia-canary/xenia-canary/actions/workflows/Windows_build.yml) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/cd506034fd8148309a45034925648499)](https://app.codacy.com/gh/xenia-canary/xenia-canary/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade) | [Latest](https://github.com/xenia-canary/xenia-canary-releases/releases/latest) ◦ [All](https://github.com/xenia-canary/xenia-canary-releases/releases) ◦ [Old](https://github.com/xenia-canary/xenia-canary/releases)
Linux | [![CI](https://github.com/xenia-canary/xenia-canary/actions/workflows/Linux_build.yml/badge.svg?branch=canary_experimental)](https://github.com/xenia-canary/xenia-canary/actions/workflows/Linux_build.yml) Linux | [![CI](https://github.com/xenia-canary/xenia-canary/actions/workflows/Linux_build.yml/badge.svg?branch=canary_experimental)](https://github.com/xenia-canary/xenia-canary/actions/workflows/Linux_build.yml)
Netplay Build | | [Latest](https://github.com/AdrianCassar/xenia-canary/releases/latest) Netplay Build | | [Latest](https://github.com/AdrianCassar/xenia-canary/releases/latest)

View File

@ -9,10 +9,11 @@ drivers.
### Windows ### Windows
* Windows 10 or later * Windows 10 or later
* [Visual Studio 2022, Visual Studio 2019](https://www.visualstudio.com/downloads/) * [Visual Studio 2022](https://www.visualstudio.com/downloads/)
* [Python 3.9+](https://www.python.org/downloads/) * CMake 3.10+ (or C++ CMake tools for Windows)
* Windows 11 SDK version 10.0.22000.0 (for Visual Studio 2022, this or any newer version)
* [Python 3.9+ 64-bit](https://www.python.org/downloads/)
* Ensure Python is in PATH. * Ensure Python is in PATH.
* Windows 11 SDK version 10.0.22000.0 (for Visual Studio 2019, this or any newer version)
``` ```
git clone https://github.com/xenia-canary/xenia-canary.git git clone https://github.com/xenia-canary/xenia-canary.git
@ -88,18 +89,24 @@ get helpful spacers/movs in the disassembly.
Linux support is extremely experimental and presently incomplete. Linux support is extremely experimental and presently incomplete.
The build script uses LLVM/Clang 9. GCC while it should work in theory, is not easily The build script uses Clang 19. GCC while it should work in theory, is not easily
interchangeable right now. interchangeable right now.
* Normal building via `xb build` uses Make. * Normal building via `xb build` uses CMake+Ninja.
* [CodeLite](https://codelite.org) is supported. `xb devenv` will generate a workspace and attempt to open it. Your distribution's version may be out of date so check their website. * Environment variables:
* Experimental CMake generation is available to facilitate use of other IDEs such as [CLion](https://www.jetbrains.com/clion/). If `clion` is available inside `$PATH`, `xb devenv` will start it. Otherwise `build/CMakeLists.txt` needs to be generated by invoking `xb premake --devenv=cmake` manually. Name | Default Value
----- | -------------
`CC` | `clang`
`CXX` | `clang++`
Clang-9 or newer should be available from system repositories on all up to date distributions. <!--* [CodeLite](https://codelite.org) is supported. `xb devenv` will generate a workspace and attempt to open it. Your distribution's version may be out of date so check their website.
* Experimental CMake generation is available to facilitate use of other IDEs such as [CLion](https://www.jetbrains.com/clion/). If `clion` is available inside `$PATH`, `xb devenv` will start it. Otherwise `build/CMakeLists.txt` needs to be generated by invoking `xb premake --devenv=cmake` manually.-->
Clang-19 or newer should be available from system repositories on all up to date distributions.
You will also need some development libraries. To get them on an Ubuntu system: You will also need some development libraries. To get them on an Ubuntu system:
```bash ```sh
sudo apt-get install libgtk-3-dev libpthread-stubs0-dev liblz4-dev libx11-dev libx11-xcb-dev libvulkan-dev libsdl2-dev libiberty-dev libunwind-dev libc++-dev libc++abi-dev sudo apt-get install build-essential mesa-vulkan-drivers valgrind libc++-dev libc++abi-dev libgtk-3-dev liblz4-dev libsdl2-dev libvulkan-dev libx11-xcb-dev clang-19 llvm-19 ninja-build
``` ```
In addition, you will need up to date Vulkan libraries and drivers for your hardware, which most distributions have in their standard repositories nowadays. In addition, you will need up to date Vulkan libraries and drivers for your hardware, which most distributions have in their standard repositories nowadays.

View File

@ -7,6 +7,11 @@ location(build_root)
targetdir(build_bin) targetdir(build_bin)
objdir(build_obj) objdir(build_obj)
-- Define variables for enabling specific submodules
-- Todo: Add changing from xb command
enableTests = false
enableMiscSubprojects = false
-- Define an ARCH variable -- Define an ARCH variable
-- Only use this to enable architecture-specific functionality. -- Only use this to enable architecture-specific functionality.
if os.istarget("linux") then if os.istarget("linux") then
@ -22,14 +27,18 @@ includedirs({
}) })
defines({ defines({
"_UNICODE", "IMGUI_DISABLE_OBSOLETE_FUNCTIONS",
"UNICODE", "IMGUI_DISABLE_DEFAULT_FONT",
--"IMGUI_USE_WCHAR32",
"IMGUI_USE_STB_SPRINTF",
--"IMGUI_ENABLE_FREETYPE",
"USE_CPP17", -- Tabulate
}) })
cdialect("C17")
cppdialect("C++20") cppdialect("C++20")
exceptionhandling("On")
rtti("On")
symbols("On") symbols("On")
fatalwarnings("All")
-- TODO(DrChat): Find a way to disable this on other architectures. -- TODO(DrChat): Find a way to disable this on other architectures.
if ARCH ~= "ppc64" then if ARCH ~= "ppc64" then
@ -38,11 +47,6 @@ if ARCH ~= "ppc64" then
filter({}) filter({})
end end
characterset("Unicode")
flags({
"FatalWarnings", -- Treat warnings as errors.
})
filter("kind:StaticLib") filter("kind:StaticLib")
defines({ defines({
"_LIB", "_LIB",
@ -50,23 +54,27 @@ filter("kind:StaticLib")
filter("configurations:Checked") filter("configurations:Checked")
runtime("Debug") runtime("Debug")
sanitize("Address")
flags("NoIncrementalLink")
editandcontinue("Off")
staticruntime("Off")
optimize("Off") optimize("Off")
defines({ defines({
"DEBUG", "DEBUG",
}) })
filter({"configurations:Checked", "platforms:Windows"})
filter({"configurations:Checked", "platforms:Windows"}) -- "toolset:msc"
buildoptions({ buildoptions({
"/RTCsu", -- Full Run-Time Checks. "/RTCsu", -- Full Run-Time Checks.
}) })
filter({"configurations:Checked", "platforms:Linux"})
filter({"configurations:Checked or Debug", "platforms:Linux"})
defines({ defines({
"_GLIBCXX_DEBUG", -- libstdc++ debug mode "_GLIBCXX_DEBUG", -- libstdc++ debug mode
}) })
filter({"configurations:Release", "platforms:Windows"})
buildoptions({ filter({"configurations:Checked or Debug", "platforms:Windows"}) -- "toolset:msc"
"/Gw", symbols("Full")
"/Ob3",
})
filter("configurations:Debug") filter("configurations:Debug")
runtime("Release") runtime("Release")
@ -75,10 +83,6 @@ filter("configurations:Debug")
"DEBUG", "DEBUG",
"_NO_DEBUG_HEAP=1", "_NO_DEBUG_HEAP=1",
}) })
filter({"configurations:Debug", "platforms:Linux"})
defines({
"_GLIBCXX_DEBUG", -- make dbg symbols work on some distros
})
filter("configurations:Release") filter("configurations:Release")
runtime("Release") runtime("Release")
@ -87,23 +91,36 @@ filter("configurations:Release")
"_NO_DEBUG_HEAP=1", "_NO_DEBUG_HEAP=1",
}) })
optimize("Speed") optimize("Speed")
inlining("Auto")
flags({ flags({
"LinkTimeOptimization", "NoBufferSecurityCheck"
"NoBufferSecurityCheck",
}) })
inlining("Auto")
editandcontinue("Off")
-- Not using floatingpoint("Fast") - NaN checks are used in some places -- Not using floatingpoint("Fast") - NaN checks are used in some places
-- (though rarely), overall preferable to avoid any functional differences -- (though rarely), overall preferable to avoid any functional differences
-- between debug and release builds, and to have calculations involved in GPU -- between debug and release builds, and to have calculations involved in GPU
-- (especially anything that may affect vertex position invariance) and CPU -- (especially anything that may affect vertex position invariance) and CPU
-- (such as constant propagation) emulation as predictable as possible, -- (such as constant propagation) emulation as predictable as possible,
-- including handling of specials since games make assumptions about them. -- including handling of specials since games make assumptions about them.
filter({"configurations:Release", "platforms:not Windows"})
symbols("Off")
filter({"configurations:Release", "platforms:Windows"}) -- "toolset:msc"
linktimeoptimization("On")
buildoptions({
"/Gw",
"/Ob3",
-- "/Qpar", -- TODO: Test this.
})
filter("platforms:Linux") filter("platforms:Linux")
system("linux") system("linux")
toolset("clang") toolset("clang")
buildoptions({ vectorextensions("AVX2")
-- "-mlzcnt", -- (don't) Assume lzcnt is supported. --buildoptions({
}) -- "-mlzcnt", -- (don't) Assume lzcnt is supported.
--})
pkg_config.all("gtk+-x11-3.0") pkg_config.all("gtk+-x11-3.0")
links({ links({
"stdc++fs", "stdc++fs",
@ -113,21 +130,26 @@ filter("platforms:Linux")
"rt", "rt",
}) })
filter({"platforms:Linux"})
vectorextensions("AVX2")
filter({"platforms:Linux", "kind:*App"}) filter({"platforms:Linux", "kind:*App"})
linkgroups("On") linkgroups("On")
filter({"platforms:Linux", "language:C++", "toolset:gcc"}) filter({"language:C++", "toolset:clang or gcc"}) -- "platforms:Linux"
disablewarnings({ disablewarnings({
"unused-result",
"deprecated-volatile",
"switch", "switch",
"deprecated-enum-enum-conversion", "attributes",
}) })
filter({"platforms:Linux", "toolset:gcc"}) filter({"language:C++", "toolset:gcc"}) -- "platforms:Linux"
disablewarnings({
"unused-result",
"volatile",
"template-id-cdtor",
"return-type",
"deprecated",
})
filter("toolset:gcc") -- "platforms:Linux"
removefatalwarnings("All") -- HACK
if ARCH == "ppc64" then if ARCH == "ppc64" then
buildoptions({ buildoptions({
"-m32", "-m32",
@ -137,23 +159,35 @@ filter({"platforms:Linux", "toolset:gcc"})
"-m32", "-m32",
"-mpowerpc64" "-mpowerpc64"
}) })
else
buildoptions({
"-fpermissive", -- HACK
})
linkoptions({
"-fpermissive", -- HACK
})
end end
filter({"platforms:Linux", "language:C++", "toolset:clang"}) filter({"language:C++", "toolset:clang"}) -- "platforms:Linux"
disablewarnings({ disablewarnings({
"deprecated-register", "deprecated-register",
"deprecated-volatile", "deprecated-volatile",
"switch",
"deprecated-enum-enum-conversion", "deprecated-enum-enum-conversion",
"attributes",
}) })
removeflags({ CLANG_BIN = os.getenv("CC") or _OPTIONS["cc"] or "clang"
"FatalWarnings" if os.istarget("linux") and string.contains(CLANG_BIN, "clang") then
}) if tonumber(string.match(os.outputof(CLANG_BIN.." --version"), "version (%d%d)")) >= 20 then
filter({"platforms:Linux", "language:C++", "toolset:clang", "files:*.cc or *.cpp"}) filter({"language:C++", "toolset:clang"}) -- "platforms:Linux"
buildoptions({ disablewarnings({
"-stdlib=libstdc++", "deprecated-literal-operator", -- Needed only for tabulate
"-std=c++20", -- clang doesn't respect cppdialect(?) "nontrivial-memcall",
})
end
end
filter({"language:C", "toolset:clang or gcc"}) -- "platforms:Linux"
disablewarnings({
"implicit-function-declaration",
}) })
filter("platforms:Android-*") filter("platforms:Android-*")
@ -178,20 +212,12 @@ filter("platforms:Windows")
toolset("msc") toolset("msc")
buildoptions({ buildoptions({
"/utf-8", -- 'build correctly on systems with non-Latin codepages'. "/utf-8", -- 'build correctly on systems with non-Latin codepages'.
-- Mark warnings as severe
"/w14839", -- non-standard use of class 'type' as an argument to a variadic function
"/w14840", -- non-portable use of class 'type' as an argument to a variadic function
-- Disable warnings -- Disable warnings
"/wd4100", -- Unreferenced parameters are ok. "/wd4201", -- Nameless struct/unions are ok.
"/wd4201", -- Nameless struct/unions are ok.
"/wd4512", -- 'assignment operator was implicitly defined as deleted'.
"/wd4127", -- 'conditional expression is constant'.
"/wd4324", -- 'structure was padded due to alignment specifier'.
"/wd4189", -- 'local variable is initialized but not referenced'.
}) })
flags({ flags({
"MultiProcessorCompile", -- Multiprocessor compilation. "MultiProcessorCompile", -- Multiprocessor compilation.
"NoMinimalRebuild", -- Required for /MP above. "NoMinimalRebuild", -- Required for /MP above.
}) })
defines({ defines({
@ -252,10 +278,7 @@ workspace("xenia")
-- 10.0.15063.0: ID3D12GraphicsCommandList1::SetSamplePositions. -- 10.0.15063.0: ID3D12GraphicsCommandList1::SetSamplePositions.
-- 10.0.19041.0: D3D12_HEAP_FLAG_CREATE_NOT_ZEROED. -- 10.0.19041.0: D3D12_HEAP_FLAG_CREATE_NOT_ZEROED.
-- 10.0.22000.0: DWMWA_WINDOW_CORNER_PREFERENCE. -- 10.0.22000.0: DWMWA_WINDOW_CORNER_PREFERENCE.
filter("action:vs2017") systemversion("latest")
systemversion("10.0.22000.0")
filter("action:vs2019")
systemversion("10.0")
filter({}) filter({})
end end
end end
@ -276,9 +299,13 @@ workspace("xenia")
include("third_party/xxhash.lua") include("third_party/xxhash.lua")
include("third_party/zarchive.lua") include("third_party/zarchive.lua")
include("third_party/zstd.lua") include("third_party/zstd.lua")
include("third_party/zlib.lua") include("third_party/zlib-ng.lua")
include("third_party/pugixml.lua") include("third_party/pugixml.lua")
if os.istarget("windows") then
include("third_party/libusb.lua")
end
if not os.istarget("android") then if not os.istarget("android") then
-- SDL2 requires sdl2-config, and as of November 2020 isn't high-quality on -- SDL2 requires sdl2-config, and as of November 2020 isn't high-quality on
-- Android yet, most importantly in game controllers - the keycode and axis -- Android yet, most importantly in game controllers - the keycode and axis
@ -296,9 +323,7 @@ workspace("xenia")
removefiles({ removefiles({
"src/xenia/base/app_win32.manifest" "src/xenia/base/app_win32.manifest"
}) })
removeflags({ removefatalwarnings("All")
"FatalWarnings",
})
end end
include("src/xenia") include("src/xenia")
@ -315,6 +340,7 @@ workspace("xenia")
include("src/xenia/gpu/vulkan") include("src/xenia/gpu/vulkan")
include("src/xenia/hid") include("src/xenia/hid")
include("src/xenia/hid/nop") include("src/xenia/hid/nop")
include("src/xenia/hid/skylander")
include("src/xenia/kernel") include("src/xenia/kernel")
include("src/xenia/patcher") include("src/xenia/patcher")
include("src/xenia/ui") include("src/xenia/ui")

View File

@ -9,8 +9,6 @@ project("xenia-app-discord")
links({ links({
"discord-rpc" "discord-rpc"
}) })
defines({
})
includedirs({ includedirs({
project_root.."/third_party/discord-rpc/src" project_root.."/third_party/discord-rpc/src"
}) })

View File

@ -9,13 +9,6 @@
#include "xenia/app/emulator_window.h" #include "xenia/app/emulator_window.h"
#include <filesystem>
#include <functional>
#include <memory>
#include <mutex>
#include <string>
#include <utility>
#include "third_party/imgui/imgui.h" #include "third_party/imgui/imgui.h"
#include "third_party/stb/stb_image_write.h" #include "third_party/stb/stb_image_write.h"
#include "third_party/tomlplusplus/toml.hpp" #include "third_party/tomlplusplus/toml.hpp"
@ -167,8 +160,8 @@ using xe::ui::UIEvent;
using namespace xe::hid; using namespace xe::hid;
using namespace xe::gpu; using namespace xe::gpu;
const std::string kRecentlyPlayedTitlesFilename = "recent.toml"; constexpr std::string_view kRecentlyPlayedTitlesFilename = "recent.toml";
const std::string kBaseTitle = "Xenia-canary"; constexpr std::string_view kBaseTitle = "Xenia-canary";
EmulatorWindow::EmulatorWindow(Emulator* emulator, EmulatorWindow::EmulatorWindow(Emulator* emulator,
ui::WindowedAppContext& app_context, ui::WindowedAppContext& app_context,
@ -181,7 +174,7 @@ EmulatorWindow::EmulatorWindow(Emulator* emulator,
std::make_unique<ui::ImGuiDrawer>(window_.get(), kZOrderImGui)), std::make_unique<ui::ImGuiDrawer>(window_.get(), kZOrderImGui)),
display_config_game_config_load_callback_( display_config_game_config_load_callback_(
new DisplayConfigGameConfigLoadCallback(*emulator, *this)) { new DisplayConfigGameConfigLoadCallback(*emulator, *this)) {
base_title_ = kBaseTitle + base_title_ = std::string(kBaseTitle) +
#ifdef DEBUG #ifdef DEBUG
#if _NO_DEBUG_HEAP == 1 #if _NO_DEBUG_HEAP == 1
" DEBUG" " DEBUG"
@ -569,6 +562,96 @@ void EmulatorWindow::DisplayConfigDialog::OnDraw(ImGuiIO& io) {
} }
} }
void EmulatorWindow::ContentInstallDialog::OnDraw(ImGuiIO& io) {
ImGui::SetNextWindowPos(ImVec2(20, 20), ImGuiCond_FirstUseEver);
ImGui::SetNextWindowSize(ImVec2(20, 20), ImGuiCond_FirstUseEver);
bool dialog_open = true;
if (!ImGui::Begin(
fmt::format("Installation Progress###{}", window_id_).c_str(),
&dialog_open,
ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_AlwaysAutoResize |
ImGuiWindowFlags_HorizontalScrollbar)) {
Close();
ImGui::End();
return;
}
bool is_everything_installed = true;
for (const auto& entry : *installation_entries_) {
ImGui::BeginTable(fmt::format("table_{}", entry.name_).c_str(), 2);
ImGui::TableNextRow(0);
ImGui::TableSetColumnIndex(0);
if (entry.icon_) {
ImGui::Image(reinterpret_cast<ImTextureID>(entry.icon_.get()),
ui::default_image_icon_size);
} else {
ImGui::Dummy(ui::default_image_icon_size);
}
ImGui::TableNextColumn();
ImGui::Text("Name: %s", entry.name_.c_str());
ImGui::Text("Installation Path:");
ImGui::SameLine();
if (ImGui::TextLink(
xe::path_to_utf8(entry.data_installation_path_).c_str())) {
LaunchFileExplorer(emulator_window_.emulator_->content_root() /
entry.data_installation_path_);
}
if (entry.content_type_ != xe::XContentType::kInvalid) {
ImGui::Text("Content Type: %s",
XContentTypeMap.at(entry.content_type_).c_str());
}
std::string result = fmt::format(
"Status: {}", xe::Emulator::installStateStringName[static_cast<uint8_t>(
entry.installation_state_)]);
if (entry.installation_state_ == xe::Emulator::InstallState::failed) {
result += fmt::format(" - {} ({:08X})",
entry.installation_error_message_.c_str(),
entry.installation_result_);
}
ImGui::Text("%s", result.c_str());
ImGui::EndTable();
if (entry.content_size_ > 0) {
ImGui::ProgressBar(static_cast<float>(entry.currently_installed_size_) /
entry.content_size_);
if (entry.currently_installed_size_ != entry.content_size_ &&
entry.installation_result_ == X_ERROR_SUCCESS) {
is_everything_installed = false;
}
} else {
ImGui::ProgressBar(0.0f);
}
if (installation_entries_->size() > 1) {
ImGui::Separator();
}
}
ImGui::Spacing();
ImGui::BeginDisabled(!is_everything_installed);
if (ImGui::Button("Close")) {
ImGui::EndDisabled();
Close();
ImGui::End();
return;
}
ImGui::EndDisabled();
if (!dialog_open && is_everything_installed) {
Close();
ImGui::End();
return;
}
ImGui::End();
}
bool EmulatorWindow::Initialize() { bool EmulatorWindow::Initialize() {
window_->AddListener(&window_listener_); window_->AddListener(&window_listener_);
window_->AddInputListener(&window_listener_, kZOrderEmulatorWindowInput); window_->AddInputListener(&window_listener_, kZOrderEmulatorWindowInput);
@ -935,11 +1018,16 @@ void EmulatorWindow::OnMouseUp(const ui::MouseEvent& e) {
void EmulatorWindow::TakeScreenshot() { void EmulatorWindow::TakeScreenshot() {
xe::ui::RawImage image; xe::ui::RawImage image;
imgui_drawer_->EnableNotifications(false);
if (!GetGraphicsSystemPresenter()->CaptureGuestOutput(image) || if (!GetGraphicsSystemPresenter()->CaptureGuestOutput(image) ||
GetGraphicsSystemPresenter() == nullptr) { GetGraphicsSystemPresenter() == nullptr) {
XELOGE("Failed to capture guest output for screenshot"); XELOGE("Failed to capture guest output for screenshot");
return; return;
} }
imgui_drawer_->EnableNotifications(true);
ExportScreenshot(image); ExportScreenshot(image);
} }
@ -1006,9 +1094,9 @@ void EmulatorWindow::ToggleFullscreenOnDoubleClick() {
// this function tests if user has double clicked. // this function tests if user has double clicked.
// if double click was achieved the fullscreen gets toggled // if double click was achieved the fullscreen gets toggled
const auto now = steady_clock::now(); // current mouse event time const auto now = steady_clock::now(); // current mouse event time
const int16_t mouse_down_max_threshold = 250; constexpr int16_t mouse_down_max_threshold = 250;
const int16_t mouse_up_max_threshold = 250; constexpr int16_t mouse_up_max_threshold = 250;
const int16_t mouse_up_down_max_delta = 100; constexpr int16_t mouse_up_down_max_delta = 100;
// max delta to prevent 'chaining' of double clicks with next mouse events // max delta to prevent 'chaining' of double clicks with next mouse events
const auto last_mouse_down_delta = diff_in_ms(now, last_mouse_down); const auto last_mouse_down_delta = diff_in_ms(now, last_mouse_down);
@ -1083,62 +1171,27 @@ void EmulatorWindow::InstallContent() {
return; return;
} }
using content_installation_data = std::shared_ptr<std::vector<Emulator::ContentInstallEntry>>
std::tuple<X_STATUS, std::string, std::string>; content_installation_status =
std::map<XContentType, std::vector<content_installation_data>> std::make_shared<std::vector<Emulator::ContentInstallEntry>>();
content_installation_details;
for (const auto& path : paths) { for (const auto& path : paths) {
// Normalize the path and make absolute. content_installation_status->push_back({path});
auto abs_path = std::filesystem::absolute(path);
Emulator::ContentInstallationInfo installation_info;
auto result = emulator_->InstallContentPackage(abs_path, installation_info);
auto entry =
content_installation_details.find(installation_info.content_type);
// There is no entry with that specific type of XContent, so we must add it.
if (entry == content_installation_details.end()) {
content_installation_details.insert({installation_info.content_type, {}});
entry = content_installation_details.find(installation_info.content_type);
};
entry->second.push_back({result, installation_info.content_name,
installation_info.installation_path});
} }
// Prepare installation process summary message for (auto& entry : *content_installation_status) {
std::string summary = "Installation result: \n"; emulator_->ProcessContentPackageHeader(entry.path_, entry);
}
for (const auto& content_type : content_installation_details) { auto installationThread = std::thread([this, content_installation_status] {
if (XContentTypeMap.find(content_type.first) != XContentTypeMap.cend()) { for (auto& entry : *content_installation_status) {
summary += XContentTypeMap.at(content_type.first) + ":\n"; emulator_->InstallContentPackage(entry.path_, entry);
} else {
summary += "Unknown:\n";
} }
});
installationThread.detach();
for (const auto& content_installation_entry : content_type.second) { new ContentInstallDialog(imgui_drawer_.get(), *this,
const std::string status = content_installation_status);
std::get<0>(content_installation_entry) == X_STATUS_SUCCESS
? "Success"
: fmt::format("Failed (0x{:08X})",
std::get<0>(content_installation_entry));
summary += fmt::format("\t{} - {} => {}\n", status,
std::get<1>(content_installation_entry),
std::get<2>(content_installation_entry));
}
summary += "\n";
}
if (content_installation_details.count(XContentType::kProfile)) {
emulator_->kernel_state()->xam_state()->profile_manager()->ReloadProfiles();
}
xe::ui::ImGuiDialog::ShowMessageBox(imgui_drawer_.get(),
"Content Installation Summary", summary);
} }
void EmulatorWindow::ExtractZarchive() { void EmulatorWindow::ExtractZarchive() {
@ -1424,6 +1477,12 @@ void EmulatorWindow::ToggleControllerVibration() {
auto input_lock = input_sys->lock(); auto input_lock = input_sys->lock();
input_sys->ToggleVibration(); input_sys->ToggleVibration();
if (emulator_->kernel_state()) {
emulator_->kernel_state()->BroadcastNotification(
kXNotificationSystemProfileSettingChanged,
static_cast<uint32_t>(input_sys->GetConnectedSlots().count()));
}
} }
} }
@ -1624,7 +1683,7 @@ EmulatorWindow::ControllerHotKey EmulatorWindow::ProcessControllerHotkey(
} }
// Hotkey cool-down to prevent toggling too fast // Hotkey cool-down to prevent toggling too fast
const std::chrono::milliseconds delay(75); constexpr std::chrono::milliseconds delay(75);
// If the Xbox Gamebar is enabled or the Guide button is disabled then // If the Xbox Gamebar is enabled or the Guide button is disabled then
// replace the Guide button with the Back button without redeclaring the key // replace the Guide button with the Back button without redeclaring the key
@ -1794,10 +1853,11 @@ EmulatorWindow::ControllerHotKey EmulatorWindow::ProcessControllerHotkey(
} }
if (!notificationTitle.empty()) { if (!notificationTitle.empty()) {
app_context_.CallInUIThread([&]() { app_context_.CallInUIThread(
new xe::ui::HostNotificationWindow(imgui_drawer(), notificationTitle, [imgui_drawer = imgui_drawer(), notificationTitle, notificationDesc]() {
notificationDesc, 0); new xe::ui::HostNotificationWindow(imgui_drawer, notificationTitle,
}); notificationDesc, 0);
});
} }
xe::threading::Sleep(delay); xe::threading::Sleep(delay);
@ -1808,7 +1868,7 @@ EmulatorWindow::ControllerHotKey EmulatorWindow::ProcessControllerHotkey(
void EmulatorWindow::VibrateController(xe::hid::InputSystem* input_sys, void EmulatorWindow::VibrateController(xe::hid::InputSystem* input_sys,
uint32_t user_index, uint32_t user_index,
bool toggle_rumble) { bool toggle_rumble) {
const std::chrono::milliseconds rumble_duration(100); constexpr std::chrono::milliseconds rumble_duration(100);
// Hold lock while sleeping this thread for the duration of the rumble, // Hold lock while sleeping this thread for the duration of the rumble,
// otherwise the rumble may fail. // otherwise the rumble may fail.
@ -1830,7 +1890,7 @@ void EmulatorWindow::VibrateController(xe::hid::InputSystem* input_sys,
void EmulatorWindow::GamepadHotKeys() { void EmulatorWindow::GamepadHotKeys() {
X_INPUT_STATE state; X_INPUT_STATE state;
const std::chrono::milliseconds thread_delay(75); constexpr std::chrono::milliseconds thread_delay(75);
auto input_sys = emulator_->input_system(); auto input_sys = emulator_->input_system();

View File

@ -167,6 +167,34 @@ class EmulatorWindow {
EmulatorWindow& emulator_window_; EmulatorWindow& emulator_window_;
}; };
class ContentInstallDialog final : public ui::ImGuiDialog {
public:
ContentInstallDialog(
ui::ImGuiDrawer* imgui_drawer, EmulatorWindow& emulator_window,
std::shared_ptr<std::vector<Emulator::ContentInstallEntry>> entries)
: ui::ImGuiDialog(imgui_drawer),
emulator_window_(emulator_window),
installation_entries_(entries) {
window_id_ = GetWindowId();
}
~ContentInstallDialog() {
for (auto& entry : *installation_entries_) {
entry.icon_.release();
}
}
protected:
void OnDraw(ImGuiIO& io) override;
private:
uint64_t window_id_;
EmulatorWindow& emulator_window_;
std::shared_ptr<std::vector<Emulator::ContentInstallEntry>>
installation_entries_;
};
class DisplayConfigDialog final : public ui::ImGuiDialog { class DisplayConfigDialog final : public ui::ImGuiDialog {
public: public:
DisplayConfigDialog(ui::ImGuiDrawer* imgui_drawer, DisplayConfigDialog(ui::ImGuiDrawer* imgui_drawer,

View File

@ -54,11 +54,13 @@ project("xenia-app")
-- Unified library containing all apps as StaticLibs, not just the main -- Unified library containing all apps as StaticLibs, not just the main
-- emulator windowed app. -- emulator windowed app.
kind("SharedLib") kind("SharedLib")
links({ if enableMiscSubprojects then
"xenia-gpu-vulkan-trace-viewer", links({
"xenia-hid-demo", "xenia-gpu-vulkan-trace-viewer",
"xenia-ui-window-vulkan-demo", "xenia-hid-demo",
}) "xenia-ui-window-vulkan-demo",
})
end
filter(NOT_SINGLE_LIBRARY_FILTER) filter(NOT_SINGLE_LIBRARY_FILTER)
kind("WindowedApp") kind("WindowedApp")
@ -114,21 +116,17 @@ project("xenia-app")
"xenia-ui-d3d12", "xenia-ui-d3d12",
}) })
filter({"platforms:Windows", SINGLE_LIBRARY_FILTER}) if enableMiscSubprojects then
links({ filter({"platforms:Windows", SINGLE_LIBRARY_FILTER})
"xenia-gpu-d3d12-trace-viewer", links({
"xenia-ui-window-d3d12-demo", "xenia-gpu-d3d12-trace-viewer",
}) "xenia-ui-window-d3d12-demo",
-- filter({"configurations:Release", "platforms:Windows"}) })
-- buildoptions({ end
-- "/O1",
-- })
filter("platforms:Windows") filter("platforms:Windows")
-- Only create the .user file if it doesn't already exist. -- Only create the .user file if it doesn't already exist.
local user_file = project_root.."/build/xenia-app.vcxproj.user" local user_file = project_root.."/build/xenia-app.vcxproj.user"
if not os.isfile(user_file) then if not os.isfile(user_file) then
debugdir(project_root) debugdir(project_root)
debugargs({
})
end end

View File

@ -6,83 +6,22 @@
* Released under the BSD license - see LICENSE in the root for more details. * * Released under the BSD license - see LICENSE in the root for more details. *
****************************************************************************** ******************************************************************************
*/ */
#include "xenia/app/profile_dialogs.h" #include "xenia/app/profile_dialogs.h"
#include <algorithm>
#include "xenia/app/emulator_window.h" #include "xenia/app/emulator_window.h"
#include "xenia/base/png_utils.h"
#include "xenia/base/system.h" #include "xenia/base/system.h"
#include "xenia/kernel/util/shim_utils.h" #include "xenia/kernel/util/shim_utils.h"
#include "xenia/kernel/xam/xam_ui.h"
#include "xenia/ui/file_picker.h"
#include "xenia/kernel/xam/ui/create_profile_ui.h"
#include "xenia/kernel/xam/ui/gamercard_ui.h"
#include "xenia/kernel/xam/ui/signin_ui.h"
#include "xenia/kernel/xam/ui/title_info_ui.h"
namespace xe { namespace xe {
namespace kernel {
namespace xam {
extern bool xeDrawProfileContent(ui::ImGuiDrawer* imgui_drawer,
const uint64_t xuid, const uint8_t user_index,
const X_XAMACCOUNTINFO* account,
uint64_t* selected_xuid);
}
} // namespace kernel
namespace app { namespace app {
void CreateProfileDialog::OnDraw(ImGuiIO& io) {
if (!has_opened_) {
ImGui::OpenPopup("Create Profile");
has_opened_ = true;
}
auto profile_manager = emulator_window_->emulator()
->kernel_state()
->xam_state()
->profile_manager();
bool dialog_open = true;
if (!ImGui::BeginPopupModal("Create Profile", &dialog_open,
ImGuiWindowFlags_NoCollapse |
ImGuiWindowFlags_AlwaysAutoResize |
ImGuiWindowFlags_HorizontalScrollbar)) {
Close();
return;
}
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows) &&
!ImGui::IsAnyItemActive() && !ImGui::IsMouseClicked(0)) {
ImGui::SetKeyboardFocusHere(0);
}
ImGui::TextUnformatted("Gamertag:");
ImGui::InputText("##Gamertag", gamertag_, sizeof(gamertag_));
const std::string gamertag_string = std::string(gamertag_);
bool valid = profile_manager->IsGamertagValid(gamertag_string);
ImGui::BeginDisabled(!valid);
if (ImGui::Button("Create")) {
bool autologin = (profile_manager->GetAccountCount() == 0);
if (profile_manager->CreateProfile(gamertag_string, autologin,
migration_) &&
migration_) {
emulator_window_->emulator()->DataMigration(0xB13EBABEBABEBABE);
}
std::fill(std::begin(gamertag_), std::end(gamertag_), '\0');
dialog_open = false;
}
ImGui::EndDisabled();
ImGui::SameLine();
if (ImGui::Button("Cancel")) {
std::fill(std::begin(gamertag_), std::end(gamertag_), '\0');
dialog_open = false;
}
if (!dialog_open) {
ImGui::CloseCurrentPopup();
Close();
ImGui::EndPopup();
return;
}
ImGui::EndPopup();
}
void NoProfileDialog::OnDraw(ImGuiIO& io) { void NoProfileDialog::OnDraw(ImGuiIO& io) {
auto profile_manager = emulator_window_->emulator() auto profile_manager = emulator_window_->emulator()
->kernel_state() ->kernel_state()
@ -124,13 +63,13 @@ void NoProfileDialog::OnDraw(ImGuiIO& io) {
if (content_files.empty()) { if (content_files.empty()) {
if (ImGui::Button("Create Profile")) { if (ImGui::Button("Create Profile")) {
new CreateProfileDialog(emulator_window_->imgui_drawer(), new kernel::xam::ui::CreateProfileUI(emulator_window_->imgui_drawer(),
emulator_window_); emulator_window_->emulator());
} }
} else { } else {
if (ImGui::Button("Create profile & migrate data")) { if (ImGui::Button("Create profile & migrate data")) {
new CreateProfileDialog(emulator_window_->imgui_drawer(), new kernel::xam::ui::CreateProfileUI(emulator_window_->imgui_drawer(),
emulator_window_, true); emulator_window_->emulator(), true);
} }
} }
@ -149,6 +88,57 @@ void NoProfileDialog::OnDraw(ImGuiIO& io) {
ImGui::End(); ImGui::End();
} }
void ProfileConfigDialog::LoadProfileIcon() {
if (!emulator_window_) {
return;
}
for (uint8_t user_index = 0; user_index < XUserMaxUserCount; user_index++) {
const auto profile = emulator_window_->emulator()
->kernel_state()
->xam_state()
->profile_manager()
->GetProfile(user_index);
if (!profile) {
continue;
}
LoadProfileIcon(profile->xuid());
}
}
void ProfileConfigDialog::LoadProfileIcon(const uint64_t xuid) {
if (!emulator_window_) {
return;
}
const auto profile_manager = emulator_window_->emulator()
->kernel_state()
->xam_state()
->profile_manager();
if (!profile_manager) {
return;
}
const auto profile = profile_manager->GetProfile(xuid);
if (!profile) {
if (profile_icon_.contains(xuid)) {
profile_icon_[xuid].release();
}
return;
}
const auto profile_icon =
profile->GetProfileIcon(kernel::xam::XTileType::kGamerTile);
if (profile_icon.empty()) {
return;
}
profile_icon_[xuid].release();
profile_icon_[xuid] = imgui_drawer()->LoadImGuiIcon(profile_icon);
}
void ProfileConfigDialog::OnDraw(ImGuiIO& io) { void ProfileConfigDialog::OnDraw(ImGuiIO& io) {
if (!emulator_window_->emulator() || if (!emulator_window_->emulator() ||
!emulator_window_->emulator()->kernel_state() || !emulator_window_->emulator()->kernel_state() ||
@ -184,28 +174,120 @@ void ProfileConfigDialog::OnDraw(ImGuiIO& io) {
ImGui::Separator(); ImGui::Separator();
} }
const ImVec2 next_window_position =
ImVec2(ImGui::GetWindowPos().x + ImGui::GetWindowSize().x + 20.f,
ImGui::GetWindowPos().y);
for (auto& [xuid, account] : *profiles) { for (auto& [xuid, account] : *profiles) {
ImGui::PushID(static_cast<int>(xuid)); ImGui::PushID(static_cast<int>(xuid));
const uint8_t user_index = const uint8_t user_index =
profile_manager->GetUserIndexAssignedToProfile(xuid); profile_manager->GetUserIndexAssignedToProfile(xuid);
if (!kernel::xam::xeDrawProfileContent(imgui_drawer(), xuid, user_index, const auto profile_icon = profile_icon_.find(xuid) != profile_icon_.cend()
&account, &selected_xuid_)) { ? profile_icon_[xuid].get()
: nullptr;
auto context_menu_fun = [=, this]() -> bool {
if (ImGui::BeginPopupContextItem("Profile Menu")) {
//*selected_xuid = xuid;
if (user_index == XUserIndexAny) {
if (ImGui::MenuItem("Login")) {
profile_manager->Login(xuid);
if (!profile_manager->GetProfile(xuid)
->GetProfileIcon(kernel::xam::XTileType::kGamerTile)
.empty()) {
LoadProfileIcon(xuid);
}
}
if (ImGui::BeginMenu("Login to slot:")) {
for (uint8_t i = 1; i <= XUserMaxUserCount; i++) {
if (ImGui::MenuItem(fmt::format("slot {}", i).c_str())) {
profile_manager->Login(xuid, i - 1);
}
}
ImGui::EndMenu();
}
} else {
if (ImGui::MenuItem("Logout")) {
profile_manager->Logout(user_index);
LoadProfileIcon(xuid);
}
}
if (ImGui::MenuItem("Modify")) {
new kernel::xam::ui::GamercardUI(
emulator_window_->window(), emulator_window_->imgui_drawer(),
emulator_window_->emulator()->kernel_state(), xuid);
}
const bool is_signedin = profile_manager->GetProfile(xuid) != nullptr;
ImGui::BeginDisabled(!is_signedin);
if (ImGui::MenuItem("Show Played Titles")) {
new kernel::xam::ui::TitleListUI(
emulator_window_->imgui_drawer(), next_window_position,
profile_manager->GetProfile(user_index));
}
ImGui::EndDisabled();
if (ImGui::MenuItem("Show Content Directory")) {
const auto path = profile_manager->GetProfileContentPath(
xuid, emulator_window_->emulator()->kernel_state()->title_id());
if (!std::filesystem::exists(path)) {
std::filesystem::create_directories(path);
}
std::thread path_open(LaunchFileExplorer, path);
path_open.detach();
}
if (!emulator_window_->emulator()->is_title_open()) {
ImGui::Separator();
if (ImGui::BeginMenu("Delete Profile")) {
ImGui::BeginTooltip();
ImGui::TextUnformatted(
fmt::format(
"You're about to delete profile: {} (XUID: {:016X}). "
"This will remove all data assigned to this profile "
"including savefiles. Are you sure?",
account.GetGamertagString(), xuid)
.c_str());
ImGui::EndTooltip();
if (ImGui::MenuItem("Yes, delete it!")) {
profile_manager->DeleteProfile(xuid);
ImGui::EndMenu();
ImGui::EndPopup();
return false;
}
ImGui::EndMenu();
}
}
ImGui::EndPopup();
}
return true;
};
if (!kernel::xam::xeDrawProfileContent(
imgui_drawer(), xuid, user_index, &account, profile_icon,
context_menu_fun, [=, this]() { LoadProfileIcon(xuid); },
&selected_xuid_)) {
ImGui::PopID(); ImGui::PopID();
ImGui::End(); ImGui::End();
return; return;
} }
ImGui::PopID(); ImGui::PopID();
ImGui::Spacing();
ImGui::Separator(); ImGui::Separator();
} }
ImGui::Spacing(); ImGui::Spacing();
if (ImGui::Button("Create Profile")) { if (ImGui::Button("Create Profile")) {
new CreateProfileDialog(emulator_window_->imgui_drawer(), emulator_window_); new kernel::xam::ui::CreateProfileUI(emulator_window_->imgui_drawer(),
emulator_window_->emulator());
} }
ImGui::End(); ImGui::End();
@ -217,4 +299,4 @@ void ProfileConfigDialog::OnDraw(ImGuiIO& io) {
} }
} // namespace app } // namespace app
} // namespace xe } // namespace xe

View File

@ -19,26 +19,6 @@ namespace app {
class EmulatorWindow; class EmulatorWindow;
class CreateProfileDialog final : public ui::ImGuiDialog {
public:
CreateProfileDialog(ui::ImGuiDrawer* imgui_drawer,
EmulatorWindow* emulator_window,
bool with_migration = false)
: ui::ImGuiDialog(imgui_drawer),
emulator_window_(emulator_window),
migration_(with_migration) {
memset(gamertag_, 0, sizeof(gamertag_));
}
protected:
void OnDraw(ImGuiIO& io) override;
bool has_opened_ = false;
bool migration_ = false;
char gamertag_[16] = "";
EmulatorWindow* emulator_window_;
};
class NoProfileDialog final : public ui::ImGuiDialog { class NoProfileDialog final : public ui::ImGuiDialog {
public: public:
NoProfileDialog(ui::ImGuiDrawer* imgui_drawer, NoProfileDialog(ui::ImGuiDrawer* imgui_drawer,
@ -55,12 +35,19 @@ class ProfileConfigDialog final : public ui::ImGuiDialog {
public: public:
ProfileConfigDialog(ui::ImGuiDrawer* imgui_drawer, ProfileConfigDialog(ui::ImGuiDrawer* imgui_drawer,
EmulatorWindow* emulator_window) EmulatorWindow* emulator_window)
: ui::ImGuiDialog(imgui_drawer), emulator_window_(emulator_window) {} : ui::ImGuiDialog(imgui_drawer), emulator_window_(emulator_window) {
LoadProfileIcon();
}
protected: protected:
void OnDraw(ImGuiIO& io) override; void OnDraw(ImGuiIO& io) override;
private: private:
void LoadProfileIcon();
void LoadProfileIcon(const uint64_t xuid);
std::map<uint64_t, std::unique_ptr<ui::ImmediateTexture>> profile_icon_;
uint64_t selected_xuid_ = 0; uint64_t selected_xuid_ = 0;
EmulatorWindow* emulator_window_; EmulatorWindow* emulator_window_;
}; };

View File

@ -13,7 +13,6 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include <thread> #include <thread>
#include <vector>
#include "xenia/app/discord/discord_presence.h" #include "xenia/app/discord/discord_presence.h"
#include "xenia/app/emulator_window.h" #include "xenia/app/emulator_window.h"
@ -95,9 +94,15 @@ UPDATE_from_bool(mount_cache, 2024, 8, 31, 20, false);
DEFINE_transient_path(target, "", DEFINE_transient_path(target, "",
"Specifies the target .xex or .iso to execute.", "Specifies the target .xex or .iso to execute.",
"General"); "General");
#ifndef XE_PLATFORM_WIN32
DEFINE_transient_bool(portable, false,
"Specifies if Xenia should run in portable mode.",
"General");
#else
DEFINE_transient_bool(portable, true, DEFINE_transient_bool(portable, true,
"Specifies if Xenia should run in portable mode.", "Specifies if Xenia should run in portable mode.",
"General"); "General");
#endif
DECLARE_bool(debug); DECLARE_bool(debug);
@ -421,7 +426,7 @@ bool EmulatorApp::OnInitialize() {
if (!cvars::portable && if (!cvars::portable &&
!std::filesystem::exists(storage_root / "portable.txt")) { !std::filesystem::exists(storage_root / "portable.txt")) {
storage_root = xe::filesystem::GetUserFolder(); storage_root = xe::filesystem::GetUserFolder();
#if defined(XE_PLATFORM_WIN32) || defined(XE_PLATFORM_GNU_LINUX) #if defined(XE_PLATFORM_WIN32) || defined(XE_PLATFORM_LINUX)
storage_root = storage_root / "Xenia"; storage_root = storage_root / "Xenia";
#else #else
// TODO(Triang3l): Point to the app's external storage "files" directory // TODO(Triang3l): Point to the app's external storage "files" directory

View File

@ -18,12 +18,12 @@ namespace apu {
class AudioDriver { class AudioDriver {
public: public:
static const uint32_t kFrameFrequencyDefault = 48000; static constexpr uint32_t kFrameFrequencyDefault = 48000;
static const uint32_t kFrameChannelsDefault = 6; static constexpr uint32_t kFrameChannelsDefault = 6;
static const uint32_t kChannelSamplesDefault = 256; static constexpr uint32_t kChannelSamplesDefault = 256;
static const uint32_t kFrameSamplesMax = static constexpr uint32_t kFrameSamplesMax =
kFrameChannelsDefault * kChannelSamplesDefault; kFrameChannelsDefault * kChannelSamplesDefault;
static const uint32_t kFrameSizeMax = sizeof(float) * kFrameSamplesMax; static constexpr uint32_t kFrameSizeMax = sizeof(float) * kFrameSamplesMax;
virtual ~AudioDriver(); virtual ~AudioDriver();

View File

@ -412,8 +412,9 @@ bool AudioMediaPlayer::LoadSongToMemory(std::vector<uint8_t>* buffer) {
buffer->resize(vfs_file->entry()->size()); buffer->resize(vfs_file->entry()->size());
size_t bytes_read = 0; size_t bytes_read = 0;
result = vfs_file->ReadSync(buffer->data(), vfs_file->entry()->size(), 0, result = vfs_file->ReadSync(
&bytes_read); std::span<uint8_t>(buffer->data(), vfs_file->entry()->size()), 0,
&bytes_read);
return !result; return !result;
} }
@ -553,4 +554,4 @@ void AudioMediaPlayer::DeleteDriver() {
} }
} // namespace apu } // namespace apu
} // namespace xe } // namespace xe

View File

@ -32,7 +32,7 @@ class AudioSystem {
public: public:
// TODO(gibbed): respect XAUDIO2_MAX_QUEUED_BUFFERS somehow (ie min(64, // TODO(gibbed): respect XAUDIO2_MAX_QUEUED_BUFFERS somehow (ie min(64,
// XAUDIO2_MAX_QUEUED_BUFFERS)) // XAUDIO2_MAX_QUEUED_BUFFERS))
static const size_t kMaximumQueuedFrames = 64; static constexpr size_t kMaximumQueuedFrames = 64;
virtual ~AudioSystem(); virtual ~AudioSystem();
@ -81,7 +81,7 @@ class AudioSystem {
kernel::object_ref<kernel::XHostThread> worker_thread_; kernel::object_ref<kernel::XHostThread> worker_thread_;
xe::global_critical_region global_critical_region_; xe::global_critical_region global_critical_region_;
static const size_t kMaximumClientCount = 8; static constexpr size_t kMaximumClientCount = 8;
struct { struct {
AudioDriver* driver; AudioDriver* driver;
uint32_t callback; uint32_t callback;

View File

@ -10,6 +10,4 @@ project("xenia-apu-nop")
"xenia-base", "xenia-base",
"xenia-apu", "xenia-apu",
}) })
defines({
})
local_platform_files() local_platform_files()

View File

@ -12,8 +12,6 @@ project("xenia-apu")
"libavformat", "libavformat",
"xenia-base", "xenia-base",
}) })
defines({
})
includedirs({ includedirs({
project_root.."/third_party/FFmpeg/", project_root.."/third_party/FFmpeg/",
}) })

View File

@ -12,7 +12,5 @@ project("xenia-apu-sdl")
"xenia-helper-sdl", "xenia-helper-sdl",
"SDL2", "SDL2",
}) })
defines({
})
local_platform_files() local_platform_files()
sdl2_include() sdl2_include()

View File

@ -9,7 +9,6 @@
#include "xenia/apu/sdl/sdl_audio_driver.h" #include "xenia/apu/sdl/sdl_audio_driver.h"
#include <array>
#include <cstring> #include <cstring>
#include "xenia/apu/apu_flags.h" #include "xenia/apu/apu_flags.h"

View File

@ -10,6 +10,4 @@ project("xenia-apu-xaudio2")
"xenia-base", "xenia-base",
"xenia-apu", "xenia-apu",
}) })
defines({
})
local_platform_files() local_platform_files()

View File

@ -137,10 +137,10 @@ bool XAudio2AudioDriver::InitializeObjects(Objects& objects) {
api::XAUDIO2_DEBUG_CONFIGURATION config; api::XAUDIO2_DEBUG_CONFIGURATION config;
config.TraceMask = api::XE_XAUDIO2_LOG_ERRORS | api::XE_XAUDIO2_LOG_WARNINGS; config.TraceMask = api::XE_XAUDIO2_LOG_ERRORS | api::XE_XAUDIO2_LOG_WARNINGS;
config.BreakMask = 0; config.BreakMask = 0;
config.LogThreadID = FALSE; config.LogThreadID = false;
config.LogTiming = TRUE; config.LogTiming = true;
config.LogFunctionName = TRUE; config.LogFunctionName = true;
config.LogFileline = TRUE; config.LogFileline = true;
objects.audio->SetDebugConfiguration(&config); objects.audio->SetDebugConfiguration(&config);
hr = objects.audio->CreateMasteringVoice(&objects.mastering_voice); hr = objects.audio->CreateMasteringVoice(&objects.mastering_voice);
@ -165,7 +165,7 @@ bool XAudio2AudioDriver::InitializeObjects(Objects& objects) {
waveformat.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; waveformat.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
waveformat.Samples.wValidBitsPerSample = waveformat.Format.wBitsPerSample; waveformat.Samples.wValidBitsPerSample = waveformat.Format.wBitsPerSample;
static const DWORD kChannelMasks[] = { static constexpr DWORD kChannelMasks[] = {
0, 0,
0, 0,
SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT, SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT,

View File

@ -106,7 +106,7 @@ class XAudio2AudioDriver : public AudioDriver {
uint32_t frame_size_; uint32_t frame_size_;
bool need_format_conversion_; bool need_format_conversion_;
static const uint32_t frame_count_ = api::XE_XAUDIO2_MAX_QUEUED_BUFFERS; static constexpr uint32_t frame_count_ = api::XE_XAUDIO2_MAX_QUEUED_BUFFERS;
float frames_[frame_count_][kFrameSamplesMax]; float frames_[frame_count_][kFrameSamplesMax];
uint32_t current_frame_ = 0; uint32_t current_frame_ = 0;

View File

@ -9,7 +9,6 @@
#include "xenia/apu/xma_context.h" #include "xenia/apu/xma_context.h"
#include <algorithm>
#include <cstring> #include <cstring>
#include "xenia/apu/xma_decoder.h" #include "xenia/apu/xma_decoder.h"

View File

@ -14,7 +14,6 @@
#include <atomic> #include <atomic>
#include <mutex> #include <mutex>
#include <queue> #include <queue>
// #include <vector>
#include "xenia/memory.h" #include "xenia/memory.h"
#include "xenia/xbox.h" #include "xenia/xbox.h"

View File

@ -10,8 +10,6 @@
#include "xenia/apu/xma_context_new.h" #include "xenia/apu/xma_context_new.h"
#include "xenia/apu/xma_helpers.h" #include "xenia/apu/xma_helpers.h"
#include <algorithm>
#include "xenia/base/logging.h" #include "xenia/base/logging.h"
#include "xenia/base/platform.h" #include "xenia/base/platform.h"
#include "xenia/base/profiling.h" #include "xenia/base/profiling.h"
@ -691,4 +689,4 @@ bool XmaContextNew::DecodePacket(AVCodecContext* av_context,
} }
} // namespace apu } // namespace apu
} // namespace xe } // namespace xe

View File

@ -133,4 +133,4 @@ class XmaContextNew : public XmaContext {
} // namespace apu } // namespace apu
} // namespace xe } // namespace xe
#endif // XENIA_APU_XMA_CONTEXT_H_ #endif // XENIA_APU_XMA_CONTEXT_H_

View File

@ -9,7 +9,6 @@
#include "xenia/apu/xma_context_old.h" #include "xenia/apu/xma_context_old.h"
#include <algorithm>
#include <cstring> #include <cstring>
#include "xenia/apu/xma_decoder.h" #include "xenia/apu/xma_decoder.h"

View File

@ -18,7 +18,7 @@ namespace xe {
namespace apu { namespace apu {
namespace xma { namespace xma {
static const uint32_t kMaxFrameLength = 0x7FFF; static constexpr uint32_t kMaxFrameLength = 0x7FFF;
// Get number of frames that /begin/ in this packet. This is valid only for XMA2 // Get number of frames that /begin/ in this packet. This is valid only for XMA2
// packets // packets
@ -49,4 +49,4 @@ static uint32_t GetPacketFrameOffset(const uint8_t* packet) {
} // namespace apu } // namespace apu
} // namespace xe } // namespace xe
#endif // XENIA_APU_XMA_HELPERS_H_ #endif // XENIA_APU_XMA_HELPERS_H_

View File

@ -32,7 +32,7 @@ class XmaRegisterFile {
static const XmaRegisterInfo* GetRegisterInfo(uint32_t index); static const XmaRegisterInfo* GetRegisterInfo(uint32_t index);
static const size_t kRegisterCount = (0xFFFF + 1) / 4; static constexpr size_t kRegisterCount = (0xFFFF + 1) / 4;
uint32_t values[kRegisterCount]; uint32_t values[kRegisterCount];
uint32_t operator[](uint32_t reg) const { return values[reg]; } uint32_t operator[](uint32_t reg) const { return values[reg]; }

View File

@ -10,7 +10,6 @@
#include "xenia/base/arena.h" #include "xenia/base/arena.h"
#include <cstring> #include <cstring>
#include <memory>
#include "xenia/base/assert.h" #include "xenia/base/assert.h"
#include "xenia/base/math.h" #include "xenia/base/math.h"

View File

@ -113,4 +113,4 @@ void BitMap::Reset() {
} }
} }
} // namespace xe } // namespace xe

View File

@ -46,8 +46,8 @@ class BitMap {
std::vector<uint64_t>& data() { return data_; } std::vector<uint64_t>& data() { return data_; }
private: private:
const static size_t kDataSize = 8; constexpr static size_t kDataSize = 8;
const static size_t kDataSizeBits = kDataSize * 8; constexpr static size_t kDataSizeBits = kDataSize * 8;
std::vector<uint64_t> data_; std::vector<uint64_t> data_;
inline size_t TryAcquireAt(size_t i); inline size_t TryAcquireAt(size_t i);
}; };

View File

@ -30,7 +30,7 @@ std::pair<size_t, size_t> NextUnsetRange(const Block* bits, size_t first,
return std::make_pair(size_t(first), size_t(0)); return std::make_pair(size_t(first), size_t(0));
} }
size_t last = first + length - 1; size_t last = first + length - 1;
const size_t block_bits = sizeof(Block) * CHAR_BIT; constexpr size_t block_bits = sizeof(Block) * CHAR_BIT;
size_t block_first = first / block_bits; size_t block_first = first / block_bits;
size_t block_last = last / block_bits; size_t block_last = last / block_bits;
size_t range_start = SIZE_MAX; size_t range_start = SIZE_MAX;
@ -80,7 +80,7 @@ void SetRange(Block* bits, size_t first, size_t length) {
return; return;
} }
size_t last = first + length - 1; size_t last = first + length - 1;
const size_t block_bits = sizeof(Block) * CHAR_BIT; constexpr size_t block_bits = sizeof(Block) * CHAR_BIT;
size_t block_first = first / block_bits; size_t block_first = first / block_bits;
size_t block_last = last / block_bits; size_t block_last = last / block_bits;
Block set_first = ~((Block(1) << (first & (block_bits - 1))) - 1); Block set_first = ~((Block(1) << (first & (block_bits - 1))) - 1);

View File

@ -9,8 +9,6 @@
#include "xenia/base/clock.h" #include "xenia/base/clock.h"
#include <algorithm>
#include <limits>
#include <mutex> #include <mutex>
#include "xenia/base/assert.h" #include "xenia/base/assert.h"

View File

@ -53,4 +53,5 @@ uint64_t Clock::QueryHostUptimeMillis() {
return host_tick_count_platform() * 1000 / host_tick_frequency_platform(); return host_tick_count_platform() * 1000 / host_tick_frequency_platform();
} }
uint64_t Clock::QueryHostInterruptTime() { return host_tick_count_platform(); }
} // namespace xe } // namespace xe

View File

@ -7,14 +7,11 @@
****************************************************************************** ******************************************************************************
*/ */
#include <string>
#include <vector>
#include "xenia/base/console_app_main.h" #include "xenia/base/console_app_main.h"
#include "xenia/base/cvar.h" #include "xenia/base/cvar.h"
#include "xenia/base/logging.h" #include "xenia/base/logging.h"
extern "C" int main(int argc, char** argv) { int main(int argc, char** argv) {
xe::ConsoleAppEntryInfo entry_info = xe::GetConsoleAppEntryInfo(); xe::ConsoleAppEntryInfo entry_info = xe::GetConsoleAppEntryInfo();
if (!entry_info.transparent_options) { if (!entry_info.transparent_options) {

View File

@ -8,7 +8,6 @@
*/ */
#include <cstdlib> #include <cstdlib>
#include <vector>
#include "xenia/base/console_app_main.h" #include "xenia/base/console_app_main.h"
#include "xenia/base/main_win.h" #include "xenia/base/main_win.h"

View File

@ -9,7 +9,7 @@
#include "xenia/base/cvar.h" #include "xenia/base/cvar.h"
#include <iostream> #include <iostream>
#define UTF_CPP_CPLUSPLUS 201703L #define UTF_CPP_CPLUSPLUS 202002L
#include "third_party/utfcpp/source/utf8.h" #include "third_party/utfcpp/source/utf8.h"
#include "xenia/base/console.h" #include "xenia/base/console.h"
@ -125,9 +125,9 @@ std::string EscapeBasicString(const std::string_view view) {
result += "\\\\"; result += "\\\\";
} else if (c < 0x20 || c == 0x7F) { } else if (c < 0x20 || c == 0x7F) {
if (c <= 0xFFFF) { if (c <= 0xFFFF) {
result += fmt::format("\\u{:04X}", c); result += fmt::format("\\u{:04X}", static_cast<uint32_t>(c));
} else { } else {
result += fmt::format("\\u{:08X}", c); result += fmt::format("\\u{:08X}", static_cast<uint32_t>(c));
} }
} else { } else {
utfcpp::append(static_cast<char32_t>(c), result); utfcpp::append(static_cast<char32_t>(c), result);
@ -159,7 +159,7 @@ std::string EscapeMultilineBasicString(const std::string_view view) {
if (c == '\b') { if (c == '\b') {
result += "\\b"; result += "\\b";
} else if (c == '\t' || c == '\n') { } else if (c == '\t' || c == '\n') {
result += c; result += static_cast<uint32_t>(c);
} else if (c == '\f') { } else if (c == '\f') {
result += "\\f"; result += "\\f";
} else if (c == '\r') { } else if (c == '\r') {
@ -171,9 +171,9 @@ std::string EscapeMultilineBasicString(const std::string_view view) {
result += "\\\\"; result += "\\\\";
} else if (c < 0x20 || c == 0x7F) { } else if (c < 0x20 || c == 0x7F) {
if (c <= 0xFFFF) { if (c <= 0xFFFF) {
result += fmt::format("\\u{:04X}", c); result += fmt::format("\\u{:04X}", static_cast<uint32_t>(c));
} else { } else {
result += fmt::format("\\u{:08X}", c); result += fmt::format("\\u{:08X}", static_cast<uint32_t>(c));
} }
} else { } else {
utfcpp::append(static_cast<char32_t>(c), result); utfcpp::append(static_cast<char32_t>(c), result);
@ -189,8 +189,8 @@ std::string EscapeMultilineBasicString(const std::string_view view) {
} }
std::string EscapeString(const std::string_view view) { std::string EscapeString(const std::string_view view) {
const auto multiline_chars = std::string_view("\r\n"); constexpr auto multiline_chars = std::string_view("\r\n");
const auto escape_chars = std::string_view( constexpr auto escape_chars = std::string_view(
"\0\b\v\f" "\0\b\v\f"
"\x01\x02\x03\x04\x05\x06\x07\x0E\x0F" "\x01\x02\x03\x04\x05\x06\x07\x0E\x0F"
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F" "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"

View File

@ -10,7 +10,6 @@
#include "xenia/base/exception_handler.h" #include "xenia/base/exception_handler.h"
#include <signal.h> #include <signal.h>
#include <ucontext.h>
#include <cstdint> #include <cstdint>
#include "xenia/base/assert.h" #include "xenia/base/assert.h"
@ -168,7 +167,7 @@ static void ExceptionHandlerCallback(int signal_number, siginfo_t* signal_info,
mcontext.gregs[REG_EFL] = greg_t(thread_context.eflags); mcontext.gregs[REG_EFL] = greg_t(thread_context.eflags);
uint32_t modified_register_index; uint32_t modified_register_index;
// The order must match the order in X64Register. // The order must match the order in X64Register.
static const size_t kIntRegisterMap[] = { static constexpr size_t kIntRegisterMap[] = {
REG_RAX, REG_RCX, REG_RDX, REG_RBX, REG_RSP, REG_RBP, REG_RAX, REG_RCX, REG_RDX, REG_RBX, REG_RSP, REG_RBP,
REG_RSI, REG_RDI, REG_R8, REG_R9, REG_R10, REG_R11, REG_RSI, REG_RDI, REG_R8, REG_R9, REG_R10, REG_R11,
REG_R12, REG_R13, REG_R14, REG_R15, REG_R12, REG_R13, REG_R14, REG_R15,

View File

@ -9,8 +9,6 @@
#include "xenia/base/filesystem.h" #include "xenia/base/filesystem.h"
#include <algorithm>
namespace xe { namespace xe {
namespace filesystem { namespace filesystem {
@ -24,5 +22,42 @@ bool CreateParentFolder(const std::filesystem::path& path) {
return true; return true;
} }
std::error_code CreateFolder(const std::filesystem::path& path) {
if (std::filesystem::exists(path)) {
return {};
}
std::error_code ec;
if (std::filesystem::create_directories(path, ec)) {
return {};
}
return ec;
}
std::vector<FileInfo> ListDirectories(const std::filesystem::path& path) {
std::vector<FileInfo> files = ListFiles(path);
std::vector<FileInfo> directories = {};
std::copy_if(files.cbegin(), files.cend(), std::back_inserter(directories),
[](const FileInfo& file) {
return file.type == FileInfo::Type::kDirectory;
});
return std::move(directories);
}
std::vector<FileInfo> FilterByName(const std::vector<FileInfo>& files,
const std::regex pattern) {
std::vector<FileInfo> filtered_entries = {};
std::copy_if(
files.cbegin(), files.cend(), std::back_inserter(filtered_entries),
[pattern](const FileInfo& file) {
return std::regex_match(file.name.filename().string(), pattern);
});
return std::move(filtered_entries);
}
} // namespace filesystem } // namespace filesystem
} // namespace xe } // namespace xe

View File

@ -45,6 +45,10 @@ std::filesystem::path GetUserFolder();
// attempting to create it. // attempting to create it.
bool CreateParentFolder(const std::filesystem::path& path); bool CreateParentFolder(const std::filesystem::path& path);
// Creates folder on specified path.
// If folder already exists it returns success (no error).
std::error_code CreateFolder(const std::filesystem::path& path);
// Creates an empty file at the given path, overwriting if it exists. // Creates an empty file at the given path, overwriting if it exists.
bool CreateEmptyFile(const std::filesystem::path& path); bool CreateEmptyFile(const std::filesystem::path& path);
@ -65,14 +69,14 @@ bool TruncateStdioFile(FILE* file, uint64_t length);
struct FileAccess { struct FileAccess {
// Implies kFileReadData. // Implies kFileReadData.
static const uint32_t kGenericRead = 0x80000000; static constexpr uint32_t kGenericRead = 0x80000000;
// Implies kFileWriteData. // Implies kFileWriteData.
static const uint32_t kGenericWrite = 0x40000000; static constexpr uint32_t kGenericWrite = 0x40000000;
static const uint32_t kGenericExecute = 0x20000000; static constexpr uint32_t kGenericExecute = 0x20000000;
static const uint32_t kGenericAll = 0x10000000; static constexpr uint32_t kGenericAll = 0x10000000;
static const uint32_t kFileReadData = 0x00000001; static constexpr uint32_t kFileReadData = 0x00000001;
static const uint32_t kFileWriteData = 0x00000002; static constexpr uint32_t kFileWriteData = 0x00000002;
static const uint32_t kFileAppendData = 0x00000004; static constexpr uint32_t kFileAppendData = 0x00000004;
}; };
class FileHandle { class FileHandle {

View File

@ -214,7 +214,7 @@ bool IsAndroidContentUri(const std::string_view source) {
// still including // in the comparison to distinguish from a file with a name // still including // in the comparison to distinguish from a file with a name
// starting from content: (as this is the main purpose of this code - // starting from content: (as this is the main purpose of this code -
// separating URIs from file paths) more clearly. // separating URIs from file paths) more clearly.
static const char kContentSchema[] = "content://"; static constexpr char kContentSchema[] = "content://";
constexpr size_t kContentSchemaLength = xe::countof(kContentSchema) - 1; constexpr size_t kContentSchemaLength = xe::countof(kContentSchema) - 1;
return source.size() >= kContentSchemaLength && return source.size() >= kContentSchemaLength &&
!xe_strncasecmp(source.data(), kContentSchema, kContentSchemaLength); !xe_strncasecmp(source.data(), kContentSchema, kContentSchemaLength);

View File

@ -16,14 +16,12 @@
#include <dirent.h> #include <dirent.h>
#include <fcntl.h> #include <fcntl.h>
#include <ftw.h> #include <ftw.h>
#include <libgen.h>
#include <pwd.h> #include <pwd.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#include <iostream>
namespace xe { namespace xe {
@ -192,20 +190,26 @@ std::unique_ptr<FileHandle> FileHandle::OpenExisting(
return std::make_unique<PosixFileHandle>(path, handle); return std::make_unique<PosixFileHandle>(path, handle);
} }
bool GetInfo(const std::filesystem::path& path, FileInfo* out_info) { std::optional<FileInfo> GetInfo(const std::filesystem::path& path) {
FileInfo info{};
struct stat st; struct stat st;
if (stat(path.c_str(), &st) == 0) { if (stat(path.c_str(), &st) == 0) {
if (S_ISDIR(st.st_mode)) { if (S_ISDIR(st.st_mode)) {
out_info->type = FileInfo::Type::kDirectory; info.type = FileInfo::Type::kDirectory;
// On Linux st.st_size can have non-zero size (generally 4096) so make 0
info.total_size = 0;
} else { } else {
out_info->type = FileInfo::Type::kFile; info.type = FileInfo::Type::kFile;
info.total_size = st.st_size;
} }
out_info->create_timestamp = convertUnixtimeToWinFiletime(st.st_ctime); info.path = path.parent_path();
out_info->access_timestamp = convertUnixtimeToWinFiletime(st.st_atime); info.name = path.filename();
out_info->write_timestamp = convertUnixtimeToWinFiletime(st.st_mtime); info.create_timestamp = convertUnixtimeToWinFiletime(st.st_ctime);
return true; info.access_timestamp = convertUnixtimeToWinFiletime(st.st_atime);
info.write_timestamp = convertUnixtimeToWinFiletime(st.st_mtime);
return std::move(info);
} }
return false; return {};
} }
std::vector<FileInfo> ListFiles(const std::filesystem::path& path) { std::vector<FileInfo> ListFiles(const std::filesystem::path& path) {
@ -240,7 +244,7 @@ std::vector<FileInfo> ListFiles(const std::filesystem::path& path) {
result.push_back(info); result.push_back(info);
} }
closedir(dir); closedir(dir);
return result; return std::move(result);
} }
bool SetAttributes(const std::filesystem::path& path, uint64_t attributes) { bool SetAttributes(const std::filesystem::path& path, uint64_t attributes) {

View File

@ -9,8 +9,6 @@
#include "xenia/base/filesystem_wildcard.h" #include "xenia/base/filesystem_wildcard.h"
#include <algorithm>
#include "xenia/base/assert.h" #include "xenia/base/assert.h"
#include "xenia/base/string.h" #include "xenia/base/string.h"

View File

@ -263,30 +263,6 @@ std::vector<FileInfo> ListFiles(const std::filesystem::path& path) {
return result; return result;
} }
std::vector<FileInfo> ListDirectories(const std::filesystem::path& path) {
std::vector<FileInfo> files = ListFiles(path);
std::vector<FileInfo> directories = {};
std::copy_if(
files.cbegin(), files.cend(), std::back_inserter(directories),
[](FileInfo file) { return file.type == FileInfo::Type::kDirectory; });
return directories;
}
std::vector<FileInfo> FilterByName(const std::vector<FileInfo>& files,
const std::regex pattern) {
std::vector<FileInfo> filtered_entries = {};
std::copy_if(files.cbegin(), files.cend(),
std::back_inserter(filtered_entries), [pattern](FileInfo file) {
return std::regex_match(file.name.filename().string(),
pattern);
});
return filtered_entries;
}
bool SetAttributes(const std::filesystem::path& path, uint64_t attributes) { bool SetAttributes(const std::filesystem::path& path, uint64_t attributes) {
return SetFileAttributes(path.c_str(), static_cast<DWORD>(attributes)); return SetFileAttributes(path.c_str(), static_cast<DWORD>(attributes));
} }

View File

@ -11,7 +11,6 @@
#include <cctype> #include <cctype>
#include <cstring> #include <cstring>
#include <iostream>
// TODO(gibbed): UTF8 support. // TODO(gibbed): UTF8 support.

View File

@ -14,23 +14,23 @@
namespace xe::literals { namespace xe::literals {
constexpr size_t operator""_KiB(unsigned long long int x) { constexpr size_t operator""_KiB(const unsigned long long int x) {
return 1024ULL * x; return 1024ULL * x;
} }
constexpr size_t operator""_MiB(unsigned long long int x) { constexpr size_t operator""_MiB(const unsigned long long int x) {
return 1024_KiB * x; return 1024_KiB * x;
} }
constexpr size_t operator""_GiB(unsigned long long int x) { constexpr size_t operator""_GiB(const unsigned long long int x) {
return 1024_MiB * x; return 1024_MiB * x;
} }
constexpr size_t operator""_TiB(unsigned long long int x) { constexpr size_t operator""_TiB(const unsigned long long int x) {
return 1024_GiB * x; return 1024_GiB * x;
} }
constexpr size_t operator""_PiB(unsigned long long int x) { constexpr size_t operator""_PiB(const unsigned long long int x) {
return 1024_TiB * x; return 1024_TiB * x;
} }

View File

@ -10,11 +10,8 @@
#include "xenia/base/logging.h" #include "xenia/base/logging.h"
#include <algorithm> #include <algorithm>
#include <atomic>
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include <mutex>
#include <vector>
#include "third_party/disruptorplus/include/disruptorplus/multi_threaded_claim_strategy.hpp" #include "third_party/disruptorplus/include/disruptorplus/multi_threaded_claim_strategy.hpp"
#include "third_party/disruptorplus/include/disruptorplus/ring_buffer.hpp" #include "third_party/disruptorplus/include/disruptorplus/ring_buffer.hpp"
@ -244,12 +241,12 @@ class Logger {
} }
private: private:
static const size_t kBufferSize = 8_MiB; static constexpr size_t kBufferSize = 8_MiB;
uint8_t buffer_[kBufferSize]; uint8_t buffer_[kBufferSize];
static const size_t kBlockSize = 256; static constexpr size_t kBlockSize = 256;
static const size_t kBlockCount = kBufferSize / kBlockSize; static constexpr size_t kBlockCount = kBufferSize / kBlockSize;
static const size_t kBlockIndexMask = kBlockCount - 1; static constexpr size_t kBlockIndexMask = kBlockCount - 1;
static const size_t kClaimStrategyFootprint = static const size_t kClaimStrategyFootprint =
sizeof(std::atomic<dp::sequence_t>[kBlockCount]); sizeof(std::atomic<dp::sequence_t>[kBlockCount]);
@ -353,14 +350,14 @@ class Logger {
? line_range.second[line_range.second_length - 1] ? line_range.second[line_range.second_length - 1]
: line_range.first[line_range.first_length - 1]; : line_range.first[line_range.first_length - 1];
if (last_char != '\n') { if (last_char != '\n') {
const char suffix[1] = {'\n'}; constexpr char suffix[1] = {'\n'};
Write(suffix, 1); Write(suffix, 1);
} }
rb.EndRead(std::move(line_range)); rb.EndRead(std::move(line_range));
} else { } else {
// Always ensure there is a newline. // Always ensure there is a newline.
const char suffix[1] = {'\n'}; constexpr char suffix[1] = {'\n'};
Write(suffix, 1); Write(suffix, 1);
} }

View File

@ -0,0 +1,46 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2023 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include <gdk/gdk.h>
#include <gtk/gtk.h>
#include <xbyak/xbyak/xbyak_util.h>
#include "xenia/ui/window_gtk.h"
class StartupCpuFeatureCheck {
public:
StartupCpuFeatureCheck() {
Xbyak::util::Cpu cpu;
const char* error_message = nullptr;
if (!cpu.has(Xbyak::util::Cpu::tAVX)) {
error_message =
"Your CPU does not support AVX, which is required by Xenia. See "
"the "
"FAQ for system requirements at https://xenia.jp";
}
if (error_message == nullptr) {
return;
} else {
GtkDialogFlags flags = GTK_DIALOG_DESTROY_WITH_PARENT;
auto dialog =
gtk_message_dialog_new(nullptr, flags, GTK_MESSAGE_ERROR,
GTK_BUTTONS_CLOSE, "%s", error_message);
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
exit(1);
}
}
};
// This is a hack to get an instance of StartupAvxCheck
// constructed before any initialization code,
// where the AVX check then happens in the constructor.
// Ref:
// https://reviews.llvm.org/D12689#243295
__attribute__((
init_priority(101))) static StartupCpuFeatureCheck gStartupAvxCheck;

View File

@ -43,4 +43,4 @@ class StartupCpuFeatureCheck {
// https://docs.microsoft.com/en-us/cpp/preprocessor/init-seg // https://docs.microsoft.com/en-us/cpp/preprocessor/init-seg
#pragma warning(suppress : 4073) #pragma warning(suppress : 4073)
#pragma init_seg(lib) #pragma init_seg(lib)
static StartupCpuFeatureCheck gStartupAvxCheck; static StartupCpuFeatureCheck gStartupAvxCheck;

View File

@ -7,7 +7,6 @@
****************************************************************************** ******************************************************************************
*/ */
#include <malloc.h>
#include <cstring> #include <cstring>
#include "xenia/base/cvar.h" #include "xenia/base/cvar.h"
@ -60,7 +59,7 @@ static void RequestWin32HighResolutionTimer() {
ULONG minimum_resolution, maximum_resolution, current_resolution; ULONG minimum_resolution, maximum_resolution, current_resolution;
nt_query_timer_resolution(&minimum_resolution, &maximum_resolution, nt_query_timer_resolution(&minimum_resolution, &maximum_resolution,
&current_resolution); &current_resolution);
nt_set_timer_resolution(maximum_resolution, TRUE, &current_resolution); nt_set_timer_resolution(maximum_resolution, true, &current_resolution);
} }
static void RequestWin32MMCSS() { static void RequestWin32MMCSS() {
@ -74,7 +73,7 @@ static void RequestWin32MMCSS() {
dwm_enable_mmcss = reinterpret_cast<decltype(dwm_enable_mmcss)>( dwm_enable_mmcss = reinterpret_cast<decltype(dwm_enable_mmcss)>(
GetProcAddress(dwmapi_module, "DwmEnableMMCSS")); GetProcAddress(dwmapi_module, "DwmEnableMMCSS"));
if (dwm_enable_mmcss) { if (dwm_enable_mmcss) {
dwm_enable_mmcss(TRUE); dwm_enable_mmcss(true);
} }
FreeLibrary(dwmapi_module); FreeLibrary(dwmapi_module);
} }

View File

@ -7,9 +7,7 @@
****************************************************************************** ******************************************************************************
*/ */
#include <memory>
#include <mutex> #include <mutex>
#include <vector>
#include "third_party/fmt/include/fmt/format.h" #include "third_party/fmt/include/fmt/format.h"
#include "xenia/base/logging.h" #include "xenia/base/logging.h"
@ -29,7 +27,7 @@ class Win32MappedMemory : public MappedMemory {
public: public:
// CreateFile returns INVALID_HANDLE_VALUE in case of failure. // CreateFile returns INVALID_HANDLE_VALUE in case of failure.
// chrispy: made inline const to get around clang error // chrispy: made inline const to get around clang error
static inline const HANDLE kFileHandleInvalid = INVALID_HANDLE_VALUE; static inline constexpr HANDLE kFileHandleInvalid = INVALID_HANDLE_VALUE;
// CreateFileMapping returns nullptr in case of failure. // CreateFileMapping returns nullptr in case of failure.
static constexpr HANDLE kMappingHandleInvalid = nullptr; static constexpr HANDLE kMappingHandleInvalid = nullptr;

View File

@ -629,7 +629,7 @@ static constexpr uint32_t PregenerateUint32Div(uint32_t _denom,
int s; int s;
} magu{}; } magu{};
magu.a = 0; magu.a = 0;
nc = -1 - ((uint32_t) - (int32_t)d) % d; nc = -1 - ((uint32_t)-(int32_t)d) % d;
p = 31; p = 31;
q1 = 0x80000000 / nc; q1 = 0x80000000 / nc;
r1 = 0x80000000 - q1 * nc; r1 = 0x80000000 - q1 * nc;

View File

@ -16,8 +16,6 @@
#include <arm_neon.h> #include <arm_neon.h>
#endif #endif
#include <algorithm>
DEFINE_bool( DEFINE_bool(
writable_executable_memory, true, writable_executable_memory, true,
"Allow mapping memory with both write and execute access, for simulating " "Allow mapping memory with both write and execute access, for simulating "
@ -473,7 +471,7 @@ void copy_and_swap_16_unaligned(void* dst_ptr, const void* src_ptr,
auto dst = reinterpret_cast<uint8_t*>(dst_ptr); auto dst = reinterpret_cast<uint8_t*>(dst_ptr);
auto src = reinterpret_cast<const uint8_t*>(src_ptr); auto src = reinterpret_cast<const uint8_t*>(src_ptr);
const uint8x16_t tbl_idx = constexpr uint8x16_t tbl_idx =
vcombine_u8(vcreate_u8(UINT64_C(0x0607040502030001)), vcombine_u8(vcreate_u8(UINT64_C(0x0607040502030001)),
vcreate_u8(UINT64_C(0x0E0F0C0D0A0B0809))); vcreate_u8(UINT64_C(0x0E0F0C0D0A0B0809)));
@ -507,7 +505,7 @@ void copy_and_swap_32_unaligned(void* dst_ptr, const void* src_ptr,
auto dst = reinterpret_cast<uint8_t*>(dst_ptr); auto dst = reinterpret_cast<uint8_t*>(dst_ptr);
auto src = reinterpret_cast<const uint8_t*>(src_ptr); auto src = reinterpret_cast<const uint8_t*>(src_ptr);
const uint8x16_t tbl_idx = constexpr uint8x16_t tbl_idx =
vcombine_u8(vcreate_u8(UINT64_C(0x405060700010203)), vcombine_u8(vcreate_u8(UINT64_C(0x405060700010203)),
vcreate_u8(UINT64_C(0x0C0D0E0F08090A0B))); vcreate_u8(UINT64_C(0x0C0D0E0F08090A0B)));
@ -539,7 +537,7 @@ void copy_and_swap_64_unaligned(void* dst_ptr, const void* src_ptr,
auto dst = reinterpret_cast<uint8_t*>(dst_ptr); auto dst = reinterpret_cast<uint8_t*>(dst_ptr);
auto src = reinterpret_cast<const uint8_t*>(src_ptr); auto src = reinterpret_cast<const uint8_t*>(src_ptr);
const uint8x16_t tbl_idx = constexpr uint8x16_t tbl_idx =
vcombine_u8(vcreate_u8(UINT64_C(0x0001020304050607)), vcombine_u8(vcreate_u8(UINT64_C(0x0001020304050607)),
vcreate_u8(UINT64_C(0x08090A0B0C0D0E0F))); vcreate_u8(UINT64_C(0x08090A0B0C0D0E0F)));

View File

@ -813,12 +813,12 @@ template <unsigned Size>
static void smallset_const(void* destination, unsigned char fill_value) { static void smallset_const(void* destination, unsigned char fill_value) {
#if XE_ARCH_AMD64 == 1 && XE_COMPILER_MSVC == 1 #if XE_ARCH_AMD64 == 1 && XE_COMPILER_MSVC == 1
if constexpr ((Size & 7) == 0) { if constexpr ((Size & 7) == 0) {
unsigned long long fill = static unsigned long long fill =
static_cast<unsigned long long>(fill_value) * 0x0101010101010101ULL; static_cast<unsigned long long>(fill_value) * 0x0101010101010101ULL;
__stosq((unsigned long long*)destination, fill, Size / 8); __stosq((unsigned long long*)destination, fill, Size / 8);
} else if constexpr ((Size & 3) == 0) { } else if constexpr ((Size & 3) == 0) {
static constexpr unsigned long fill = static unsigned long fill =
static_cast<unsigned long>(fill_value) * 0x01010101U; static_cast<unsigned long>(fill_value) * 0x01010101U;
__stosd((unsigned long*)destination, fill, Size / 4); __stosd((unsigned long*)destination, fill, Size / 4);
// dont even bother with movsw, i think the operand size override prefix // dont even bother with movsw, i think the operand size override prefix

View File

@ -13,6 +13,9 @@
#include <sys/mman.h> #include <sys/mman.h>
#include <unistd.h> #include <unistd.h>
#include <cstddef> #include <cstddef>
#include <fstream>
#include <mutex>
#include <sstream>
#include "xenia/base/math.h" #include "xenia/base/math.h"
#include "xenia/base/platform.h" #include "xenia/base/platform.h"
@ -79,19 +82,50 @@ uint32_t ToPosixProtectFlags(PageAccess access) {
} }
} }
PageAccess ToXeniaProtectFlags(const char* protection) {
if (protection[0] == 'r' && protection[1] == 'w' && protection[2] == 'x') {
return PageAccess::kExecuteReadWrite;
}
if (protection[0] == 'r' && protection[1] == '-' && protection[2] == 'x') {
return PageAccess::kExecuteReadOnly;
}
if (protection[0] == 'r' && protection[1] == 'w' && protection[2] == '-') {
return PageAccess::kReadWrite;
}
if (protection[0] == 'r' && protection[1] == '-' && protection[2] == '-') {
return PageAccess::kReadOnly;
}
return PageAccess::kNoAccess;
}
bool IsWritableExecutableMemorySupported() { return true; } bool IsWritableExecutableMemorySupported() { return true; }
struct MappedFileRange {
uintptr_t region_begin;
uintptr_t region_end;
};
std::vector<MappedFileRange> mapped_file_ranges;
std::mutex g_mapped_file_ranges_mutex;
void* AllocFixed(void* base_address, size_t length, void* AllocFixed(void* base_address, size_t length,
AllocationType allocation_type, PageAccess access) { AllocationType allocation_type, PageAccess access) {
// mmap does not support reserve / commit, so ignore allocation_type. // mmap does not support reserve / commit, so ignore allocation_type.
uint32_t prot = ToPosixProtectFlags(access); uint32_t prot = ToPosixProtectFlags(access);
int flags = 0; int flags = MAP_PRIVATE | MAP_ANONYMOUS;
if (base_address != nullptr) { if (base_address != nullptr) {
flags = MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS; if (allocation_type == AllocationType::kCommit) {
} else { if (Protect(base_address, length, access)) {
flags = MAP_PRIVATE | MAP_ANONYMOUS; return base_address;
}
return nullptr;
}
flags |= MAP_FIXED_NOREPLACE;
} }
void* result = mmap(base_address, length, prot, flags, -1, 0); void* result = mmap(base_address, length, prot, flags, -1, 0);
if (result != MAP_FAILED) { if (result != MAP_FAILED) {
return result; return result;
} }
@ -100,19 +134,90 @@ void* AllocFixed(void* base_address, size_t length,
bool DeallocFixed(void* base_address, size_t length, bool DeallocFixed(void* base_address, size_t length,
DeallocationType deallocation_type) { DeallocationType deallocation_type) {
return munmap(base_address, length) == 0; const auto region_begin = reinterpret_cast<uintptr_t>(base_address);
const uintptr_t region_end =
reinterpret_cast<uintptr_t>(base_address) + length;
std::lock_guard guard(g_mapped_file_ranges_mutex);
for (const auto& mapped_range : mapped_file_ranges) {
if (region_begin >= mapped_range.region_begin &&
region_end <= mapped_range.region_end) {
switch (deallocation_type) {
case DeallocationType::kDecommit:
return Protect(base_address, length, PageAccess::kNoAccess);
case DeallocationType::kRelease:
assert_always("Error: Tried to release mapped memory!");
default:
assert_unhandled_case(deallocation_type);
}
}
}
switch (deallocation_type) {
case DeallocationType::kDecommit:
return Protect(base_address, length, PageAccess::kNoAccess);
case DeallocationType::kRelease:
return munmap(base_address, length) == 0;
default:
assert_unhandled_case(deallocation_type);
}
} }
bool Protect(void* base_address, size_t length, PageAccess access, bool Protect(void* base_address, size_t length, PageAccess access,
PageAccess* out_old_access) { PageAccess* out_old_access) {
// Linux does not have a syscall to query memory permissions. if (out_old_access) {
assert_null(out_old_access); size_t length_copy = length;
QueryProtect(base_address, length_copy, *out_old_access);
}
uint32_t prot = ToPosixProtectFlags(access); uint32_t prot = ToPosixProtectFlags(access);
return mprotect(base_address, length, prot) == 0; return mprotect(base_address, length, prot) == 0;
} }
bool QueryProtect(void* base_address, size_t& length, PageAccess& access_out) { bool QueryProtect(void* base_address, size_t& length, PageAccess& access_out) {
// No generic POSIX solution exists. The Linux solution should work on all
// Linux kernel based OS, including Android.
std::ifstream memory_maps;
memory_maps.open("/proc/self/maps", std::ios_base::in);
std::string maps_entry_string;
while (std::getline(memory_maps, maps_entry_string)) {
std::stringstream entry_stream(maps_entry_string);
uintptr_t map_region_begin, map_region_end;
char separator, protection[4];
entry_stream >> std::hex >> map_region_begin >> separator >>
map_region_end >> protection;
if (map_region_begin <= reinterpret_cast<uintptr_t>(base_address) &&
map_region_end > reinterpret_cast<uintptr_t>(base_address)) {
length = map_region_end - reinterpret_cast<uintptr_t>(base_address);
access_out = ToXeniaProtectFlags(protection);
// Look at the next consecutive mappings
while (std::getline(memory_maps, maps_entry_string)) {
std::stringstream next_entry_stream(maps_entry_string);
uintptr_t next_map_region_begin, next_map_region_end;
char next_protection[4];
next_entry_stream >> std::hex >> next_map_region_begin >> separator >>
next_map_region_end >> next_protection;
if (map_region_end == next_map_region_begin &&
access_out == ToXeniaProtectFlags(next_protection)) {
length =
next_map_region_end - reinterpret_cast<uintptr_t>(base_address);
continue;
}
break;
}
memory_maps.close();
return true;
}
}
memory_maps.close();
return false; return false;
} }
@ -182,12 +287,41 @@ void CloseFileMappingHandle(FileMappingHandle handle,
void* MapFileView(FileMappingHandle handle, void* base_address, size_t length, void* MapFileView(FileMappingHandle handle, void* base_address, size_t length,
PageAccess access, size_t file_offset) { PageAccess access, size_t file_offset) {
uint32_t prot = ToPosixProtectFlags(access); uint32_t prot = ToPosixProtectFlags(access);
return mmap64(base_address, length, prot, MAP_PRIVATE | MAP_ANONYMOUS, handle,
file_offset); int flags = MAP_SHARED;
if (base_address != nullptr) {
flags |= MAP_FIXED_NOREPLACE;
}
void* result = mmap(base_address, length, prot, flags, handle, file_offset);
if (result != MAP_FAILED) {
std::lock_guard guard(g_mapped_file_ranges_mutex);
mapped_file_ranges.push_back(
{reinterpret_cast<uintptr_t>(result),
reinterpret_cast<uintptr_t>(result) + length});
return result;
}
return nullptr;
} }
bool UnmapFileView(FileMappingHandle handle, void* base_address, bool UnmapFileView(FileMappingHandle handle, void* base_address,
size_t length) { size_t length) {
std::lock_guard guard(g_mapped_file_ranges_mutex);
for (auto mapped_range = mapped_file_ranges.begin();
mapped_range != mapped_file_ranges.end();) {
if (mapped_range->region_begin ==
reinterpret_cast<uintptr_t>(base_address) &&
mapped_range->region_end ==
reinterpret_cast<uintptr_t>(base_address) + length) {
mapped_file_ranges.erase(mapped_range);
return munmap(base_address, length) == 0;
}
++mapped_range;
}
// TODO: Implement partial file unmapping.
assert_always("Error: Partial unmapping of files not yet supported.");
return munmap(base_address, length) == 0; return munmap(base_address, length) == 0;
} }

193
src/xenia/base/pe_image.h Normal file
View File

@ -0,0 +1,193 @@
/* Xenia: minor tweaks to bring up to date with winnt.h */
#include <cstdint>
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* NT image format (to be used when the Win32 SDK version of WINNT.H cannot) */
#define XIMAGE_DOS_SIGNATURE 0x5A4D /* MZ */
#define XIMAGE_OS2_SIGNATURE 0x454E /* NE */
#define XIMAGE_OS2_SIGNATURE_LE 0x454C /* LE */
#define XIMAGE_NT_SIGNATURE 0x00004550 /* PE00 */
typedef struct _XIMAGE_DOS_HEADER { /* DOS .EXE header */
uint16_t e_magic; /* Magic number */
uint16_t e_cblp; /* Bytes on last page of file */
uint16_t e_cp; /* Pages in file */
uint16_t e_crlc; /* Relocations */
uint16_t e_cparhdr; /* Size of header in paragraphs */
uint16_t e_minalloc; /* Minimum extra paragraphs needed */
uint16_t e_maxalloc; /* Maximum extra paragraphs needed */
uint16_t e_ss; /* Initial (relative) SS value */
uint16_t e_sp; /* Initial SP value */
uint16_t e_csum; /* Checksum */
uint16_t e_ip; /* Initial IP value */
uint16_t e_cs; /* Initial (relative) CS value */
uint16_t e_lfarlc; /* File address of relocation table */
uint16_t e_ovno; /* Overlay number */
uint16_t e_res[4]; /* Reserved words */
uint16_t e_oemid; /* OEM identifier (for e_oeminfo) */
uint16_t e_oeminfo; /* OEM information; e_oemid specific */
uint16_t e_res2[10]; /* Reserved words */
int32_t e_lfanew; /* File address of new exe header */
} XIMAGE_DOS_HEADER, *PXIMAGE_DOS_HEADER;
typedef struct _XIMAGE_OS2_HEADER { /* OS/2 .EXE header */
uint16_t ne_magic; /* Magic number */
int8_t ne_ver; /* Version number */
int8_t ne_rev; /* Revision number */
uint16_t ne_enttab; /* Offset of Entry Table */
uint16_t ne_cbenttab; /* Number of bytes in Entry Table */
int32_t ne_crc; /* Checksum of whole file */
uint16_t ne_flags; /* Flag word */
uint16_t ne_autodata; /* Automatic data segment number */
uint16_t ne_heap; /* Initial heap allocation */
uint16_t ne_stack; /* Initial stack allocation */
int32_t ne_csip; /* Initial CS:IP setting */
int32_t ne_sssp; /* Initial SS:SP setting */
uint16_t ne_cseg; /* Count of file segments */
uint16_t ne_cmod; /* Entries in Module Reference Table */
uint16_t ne_cbnrestab; /* Size of non-resident name table */
uint16_t ne_segtab; /* Offset of Segment Table */
uint16_t ne_rsrctab; /* Offset of Resource Table */
uint16_t ne_restab; /* Offset of resident name table */
uint16_t ne_modtab; /* Offset of Module Reference Table */
uint16_t ne_imptab; /* Offset of Imported Names Table */
int32_t ne_nrestab; /* Offset of Non-resident Names Table */
uint16_t ne_cmovent; /* Count of movable entries */
uint16_t ne_align; /* Segment alignment shift count */
uint16_t ne_cres; /* Count of resource segments */
uint8_t ne_exetyp; /* Target Operating system */
uint8_t ne_flagsothers; /* Other .EXE flags */
uint16_t ne_pretthunks; /* offset to return thunks */
uint16_t ne_psegrefbytes; /* offset to segment ref. bytes */
uint16_t ne_swaparea; /* Minimum code swap area size */
uint16_t ne_expver; /* Expected Windows version number */
} XIMAGE_OS2_HEADER, *PXIMAGE_OS2_HEADER;
typedef struct _XIMAGE_FILE_HEADER {
uint16_t Machine;
uint16_t NumberOfSections;
uint32_t TimeDateStamp;
uint32_t PointerToSymbolTable;
uint32_t NumberOfSymbols;
uint16_t SizeOfOptionalHeader;
uint16_t Characteristics;
} XIMAGE_FILE_HEADER, *PXIMAGE_FILE_HEADER;
#define XIMAGE_FILE_32BIT_MACHINE 0x0100 /* 32 bit word machine. */
#define XIMAGE_FILE_MACHINE_POWERPCBE 0x01F2 // IBM PowerPC Big-Endian
typedef struct _XIMAGE_DATA_DIRECTORY {
uint32_t VirtualAddress;
uint32_t Size;
} XIMAGE_DATA_DIRECTORY, *PXIMAGE_DATA_DIRECTORY;
#define XIMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
/*
* Optional header format.
*/
typedef struct _XIMAGE_OPTIONAL_HEADER {
/*
* Standard fields.
*/
uint16_t Magic;
uint8_t MajorLinkerVersion;
uint8_t MinorLinkerVersion;
uint32_t SizeOfCode;
uint32_t SizeOfInitializedData;
uint32_t SizeOfUninitializedData;
uint32_t AddressOfEntryPoint;
uint32_t BaseOfCode;
uint32_t BaseOfData;
/*
* NT additional fields.
*/
uint32_t ImageBase;
uint32_t SectionAlignment;
uint32_t FileAlignment;
uint16_t MajorOperatingSystemVersion;
uint16_t MinorOperatingSystemVersion;
uint16_t MajorImageVersion;
uint16_t MinorImageVersion;
uint16_t MajorSubsystemVersion;
uint16_t MinorSubsystemVersion;
uint32_t Reserved1;
uint32_t SizeOfImage;
uint32_t SizeOfHeaders;
uint32_t CheckSum;
uint16_t Subsystem;
uint16_t DllCharacteristics;
uint32_t SizeOfStackReserve;
uint32_t SizeOfStackCommit;
uint32_t SizeOfHeapReserve;
uint32_t SizeOfHeapCommit;
uint32_t LoaderFlags;
uint32_t NumberOfRvaAndSizes;
XIMAGE_DATA_DIRECTORY DataDirectory[XIMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} XIMAGE_OPTIONAL_HEADER, *PXIMAGE_OPTIONAL_HEADER;
typedef XIMAGE_OPTIONAL_HEADER XIMAGE_OPTIONAL_HEADER32;
#define XIMAGE_SIZEOF_NT_OPTIONAL_HEADER 224
#define XIMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b
typedef struct _XIMAGE_NT_HEADERS {
uint32_t Signature;
XIMAGE_FILE_HEADER FileHeader;
XIMAGE_OPTIONAL_HEADER OptionalHeader;
} XIMAGE_NT_HEADERS, *PXIMAGE_NT_HEADERS;
typedef XIMAGE_NT_HEADERS XIMAGE_NT_HEADERS32;
#define XIMAGE_FIRST_SECTION(ntheader) \
((PXIMAGE_SECTION_HEADER)((uint8_t*)ntheader + \
offsetof(XIMAGE_NT_HEADERS, OptionalHeader) + \
((PXIMAGE_NT_HEADERS)(ntheader)) \
->FileHeader.SizeOfOptionalHeader))
#define XIMAGE_SUBSYSTEM_XBOX 14
/*
* Section header format.
*/
#define XIMAGE_SIZEOF_SHORT_NAME 8
typedef struct _XIMAGE_SECTION_HEADER {
uint8_t Name[XIMAGE_SIZEOF_SHORT_NAME];
union {
uint32_t PhysicalAddress;
uint32_t VirtualSize;
} Misc;
uint32_t VirtualAddress;
uint32_t SizeOfRawData;
uint32_t PointerToRawData;
uint32_t PointerToRelocations;
uint32_t PointerToLinenumbers;
uint16_t NumberOfRelocations;
uint16_t NumberOfLinenumbers;
uint32_t Characteristics;
} XIMAGE_SECTION_HEADER, *PXIMAGE_SECTION_HEADER;
#define XIMAGE_SIZEOF_SECTION_HEADER 40
typedef struct _XIMAGE_EXPORT_DIRECTORY {
uint32_t Characteristics;
uint32_t TimeDateStamp;
uint16_t MajorVersion;
uint16_t MinorVersion;
uint32_t Name;
uint32_t Base;
uint32_t NumberOfFunctions;
uint32_t NumberOfNames;
uint32_t** AddressOfFunctions;
uint32_t** AddressOfNames;
uint16_t** AddressOfNameOrdinals;
} XIMAGE_EXPORT_DIRECTORY, *PXIMAGE_EXPORT_DIRECTORY;

View File

@ -181,12 +181,12 @@
namespace xe { namespace xe {
#if XE_PLATFORM_WIN32 #if XE_PLATFORM_WIN32
const char kPathSeparator = '\\'; constexpr char kPathSeparator = '\\';
#else #else
const char kPathSeparator = '/'; constexpr char kPathSeparator = '/';
#endif // XE_PLATFORM_WIN32 #endif // XE_PLATFORM_WIN32
const char kGuestPathSeparator = '\\'; constexpr char kGuestPathSeparator = '\\';
} // namespace xe } // namespace xe
#if XE_ARCH_AMD64 == 1 #if XE_ARCH_AMD64 == 1

View File

@ -132,4 +132,4 @@ void InitFeatureFlags() {
g_did_initialize_feature_flags = true; g_did_initialize_feature_flags = true;
} }
} // namespace amd64 } // namespace amd64
} // namespace xe } // namespace xe

View File

@ -0,0 +1,68 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2025 Xenia Canary. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "xenia/base/png_utils.h"
#include "xenia/base/filesystem.h"
#include "third_party/stb/stb_image.h"
namespace xe {
bool IsFilePngImage(const std::filesystem::path& file_path) {
FILE* file = xe::filesystem::OpenFile(file_path, "rb");
if (!file) {
return false;
}
constexpr uint8_t magic_size = 4;
char magic[magic_size];
if (fread(&magic, 1, magic_size, file) != magic_size) {
return false;
}
fclose(file);
if (magic[1] != 'P' || magic[2] != 'N' || magic[3] != 'G') {
return false;
}
return true;
}
std::pair<uint16_t, uint16_t> GetImageResolution(
const std::filesystem::path& file_path) {
FILE* file = xe::filesystem::OpenFile(file_path, "rb");
if (!file) {
return {};
}
int width, height, channels;
if (!stbi_info_from_file(file, &width, &height, &channels)) {
return {};
}
fclose(file);
return {width, height};
}
std::vector<uint8_t> ReadPngFromFile(const std::filesystem::path& file_path) {
FILE* file = xe::filesystem::OpenFile(file_path, "rb");
if (!file) {
return {};
}
const auto file_size = std::filesystem::file_size(file_path);
std::vector<uint8_t> data(file_size);
fread(data.data(), 1, file_size, file);
fclose(file);
return data;
}
} // namespace xe

View File

@ -0,0 +1,27 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2025 Xenia Canary. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_BASE_PNG_UTILS_H_
#define XENIA_BASE_PNG_UTILS_H_
#include <filesystem>
#include <utility>
#include <vector>
namespace xe {
bool IsFilePngImage(const std::filesystem::path& file_path);
std::pair<uint16_t, uint16_t> GetImageResolution(
const std::filesystem::path& file_path);
std::vector<uint8_t> ReadPngFromFile(const std::filesystem::path& file_path);
} // namespace xe
#endif // XENIA_BASE_PNG_UTILS_H_

View File

@ -8,8 +8,6 @@ project("xenia-base")
links({ links({
"fmt", "fmt",
}) })
defines({
})
local_platform_files() local_platform_files()
removefiles({"console_app_main_*.cc"}) removefiles({"console_app_main_*.cc"})
removefiles({"main_init_*.cc"}) removefiles({"main_init_*.cc"})
@ -17,4 +15,6 @@ project("xenia-base")
"debug_visualizers.natvis", "debug_visualizers.natvis",
}) })
include("testing") if enableTests then
include("testing")
end

View File

@ -7,9 +7,6 @@
****************************************************************************** ******************************************************************************
*/ */
#include <algorithm>
#include <string>
// NOTE: this must be included before microprofile as macro expansion needs // NOTE: this must be included before microprofile as macro expansion needs
// XELOGI. // XELOGI.
#include "xenia/base/logging.h" #include "xenia/base/logging.h"

View File

@ -8,7 +8,6 @@
*/ */
#include "xenia/base/ring_buffer.h" #include "xenia/base/ring_buffer.h"
#include <algorithm>
#include <cstring> #include <cstring>
namespace xe { namespace xe {

View File

@ -36,4 +36,4 @@ struct SimpleFreelist {
} }
void Reset() { head_ = nullptr; } void Reset() { head_ = nullptr; }
}; };
} // namespace xe } // namespace xe

View File

@ -10,7 +10,6 @@
#include "xenia/base/socket.h" #include "xenia/base/socket.h"
#include <mutex> #include <mutex>
#include <thread>
#include "xenia/base/logging.h" #include "xenia/base/logging.h"
#include "xenia/base/platform_win.h" #include "xenia/base/platform_win.h"
@ -96,7 +95,7 @@ class Win32Socket : public Socket {
// Keepalive for a looong time, as we may be paused by the debugger/etc. // Keepalive for a looong time, as we may be paused by the debugger/etc.
struct tcp_keepalive alive; struct tcp_keepalive alive;
alive.onoff = TRUE; alive.onoff = true;
alive.keepalivetime = 7200000; alive.keepalivetime = 7200000;
alive.keepaliveinterval = 6000; alive.keepaliveinterval = 6000;
DWORD bytes_returned; DWORD bytes_returned;
@ -209,7 +208,7 @@ class Win32SocketServer : public SocketServer {
SOCKET socket = socket_; SOCKET socket = socket_;
socket_ = INVALID_SOCKET; socket_ = INVALID_SOCKET;
linger so_linger; linger so_linger;
so_linger.l_onoff = TRUE; so_linger.l_onoff = true;
so_linger.l_linger = 30; so_linger.l_linger = 30;
setsockopt(socket, SOL_SOCKET, SO_LINGER, setsockopt(socket, SOL_SOCKET, SO_LINGER,
reinterpret_cast<const char*>(&so_linger), sizeof(so_linger)); reinterpret_cast<const char*>(&so_linger), sizeof(so_linger));
@ -231,7 +230,7 @@ class Win32SocketServer : public SocketServer {
return false; return false;
} }
struct tcp_keepalive alive; struct tcp_keepalive alive;
alive.onoff = TRUE; alive.onoff = true;
alive.keepalivetime = 7200000; alive.keepalivetime = 7200000;
alive.keepaliveinterval = 6000; alive.keepaliveinterval = 6000;
DWORD bytes_returned; DWORD bytes_returned;

View File

@ -82,4 +82,4 @@ class split_map {
}; };
} // namespace xe } // namespace xe
#endif // XENIA_BASE_SPLIT_MAP_H_ #endif // XENIA_BASE_SPLIT_MAP_H_

View File

@ -10,8 +10,6 @@
#include "xenia/base/string.h" #include "xenia/base/string.h"
#include <string.h> #include <string.h>
#include <algorithm>
#include <locale>
#include "xenia/base/platform.h" #include "xenia/base/platform.h"
#if XE_PLATFORM_WIN32 #if XE_PLATFORM_WIN32
@ -22,7 +20,7 @@
#include <strings.h> #include <strings.h>
#endif // !XE_PLATFORM_WIN32 #endif // !XE_PLATFORM_WIN32
#define UTF_CPP_CPLUSPLUS 201703L #define UTF_CPP_CPLUSPLUS 202002L
#include "third_party/utfcpp/source/utf8.h" #include "third_party/utfcpp/source/utf8.h"
namespace utfcpp = utf8; namespace utfcpp = utf8;

View File

@ -9,7 +9,6 @@
#include "xenia/base/string_buffer.h" #include "xenia/base/string_buffer.h"
#include <algorithm>
#include <cstdarg> #include <cstdarg>
#include "xenia/base/assert.h" #include "xenia/base/assert.h"

View File

@ -10,6 +10,7 @@
#ifndef XENIA_BASE_STRING_KEY_H_ #ifndef XENIA_BASE_STRING_KEY_H_
#define XENIA_BASE_STRING_KEY_H_ #define XENIA_BASE_STRING_KEY_H_
#include <algorithm>
#include <string> #include <string>
#include <variant> #include <variant>
@ -58,6 +59,41 @@ struct string_key : internal::string_key_base {
}; };
}; };
struct string_key_insensitive : internal::string_key_base {
public:
explicit string_key_insensitive(const std::string_view value)
: string_key_base(value) {}
explicit string_key_insensitive(std::string value) : string_key_base(value) {}
static string_key_insensitive create(const std::string_view value) {
return string_key_insensitive(std::string(value));
}
static string_key_insensitive create(std::string value) {
return string_key_insensitive(value);
}
bool operator==(const string_key_insensitive& other) const {
return other.view().size() == view().size() &&
std::ranges::equal(
other.view(), view(), {},
[](char ch) {
return std::tolower(static_cast<unsigned char>(ch));
},
[](char ch) {
return std::tolower(static_cast<unsigned char>(ch));
});
}
size_t hash() const { return utf8::hash_fnv1a(view()); }
struct Hash {
size_t operator()(const string_key_insensitive& t) const {
return t.hash();
}
};
};
struct string_key_case : internal::string_key_base { struct string_key_case : internal::string_key_base {
public: public:
explicit string_key_case(const std::string_view value) explicit string_key_case(const std::string_view value)
@ -91,6 +127,13 @@ struct hash<xe::string_key> {
std::size_t operator()(const xe::string_key& t) const { return t.hash(); } std::size_t operator()(const xe::string_key& t) const { return t.hash(); }
}; };
template <>
struct hash<xe::string_key_insensitive> {
std::size_t operator()(const xe::string_key_insensitive& t) const {
return t.hash();
}
};
template <> template <>
struct hash<xe::string_key_case> { struct hash<xe::string_key_case> {
std::size_t operator()(const xe::string_key_case& t) const { std::size_t operator()(const xe::string_key_case& t) const {

View File

@ -16,6 +16,7 @@
#include <cstring> #include <cstring>
#include <regex> #include <regex>
#include <string> #include <string>
#include <variant>
#include "third_party/fmt/include/fmt/format.h" #include "third_party/fmt/include/fmt/format.h"
#include "xenia/base/assert.h" #include "xenia/base/assert.h"
@ -428,6 +429,28 @@ inline vec128_t from_string<vec128_t>(const std::string_view value,
return v; return v;
} }
inline std::u16string read_u16string_and_swap(const char16_t* string_ptr) {
std::u16string input_str = std::u16string(string_ptr);
std::u16string output_str = {};
output_str.resize(input_str.size() + 1);
copy_and_swap_truncating(output_str.data(), input_str, input_str.size() + 1);
return output_str;
}
inline size_t size_in_bytes(std::variant<std::string, std::u16string> string,
bool include_terminator = true) {
if (std::holds_alternative<std::string>(string)) {
return std::get<std::string>(string).size() + include_terminator;
} else if (std::holds_alternative<std::u16string>(string)) {
return (std::get<std::u16string>(string).size() + include_terminator) *
sizeof(char16_t);
} else {
assert_always();
}
return 0;
}
} // namespace string_util } // namespace string_util
} // namespace xe } // namespace xe

View File

@ -29,7 +29,11 @@ void LaunchWebBrowser(const std::string_view url) {
system(cmd.c_str()); system(cmd.c_str());
} }
void LaunchFileExplorer(const std::filesystem::path& path) { assert_always(); } void LaunchFileExplorer(const std::filesystem::path& path) {
auto cmd = std::string("xdg-open ");
cmd.append(path);
system(cmd.c_str());
}
void ShowSimpleMessageBox(SimpleMessageBoxType type, std::string_view message) { void ShowSimpleMessageBox(SimpleMessageBoxType type, std::string_view message) {
void* libsdl2 = dlopen("libSDL2.so", RTLD_LAZY | RTLD_LOCAL); void* libsdl2 = dlopen("libSDL2.so", RTLD_LAZY | RTLD_LOCAL);

View File

@ -65,8 +65,8 @@ bool SetProcessPriorityClass(const uint32_t priority_class) {
} }
bool IsUseNexusForGameBarEnabled() { bool IsUseNexusForGameBarEnabled() {
const LPCWSTR reg_path = L"SOFTWARE\\Microsoft\\GameBar"; constexpr LPCWSTR reg_path = L"SOFTWARE\\Microsoft\\GameBar";
const LPCWSTR key = L"UseNexusForGameBarEnabled"; constexpr LPCWSTR key = L"UseNexusForGameBarEnabled";
DWORD value = 0; DWORD value = 0;
DWORD dataSize = sizeof(value); DWORD dataSize = sizeof(value);

View File

@ -516,7 +516,7 @@ TEST_CASE("create_and_close_file_mapping", "Virtual Memory Mapping") {
TEST_CASE("map_view", "[virtual_memory_mapping]") { TEST_CASE("map_view", "[virtual_memory_mapping]") {
auto path = fmt::format("xenia_test_{}", Clock::QueryHostTickCount()); auto path = fmt::format("xenia_test_{}", Clock::QueryHostTickCount());
const size_t length = 0x100; constexpr size_t length = 0x100;
auto memory = xe::memory::CreateFileMappingHandle( auto memory = xe::memory::CreateFileMappingHandle(
path, length, xe::memory::PageAccess::kReadWrite, true); path, length, xe::memory::PageAccess::kReadWrite, true);
REQUIRE(memory != xe::memory::kFileMappingHandleInvalid); REQUIRE(memory != xe::memory::kFileMappingHandleInvalid);
@ -532,7 +532,7 @@ TEST_CASE("map_view", "[virtual_memory_mapping]") {
} }
TEST_CASE("read_write_view", "[virtual_memory_mapping]") { TEST_CASE("read_write_view", "[virtual_memory_mapping]") {
const size_t length = 0x100; constexpr size_t length = 0x100;
auto path = fmt::format("xenia_test_{}", Clock::QueryHostTickCount()); auto path = fmt::format("xenia_test_{}", Clock::QueryHostTickCount());
auto memory = xe::memory::CreateFileMappingHandle( auto memory = xe::memory::CreateFileMappingHandle(
path, length, xe::memory::PageAccess::kReadWrite, true); path, length, xe::memory::PageAccess::kReadWrite, true);

View File

@ -404,19 +404,19 @@ class Timer : public WaitHandle {
#if XE_PLATFORM_WIN32 #if XE_PLATFORM_WIN32
struct ThreadPriority { struct ThreadPriority {
static const int32_t kLowest = -2; static constexpr int32_t kLowest = -2;
static const int32_t kBelowNormal = -1; static constexpr int32_t kBelowNormal = -1;
static const int32_t kNormal = 0; static constexpr int32_t kNormal = 0;
static const int32_t kAboveNormal = 1; static constexpr int32_t kAboveNormal = 1;
static const int32_t kHighest = 2; static constexpr int32_t kHighest = 2;
}; };
#else #else
struct ThreadPriority { struct ThreadPriority {
static const int32_t kLowest = 1; static constexpr int32_t kLowest = 1;
static const int32_t kBelowNormal = 8; static constexpr int32_t kBelowNormal = 8;
static const int32_t kNormal = 16; static constexpr int32_t kNormal = 16;
static const int32_t kAboveNormal = 24; static constexpr int32_t kAboveNormal = 24;
static const int32_t kHighest = 32; static constexpr int32_t kHighest = 32;
}; };
#endif #endif

View File

@ -17,15 +17,11 @@
#include <pthread.h> #include <pthread.h>
#include <sched.h> #include <sched.h>
#include <signal.h> #include <signal.h>
#include <sys/eventfd.h>
#include <sys/syscall.h> #include <sys/syscall.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#include <array> #include <array>
#include <cstddef> #include <cstddef>
#include <ctime> #include <ctime>
#include <memory>
#include "logging.h" #include "logging.h"
@ -82,8 +78,7 @@ void AndroidShutdown() {
#endif #endif
template <typename _Rep, typename _Period> template <typename _Rep, typename _Period>
inline timespec DurationToTimeSpec( timespec DurationToTimeSpec(std::chrono::duration<_Rep, _Period> duration) {
std::chrono::duration<_Rep, _Period> duration) {
auto nanoseconds = auto nanoseconds =
std::chrono::duration_cast<std::chrono::nanoseconds>(duration); std::chrono::duration_cast<std::chrono::nanoseconds>(duration);
auto div = ldiv(nanoseconds.count(), 1000000000L); auto div = ldiv(nanoseconds.count(), 1000000000L);
@ -123,7 +118,7 @@ static void signal_handler(int signal, siginfo_t* info, void* context);
void install_signal_handler(SignalType type) { void install_signal_handler(SignalType type) {
if (signal_handler_installed[static_cast<size_t>(type)]) return; if (signal_handler_installed[static_cast<size_t>(type)]) return;
struct sigaction action {}; struct sigaction action{};
action.sa_flags = SA_SIGINFO; action.sa_flags = SA_SIGINFO;
action.sa_sigaction = signal_handler; action.sa_sigaction = signal_handler;
sigemptyset(&action.sa_mask); sigemptyset(&action.sa_mask);
@ -161,6 +156,8 @@ void Sleep(std::chrono::microseconds duration) {
} while (ret == -1 && errno == EINTR); } while (ret == -1 && errno == EINTR);
} }
void NanoSleep(int64_t duration) { Sleep(std::chrono::nanoseconds(duration)); }
// TODO(bwrsandman) Implement by allowing alert interrupts from IO operations // TODO(bwrsandman) Implement by allowing alert interrupts from IO operations
thread_local bool alertable_state_ = false; thread_local bool alertable_state_ = false;
SleepResult AlertableSleep(std::chrono::microseconds duration) { SleepResult AlertableSleep(std::chrono::microseconds duration) {
@ -178,28 +175,25 @@ TlsHandle AllocateTlsHandle() {
return static_cast<TlsHandle>(key); return static_cast<TlsHandle>(key);
} }
bool FreeTlsHandle(TlsHandle handle) { bool FreeTlsHandle(TlsHandle handle) { return pthread_key_delete(handle) == 0; }
return pthread_key_delete(static_cast<pthread_key_t>(handle)) == 0;
}
uintptr_t GetTlsValue(TlsHandle handle) { uintptr_t GetTlsValue(TlsHandle handle) {
return reinterpret_cast<uintptr_t>( return reinterpret_cast<uintptr_t>(pthread_getspecific(handle));
pthread_getspecific(static_cast<pthread_key_t>(handle)));
} }
bool SetTlsValue(TlsHandle handle, uintptr_t value) { bool SetTlsValue(TlsHandle handle, uintptr_t value) {
return pthread_setspecific(static_cast<pthread_key_t>(handle), return pthread_setspecific(handle, reinterpret_cast<void*>(value)) == 0;
reinterpret_cast<void*>(value)) == 0;
} }
class PosixConditionBase { class PosixConditionBase {
public: public:
virtual ~PosixConditionBase() = default;
virtual bool Signal() = 0; virtual bool Signal() = 0;
WaitResult Wait(std::chrono::milliseconds timeout) { WaitResult Wait(std::chrono::milliseconds timeout) {
bool executed; bool executed;
auto predicate = [this] { return this->signaled(); }; auto predicate = [this] { return this->signaled(); };
auto lock = std::unique_lock<std::mutex>(mutex_); auto lock = std::unique_lock(mutex_);
if (predicate()) { if (predicate()) {
executed = true; executed = true;
} else { } else {
@ -213,15 +207,14 @@ class PosixConditionBase {
if (executed) { if (executed) {
post_execution(); post_execution();
return WaitResult::kSuccess; return WaitResult::kSuccess;
} else {
return WaitResult::kTimeout;
} }
return WaitResult::kTimeout;
} }
static std::pair<WaitResult, size_t> WaitMultiple( static std::pair<WaitResult, size_t> WaitMultiple(
std::vector<PosixConditionBase*>&& handles, bool wait_all, std::vector<PosixConditionBase*>&& handles, bool wait_all,
std::chrono::milliseconds timeout) { std::chrono::milliseconds timeout) {
assert_true(handles.size() > 0); assert_true(!handles.empty());
// Construct a condition for all or any depending on wait_all // Construct a condition for all or any depending on wait_all
std::function<bool()> predicate; std::function<bool()> predicate;
@ -239,17 +232,16 @@ class PosixConditionBase {
// TODO(bwrsandman, Triang3l) This is controversial, see issue #1677 // TODO(bwrsandman, Triang3l) This is controversial, see issue #1677
// This will probably cause a deadlock on the next thread doing any waiting // This will probably cause a deadlock on the next thread doing any waiting
// if the thread is suspended between locking and waiting // if the thread is suspended between locking and waiting
std::unique_lock<std::mutex> lock(PosixConditionBase::mutex_); std::unique_lock lock(mutex_);
bool wait_success = true; bool wait_success = true;
// If the timeout is infinite, wait without timeout. // If the timeout is infinite, wait without timeout.
// The predicate will be checked before beginning the wait // The predicate will be checked before beginning the wait
if (timeout == std::chrono::milliseconds::max()) { if (timeout == std::chrono::milliseconds::max()) {
PosixConditionBase::cond_.wait(lock, predicate); cond_.wait(lock, predicate);
} else { } else {
// Wait with timeout. // Wait with timeout.
wait_success = wait_success = cond_.wait_for(lock, timeout, predicate);
PosixConditionBase::cond_.wait_for(lock, timeout, predicate);
} }
if (wait_success) { if (wait_success) {
auto first_signaled = std::numeric_limits<size_t>::max(); auto first_signaled = std::numeric_limits<size_t>::max();
@ -264,15 +256,16 @@ class PosixConditionBase {
} }
assert_true(std::numeric_limits<size_t>::max() != first_signaled); assert_true(std::numeric_limits<size_t>::max() != first_signaled);
return std::make_pair(WaitResult::kSuccess, first_signaled); return std::make_pair(WaitResult::kSuccess, first_signaled);
} else {
return std::make_pair<WaitResult, size_t>(WaitResult::kTimeout, 0);
} }
return std::make_pair<WaitResult, size_t>(WaitResult::kTimeout, 0);
} }
virtual void* native_handle() const { return cond_.native_handle(); } [[nodiscard]] virtual void* native_handle() const {
return cond_.native_handle();
}
protected: protected:
inline virtual bool signaled() const = 0; [[nodiscard]] inline virtual bool signaled() const = 0;
inline virtual void post_execution() = 0; inline virtual void post_execution() = 0;
static std::condition_variable cond_; static std::condition_variable cond_;
static std::mutex mutex_; static std::mutex mutex_;
@ -293,23 +286,23 @@ class PosixCondition<Event> : public PosixConditionBase {
public: public:
PosixCondition(bool manual_reset, bool initial_state) PosixCondition(bool manual_reset, bool initial_state)
: signal_(initial_state), manual_reset_(manual_reset) {} : signal_(initial_state), manual_reset_(manual_reset) {}
virtual ~PosixCondition() = default; ~PosixCondition() override = default;
bool Signal() override { bool Signal() override {
auto lock = std::unique_lock<std::mutex>(mutex_); auto lock = std::unique_lock(mutex_);
signal_ = true; signal_ = true;
cond_.notify_all(); cond_.notify_all();
return true; return true;
} }
void Reset() { void Reset() {
auto lock = std::unique_lock<std::mutex>(mutex_); auto lock = std::unique_lock(mutex_);
signal_ = false; signal_ = false;
} }
private: private:
inline bool signaled() const override { return signal_; } [[nodiscard]] bool signaled() const override { return signal_; }
inline void post_execution() override { void post_execution() override {
if (!manual_reset_) { if (!manual_reset_) {
signal_ = false; signal_ = false;
} }
@ -319,7 +312,7 @@ class PosixCondition<Event> : public PosixConditionBase {
}; };
template <> template <>
class PosixCondition<Semaphore> : public PosixConditionBase { class PosixCondition<Semaphore> final : public PosixConditionBase {
public: public:
PosixCondition(uint32_t initial_count, uint32_t maximum_count) PosixCondition(uint32_t initial_count, uint32_t maximum_count)
: count_(initial_count), maximum_count_(maximum_count) {} : count_(initial_count), maximum_count_(maximum_count) {}
@ -328,7 +321,7 @@ class PosixCondition<Semaphore> : public PosixConditionBase {
bool Release(uint32_t release_count, int* out_previous_count) { bool Release(uint32_t release_count, int* out_previous_count) {
if (maximum_count_ - count_ >= release_count) { if (maximum_count_ - count_ >= release_count) {
auto lock = std::unique_lock<std::mutex>(mutex_); auto lock = std::unique_lock(mutex_);
if (out_previous_count) *out_previous_count = count_; if (out_previous_count) *out_previous_count = count_;
count_ += release_count; count_ += release_count;
cond_.notify_all(); cond_.notify_all();
@ -338,8 +331,8 @@ class PosixCondition<Semaphore> : public PosixConditionBase {
} }
private: private:
inline bool signaled() const override { return count_ > 0; } [[nodiscard]] bool signaled() const override { return count_ > 0; }
inline void post_execution() override { void post_execution() override {
count_--; count_--;
cond_.notify_all(); cond_.notify_all();
} }
@ -348,7 +341,7 @@ class PosixCondition<Semaphore> : public PosixConditionBase {
}; };
template <> template <>
class PosixCondition<Mutant> : public PosixConditionBase { class PosixCondition<Mutant> final : public PosixConditionBase {
public: public:
explicit PosixCondition(bool initial_owner) : count_(0) { explicit PosixCondition(bool initial_owner) : count_(0) {
if (initial_owner) { if (initial_owner) {
@ -361,7 +354,7 @@ class PosixCondition<Mutant> : public PosixConditionBase {
bool Release() { bool Release() {
if (owner_ == std::this_thread::get_id() && count_ > 0) { if (owner_ == std::this_thread::get_id() && count_ > 0) {
auto lock = std::unique_lock<std::mutex>(mutex_); auto lock = std::unique_lock(mutex_);
--count_; --count_;
// Free to be acquired by another thread // Free to be acquired by another thread
if (count_ == 0) { if (count_ == 0) {
@ -372,13 +365,15 @@ class PosixCondition<Mutant> : public PosixConditionBase {
return false; return false;
} }
void* native_handle() const override { return mutex_.native_handle(); } [[nodiscard]] void* native_handle() const override {
return mutex_.native_handle();
}
private: private:
inline bool signaled() const override { [[nodiscard]] bool signaled() const override {
return count_ == 0 || owner_ == std::this_thread::get_id(); return count_ == 0 || owner_ == std::this_thread::get_id();
} }
inline void post_execution() override { void post_execution() override {
count_++; count_++;
owner_ = std::this_thread::get_id(); owner_ = std::this_thread::get_id();
} }
@ -387,15 +382,15 @@ class PosixCondition<Mutant> : public PosixConditionBase {
}; };
template <> template <>
class PosixCondition<Timer> : public PosixConditionBase { class PosixCondition<Timer> final : public PosixConditionBase {
public: public:
explicit PosixCondition(bool manual_reset) explicit PosixCondition(bool manual_reset)
: callback_(nullptr), signal_(false), manual_reset_(manual_reset) {} : callback_(nullptr), signal_(false), manual_reset_(manual_reset) {}
virtual ~PosixCondition() { Cancel(); } ~PosixCondition() override { Cancel(); }
bool Signal() override { bool Signal() override {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard lock(mutex_);
signal_ = true; signal_ = true;
cond_.notify_all(); cond_.notify_all();
return true; return true;
@ -405,7 +400,7 @@ class PosixCondition<Timer> : public PosixConditionBase {
std::function<void()> opt_callback) { std::function<void()> opt_callback) {
Cancel(); Cancel();
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard lock(mutex_);
callback_ = std::move(opt_callback); callback_ = std::move(opt_callback);
signal_ = false; signal_ = false;
@ -417,7 +412,7 @@ class PosixCondition<Timer> : public PosixConditionBase {
std::function<void()> opt_callback) { std::function<void()> opt_callback) {
Cancel(); Cancel();
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard lock(mutex_);
callback_ = std::move(opt_callback); callback_ = std::move(opt_callback);
signal_ = false; signal_ = false;
@ -425,13 +420,13 @@ class PosixCondition<Timer> : public PosixConditionBase {
QueueTimerRecurring(&CompletionRoutine, this, due_time, period); QueueTimerRecurring(&CompletionRoutine, this, due_time, period);
} }
void Cancel() { void Cancel() const {
if (auto wait_item = wait_item_.lock()) { if (auto wait_item = wait_item_.lock()) {
wait_item->Disarm(); wait_item->Disarm();
} }
} }
void* native_handle() const override { [[nodiscard]] void* native_handle() const override {
assert_always(); assert_always();
return nullptr; return nullptr;
} }
@ -439,12 +434,12 @@ class PosixCondition<Timer> : public PosixConditionBase {
private: private:
static void CompletionRoutine(void* userdata) { static void CompletionRoutine(void* userdata) {
assert_not_null(userdata); assert_not_null(userdata);
auto timer = reinterpret_cast<PosixCondition<Timer>*>(userdata); auto timer = static_cast<PosixCondition*>(userdata);
timer->Signal(); timer->Signal();
// As the callback may reset the timer, store local. // As the callback may reset the timer, store local.
std::function<void()> callback; std::function<void()> callback;
{ {
std::lock_guard<std::mutex> lock(timer->mutex_); std::lock_guard lock(timer->mutex_);
callback = timer->callback_; callback = timer->callback_;
} }
if (callback) { if (callback) {
@ -452,9 +447,8 @@ class PosixCondition<Timer> : public PosixConditionBase {
} }
} }
private: [[nodiscard]] bool signaled() const override { return signal_; }
inline bool signaled() const override { return signal_; } void post_execution() override {
inline void post_execution() override {
if (!manual_reset_) { if (!manual_reset_) {
signal_ = false; signal_ = false;
} }
@ -472,7 +466,7 @@ struct ThreadStartData {
}; };
template <> template <>
class PosixCondition<Thread> : public PosixConditionBase { class PosixCondition<Thread> final : public PosixConditionBase {
enum class State { enum class State {
kUninitialized, kUninitialized,
kRunning, kRunning,
@ -526,13 +520,14 @@ class PosixCondition<Thread> : public PosixConditionBase {
: thread_(thread), : thread_(thread),
signaled_(false), signaled_(false),
exit_code_(0), exit_code_(0),
state_(State::kRunning) { state_(State::kRunning),
suspend_count_(0) {
#if XE_PLATFORM_ANDROID #if XE_PLATFORM_ANDROID
android_pre_api_26_name_[0] = '\0'; android_pre_api_26_name_[0] = '\0';
#endif #endif
} }
virtual ~PosixCondition() { ~PosixCondition() override {
// FIXME(RodoMa92): This causes random crashes. // FIXME(RodoMa92): This causes random crashes.
// The proper way to handle them according to the webs is properly shutdown // The proper way to handle them according to the webs is properly shutdown
// instead on relying on killing them using pthread_cancel. // instead on relying on killing them using pthread_cancel.
@ -560,7 +555,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
std::string name() const { std::string name() const {
WaitStarted(); WaitStarted();
auto result = std::array<char, 17>{'\0'}; auto result = std::array<char, 17>{'\0'};
std::unique_lock<std::mutex> lock(state_mutex_); std::unique_lock lock(state_mutex_);
if (state_ != State::kUninitialized && state_ != State::kFinished) { if (state_ != State::kUninitialized && state_ != State::kFinished) {
#if XE_PLATFORM_ANDROID #if XE_PLATFORM_ANDROID
// pthread_getname_np was added in API 26 - below that, store the name in // pthread_getname_np was added in API 26 - below that, store the name in
@ -584,7 +579,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
return std::string(result.data()); return std::string(result.data());
} }
void set_name(const std::string& name) { void set_name(const std::string& name) const {
WaitStarted(); WaitStarted();
std::unique_lock<std::mutex> lock(state_mutex_); std::unique_lock<std::mutex> lock(state_mutex_);
if (state_ != State::kUninitialized && state_ != State::kFinished) { if (state_ != State::kUninitialized && state_ != State::kFinished) {
@ -608,7 +603,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
uint32_t system_id() const { return static_cast<uint32_t>(thread_); } uint32_t system_id() const { return static_cast<uint32_t>(thread_); }
uint64_t affinity_mask() { uint64_t affinity_mask() const {
WaitStarted(); WaitStarted();
cpu_set_t cpu_set; cpu_set_t cpu_set;
#if XE_PLATFORM_ANDROID #if XE_PLATFORM_ANDROID
@ -630,7 +625,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
return result; return result;
} }
void set_affinity_mask(uint64_t mask) { void set_affinity_mask(uint64_t mask) const {
WaitStarted(); WaitStarted();
cpu_set_t cpu_set; cpu_set_t cpu_set;
CPU_ZERO(&cpu_set); CPU_ZERO(&cpu_set);
@ -651,7 +646,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
#endif #endif
} }
int priority() { int priority() const {
WaitStarted(); WaitStarted();
int policy; int policy;
sched_param param{}; sched_param param{};
@ -663,7 +658,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
return param.sched_priority; return param.sched_priority;
} }
void set_priority(int new_priority) { void set_priority(int new_priority) const {
WaitStarted(); WaitStarted();
sched_param param{}; sched_param param{};
param.sched_priority = new_priority; param.sched_priority = new_priority;
@ -683,7 +678,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
void QueueUserCallback(std::function<void()> callback) { void QueueUserCallback(std::function<void()> callback) {
WaitStarted(); WaitStarted();
std::unique_lock<std::mutex> lock(callback_mutex_); std::unique_lock lock(callback_mutex_);
user_callback_ = std::move(callback); user_callback_ = std::move(callback);
sigval value{}; sigval value{};
value.sival_ptr = this; value.sival_ptr = this;
@ -696,8 +691,8 @@ class PosixCondition<Thread> : public PosixConditionBase {
#endif #endif
} }
void CallUserCallback() { void CallUserCallback() const {
std::unique_lock<std::mutex> lock(callback_mutex_); std::unique_lock lock(callback_mutex_);
user_callback_(); user_callback_();
} }
@ -706,7 +701,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
*out_previous_suspend_count = 0; *out_previous_suspend_count = 0;
} }
WaitStarted(); WaitStarted();
std::unique_lock<std::mutex> lock(state_mutex_); std::unique_lock lock(state_mutex_);
if (state_ != State::kSuspended) return false; if (state_ != State::kSuspended) return false;
if (out_previous_suspend_count) { if (out_previous_suspend_count) {
*out_previous_suspend_count = suspend_count_; *out_previous_suspend_count = suspend_count_;
@ -736,7 +731,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
void Terminate(int exit_code) { void Terminate(int exit_code) {
bool is_current_thread = pthread_self() == thread_; bool is_current_thread = pthread_self() == thread_;
{ {
std::unique_lock<std::mutex> lock(state_mutex_); std::unique_lock lock(state_mutex_);
if (state_ == State::kFinished) { if (state_ == State::kFinished) {
if (is_current_thread) { if (is_current_thread) {
// This is really bad. Some thread must have called Terminate() on us // This is really bad. Some thread must have called Terminate() on us
@ -752,7 +747,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
} }
{ {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard lock(mutex_);
exit_code_ = exit_code; exit_code_ = exit_code;
signaled_ = true; signaled_ = true;
@ -760,29 +755,28 @@ class PosixCondition<Thread> : public PosixConditionBase {
} }
if (is_current_thread) { if (is_current_thread) {
pthread_exit(reinterpret_cast<void*>(exit_code)); pthread_exit(reinterpret_cast<void*>(exit_code));
} else {
#ifdef XE_PLATFORM_ANDROID
if (pthread_kill(thread_,
GetSystemSignal(SignalType::kThreadTerminate)) != 0) {
assert_always();
}
#else
if (pthread_cancel(thread_) != 0) {
assert_always();
}
#endif
} }
#ifdef XE_PLATFORM_ANDROID
if (pthread_kill(thread_, GetSystemSignal(SignalType::kThreadTerminate)) !=
0) {
assert_always();
}
#else
if (pthread_cancel(thread_) != 0) {
assert_always();
}
#endif
} }
void WaitStarted() const { void WaitStarted() const {
std::unique_lock<std::mutex> lock(state_mutex_); std::unique_lock lock(state_mutex_);
state_signal_.wait(lock, state_signal_.wait(lock,
[this] { return state_ != State::kUninitialized; }); [this] { return state_ != State::kUninitialized; });
} }
/// Set state to suspended and wait until it reset by another thread /// Set state to suspended and wait until it reset by another thread
void WaitSuspended() { void WaitSuspended() {
std::unique_lock<std::mutex> lock(state_mutex_); std::unique_lock lock(state_mutex_);
state_signal_.wait(lock, [this] { return suspend_count_ == 0; }); state_signal_.wait(lock, [this] { return suspend_count_ == 0; });
state_ = State::kRunning; state_ = State::kRunning;
} }
@ -793,8 +787,8 @@ class PosixCondition<Thread> : public PosixConditionBase {
private: private:
static void* ThreadStartRoutine(void* parameter); static void* ThreadStartRoutine(void* parameter);
inline bool signaled() const override { return signaled_; } bool signaled() const override { return signaled_; }
inline void post_execution() override { void post_execution() override {
if (thread_) { if (thread_) {
pthread_join(thread_, nullptr); pthread_join(thread_, nullptr);
} }
@ -818,6 +812,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
class PosixWaitHandle { class PosixWaitHandle {
public: public:
virtual ~PosixWaitHandle() = default;
virtual PosixConditionBase& condition() = 0; virtual PosixConditionBase& condition() = 0;
}; };
@ -834,7 +829,9 @@ class PosixConditionHandle : public T, public PosixWaitHandle {
~PosixConditionHandle() override = default; ~PosixConditionHandle() override = default;
PosixCondition<T>& condition() override { return handle_; } PosixCondition<T>& condition() override { return handle_; }
void* native_handle() const override { return handle_.native_handle(); } [[nodiscard]] void* native_handle() const override {
return handle_.native_handle();
}
protected: protected:
PosixCondition<T> handle_; PosixCondition<T> handle_;
@ -915,7 +912,7 @@ std::pair<WaitResult, size_t> WaitMultiple(WaitHandle* wait_handles[],
return result; return result;
} }
class PosixEvent : public PosixConditionHandle<Event> { class PosixEvent final : public PosixConditionHandle<Event> {
public: public:
PosixEvent(bool manual_reset, bool initial_state) PosixEvent(bool manual_reset, bool initial_state)
: PosixConditionHandle(manual_reset, initial_state) {} : PosixConditionHandle(manual_reset, initial_state) {}
@ -944,7 +941,7 @@ std::unique_ptr<Event> Event::CreateAutoResetEvent(bool initial_state) {
return std::make_unique<PosixEvent>(false, initial_state); return std::make_unique<PosixEvent>(false, initial_state);
} }
class PosixSemaphore : public PosixConditionHandle<Semaphore> { class PosixSemaphore final : public PosixConditionHandle<Semaphore> {
public: public:
PosixSemaphore(int initial_count, int maximum_count) PosixSemaphore(int initial_count, int maximum_count)
: PosixConditionHandle(static_cast<uint32_t>(initial_count), : PosixConditionHandle(static_cast<uint32_t>(initial_count),
@ -968,7 +965,7 @@ std::unique_ptr<Semaphore> Semaphore::Create(int initial_count,
return std::make_unique<PosixSemaphore>(initial_count, maximum_count); return std::make_unique<PosixSemaphore>(initial_count, maximum_count);
} }
class PosixMutant : public PosixConditionHandle<Mutant> { class PosixMutant final : public PosixConditionHandle<Mutant> {
public: public:
explicit PosixMutant(bool initial_owner) explicit PosixMutant(bool initial_owner)
: PosixConditionHandle(initial_owner) {} : PosixConditionHandle(initial_owner) {}
@ -980,9 +977,9 @@ std::unique_ptr<Mutant> Mutant::Create(bool initial_owner) {
return std::make_unique<PosixMutant>(initial_owner); return std::make_unique<PosixMutant>(initial_owner);
} }
class PosixTimer : public PosixConditionHandle<Timer> { class PosixTimer final : public PosixConditionHandle<Timer> {
using WClock_ = Timer::WClock_; using WClock_ = WClock_;
using GClock_ = Timer::GClock_; using GClock_ = GClock_;
public: public:
explicit PosixTimer(bool manual_reset) : PosixConditionHandle(manual_reset) {} explicit PosixTimer(bool manual_reset) : PosixConditionHandle(manual_reset) {}
@ -1035,7 +1032,7 @@ std::unique_ptr<Timer> Timer::CreateSynchronizationTimer() {
return std::make_unique<PosixTimer>(false); return std::make_unique<PosixTimer>(false);
} }
class PosixThread : public PosixConditionHandle<Thread> { class PosixThread final : public PosixConditionHandle<Thread> {
public: public:
PosixThread() = default; PosixThread() = default;
explicit PosixThread(pthread_t thread) : PosixConditionHandle(thread) {} explicit PosixThread(pthread_t thread) : PosixConditionHandle(thread) {}
@ -1107,14 +1104,14 @@ void* PosixCondition<Thread>::ThreadStartRoutine(void* parameter) {
current_thread_ = thread; current_thread_ = thread;
{ {
std::unique_lock<std::mutex> lock(thread->handle_.state_mutex_); std::unique_lock lock(thread->handle_.state_mutex_);
thread->handle_.state_ = thread->handle_.state_ =
create_suspended ? State::kSuspended : State::kRunning; create_suspended ? State::kSuspended : State::kRunning;
thread->handle_.state_signal_.notify_all(); thread->handle_.state_signal_.notify_all();
} }
if (create_suspended) { if (create_suspended) {
std::unique_lock<std::mutex> lock(thread->handle_.state_mutex_); std::unique_lock lock(thread->handle_.state_mutex_);
thread->handle_.suspend_count_ = 1; thread->handle_.suspend_count_ = 1;
thread->handle_.state_signal_.wait( thread->handle_.state_signal_.wait(
lock, [thread] { return thread->handle_.suspend_count_ == 0; }); lock, [thread] { return thread->handle_.suspend_count_ == 0; });
@ -1123,11 +1120,11 @@ void* PosixCondition<Thread>::ThreadStartRoutine(void* parameter) {
start_routine(); start_routine();
{ {
std::unique_lock<std::mutex> lock(thread->handle_.state_mutex_); std::unique_lock lock(thread->handle_.state_mutex_);
thread->handle_.state_ = State::kFinished; thread->handle_.state_ = State::kFinished;
} }
std::unique_lock<std::mutex> lock(mutex_); std::unique_lock lock(mutex_);
thread->handle_.exit_code_ = 0; thread->handle_.exit_code_ = 0;
thread->handle_.signaled_ = true; thread->handle_.signaled_ = true;
cond_.notify_all(); cond_.notify_all();

View File

@ -7,7 +7,6 @@
****************************************************************************** ******************************************************************************
*/ */
#include <algorithm>
#include <forward_list> #include <forward_list>
#include "third_party/disruptorplus/include/disruptorplus/blocking_wait_strategy.hpp" #include "third_party/disruptorplus/include/disruptorplus/blocking_wait_strategy.hpp"

View File

@ -170,7 +170,7 @@ void Sleep(std::chrono::microseconds duration) {
} }
SleepResult AlertableSleep(std::chrono::microseconds duration) { SleepResult AlertableSleep(std::chrono::microseconds duration) {
if (SleepEx(static_cast<DWORD>(duration.count() / 1000), TRUE) == if (SleepEx(static_cast<DWORD>(duration.count() / 1000), true) ==
WAIT_IO_COMPLETION) { WAIT_IO_COMPLETION) {
return SleepResult::kAlerted; return SleepResult::kAlerted;
} }
@ -211,7 +211,7 @@ WaitResult Wait(WaitHandle* wait_handle, bool is_alertable,
HANDLE handle = wait_handle->native_handle(); HANDLE handle = wait_handle->native_handle();
DWORD result; DWORD result;
DWORD timeout_dw = DWORD(timeout.count()); DWORD timeout_dw = DWORD(timeout.count());
BOOL bAlertable = is_alertable ? TRUE : FALSE; BOOL bAlertable = is_alertable ? true : false;
// todo: we might actually be able to use NtWaitForSingleObject even if its // todo: we might actually be able to use NtWaitForSingleObject even if its
// alertable, just need to study whether // alertable, just need to study whether
// RtlDeactivateActivationContextUnsafeFast/RtlActivateActivationContext are // RtlDeactivateActivationContextUnsafeFast/RtlActivateActivationContext are
@ -251,7 +251,7 @@ WaitResult SignalAndWait(WaitHandle* wait_handle_to_signal,
HANDLE handle_to_wait_on = wait_handle_to_wait_on->native_handle(); HANDLE handle_to_wait_on = wait_handle_to_wait_on->native_handle();
DWORD result = DWORD result =
SignalObjectAndWait(handle_to_signal, handle_to_wait_on, SignalObjectAndWait(handle_to_signal, handle_to_wait_on,
DWORD(timeout.count()), is_alertable ? TRUE : FALSE); DWORD(timeout.count()), is_alertable ? true : false);
switch (result) { switch (result) {
case WAIT_OBJECT_0: case WAIT_OBJECT_0:
return WaitResult::kSuccess; return WaitResult::kSuccess;
@ -278,8 +278,8 @@ std::pair<WaitResult, size_t> WaitMultiple(WaitHandle* wait_handles[],
handles[i] = wait_handles[i]->native_handle(); handles[i] = wait_handles[i]->native_handle();
} }
DWORD result = WaitForMultipleObjectsEx( DWORD result = WaitForMultipleObjectsEx(
static_cast<DWORD>(wait_handle_count), handles, wait_all ? TRUE : FALSE, static_cast<DWORD>(wait_handle_count), handles, wait_all ? true : false,
DWORD(timeout.count()), is_alertable ? TRUE : FALSE); DWORD(timeout.count()), is_alertable ? true : false);
if (result >= WAIT_OBJECT_0 && result < WAIT_OBJECT_0 + wait_handle_count) { if (result >= WAIT_OBJECT_0 && result < WAIT_OBJECT_0 + wait_handle_count) {
return std::pair<WaitResult, size_t>(WaitResult::kSuccess, return std::pair<WaitResult, size_t>(WaitResult::kSuccess,
result - WAIT_OBJECT_0); result - WAIT_OBJECT_0);
@ -339,7 +339,7 @@ class Win32Event : public Win32Handle<Event> {
std::unique_ptr<Event> Event::CreateManualResetEvent(bool initial_state) { std::unique_ptr<Event> Event::CreateManualResetEvent(bool initial_state) {
HANDLE handle = HANDLE handle =
CreateEvent(nullptr, TRUE, initial_state ? TRUE : FALSE, nullptr); CreateEvent(nullptr, true, initial_state ? true : false, nullptr);
if (handle) { if (handle) {
return std::make_unique<Win32Event>(handle); return std::make_unique<Win32Event>(handle);
} else { } else {
@ -351,7 +351,7 @@ std::unique_ptr<Event> Event::CreateManualResetEvent(bool initial_state) {
std::unique_ptr<Event> Event::CreateAutoResetEvent(bool initial_state) { std::unique_ptr<Event> Event::CreateAutoResetEvent(bool initial_state) {
HANDLE handle = HANDLE handle =
CreateEvent(nullptr, FALSE, initial_state ? TRUE : FALSE, nullptr); CreateEvent(nullptr, false, initial_state ? true : false, nullptr);
if (handle) { if (handle) {
return std::make_unique<Win32Event>(handle); return std::make_unique<Win32Event>(handle);
} else { } else {
@ -397,7 +397,7 @@ class Win32Mutant : public Win32Handle<Mutant> {
}; };
std::unique_ptr<Mutant> Mutant::Create(bool initial_owner) { std::unique_ptr<Mutant> Mutant::Create(bool initial_owner) {
HANDLE handle = CreateMutex(nullptr, initial_owner ? TRUE : FALSE, nullptr); HANDLE handle = CreateMutex(nullptr, initial_owner ? true : false, nullptr);
if (handle) { if (handle) {
return std::make_unique<Win32Mutant>(handle); return std::make_unique<Win32Mutant>(handle);
} else { } else {
@ -433,7 +433,7 @@ class Win32Timer : public Win32Handle<Timer> {
callback_ ? reinterpret_cast<PTIMERAPCROUTINE>(CompletionRoutine) callback_ ? reinterpret_cast<PTIMERAPCROUTINE>(CompletionRoutine)
: NULL; : NULL;
return SetWaitableTimer(handle_, &due_time_li, 0, completion_routine, this, return SetWaitableTimer(handle_, &due_time_li, 0, completion_routine, this,
FALSE) false)
? true ? true
: false; : false;
} }
@ -461,7 +461,7 @@ class Win32Timer : public Win32Handle<Timer> {
callback_ ? reinterpret_cast<PTIMERAPCROUTINE>(CompletionRoutine) callback_ ? reinterpret_cast<PTIMERAPCROUTINE>(CompletionRoutine)
: NULL; : NULL;
return SetWaitableTimer(handle_, &due_time_li, int32_t(period.count()), return SetWaitableTimer(handle_, &due_time_li, int32_t(period.count()),
completion_routine, this, FALSE) completion_routine, this, false)
? true ? true
: false; : false;
} }
@ -490,7 +490,7 @@ class Win32Timer : public Win32Handle<Timer> {
}; };
std::unique_ptr<Timer> Timer::CreateManualResetTimer() { std::unique_ptr<Timer> Timer::CreateManualResetTimer() {
HANDLE handle = CreateWaitableTimer(NULL, TRUE, NULL); HANDLE handle = CreateWaitableTimer(NULL, true, NULL);
if (handle) { if (handle) {
return std::make_unique<Win32Timer>(handle); return std::make_unique<Win32Timer>(handle);
} else { } else {
@ -500,7 +500,7 @@ std::unique_ptr<Timer> Timer::CreateManualResetTimer() {
} }
std::unique_ptr<Timer> Timer::CreateSynchronizationTimer() { std::unique_ptr<Timer> Timer::CreateSynchronizationTimer() {
HANDLE handle = CreateWaitableTimer(NULL, FALSE, NULL); HANDLE handle = CreateWaitableTimer(NULL, false, NULL);
if (handle) { if (handle) {
return std::make_unique<Win32Timer>(handle); return std::make_unique<Win32Timer>(handle);
} else { } else {

View File

@ -11,11 +11,8 @@
#include <algorithm> #include <algorithm>
#include <cstdint> #include <cstdint>
#include <locale>
#include <numeric>
#include <tuple>
#define UTF_CPP_CPLUSPLUS 201703L #define UTF_CPP_CPLUSPLUS 202002L
#include "third_party/utfcpp/source/utf8.h" #include "third_party/utfcpp/source/utf8.h"
namespace utfcpp = utf8; namespace utfcpp = utf8;
@ -82,10 +79,10 @@ std::string upper_ascii(const std::string_view view) {
template <bool LOWER> template <bool LOWER>
inline size_t hash_fnv1a(const std::string_view view) { inline size_t hash_fnv1a(const std::string_view view) {
const size_t offset_basis = 0xCBF29CE484222325ull; constexpr size_t offset_basis = 0xCBF29CE484222325ull;
// chrispy: constant capture errors on clang // chrispy: constant capture errors on clang
auto work = [](size_t hash, uint8_t byte_of_data) { auto work = [](size_t hash, uint8_t byte_of_data) {
const size_t prime = 0x00000100000001B3ull; constexpr size_t prime = 0x00000100000001B3ull;
hash ^= byte_of_data; hash ^= byte_of_data;
hash *= prime; hash *= prime;
return hash; return hash;

View File

@ -7,7 +7,6 @@
****************************************************************************** ******************************************************************************
*/ */
#include <cstddef>
#include <ostream> #include <ostream>
#include <string> #include <string>

View File

@ -206,7 +206,7 @@ void SaveConfig() {
line_count = xe::utf8::count(*last); line_count = xe::utf8::count(*last);
} }
const size_t value_alignment = 50; constexpr size_t value_alignment = 50;
const auto& description = config_var->description(); const auto& description = config_var->description();
if (!description.empty()) { if (!description.empty()) {
if (line_count < value_alignment) { if (line_count < value_alignment) {

View File

@ -14,8 +14,6 @@ project("xenia-cpu-backend-x64")
}) })
defines({ defines({
"CAPSTONE_X86_ATT_DISABLE", "CAPSTONE_X86_ATT_DISABLE",
"CAPSTONE_DIET_NO",
"CAPSTONE_X86_REDUCE_NO",
"CAPSTONE_HAS_X86", "CAPSTONE_HAS_X86",
"CAPSTONE_USE_SYS_DYN_MEM", "CAPSTONE_USE_SYS_DYN_MEM",
"XBYAK_NO_OP_NAMES", "XBYAK_NO_OP_NAMES",

View File

@ -9,7 +9,6 @@
#include "xenia/cpu/backend/x64/x64_backend.h" #include "xenia/cpu/backend/x64/x64_backend.h"
#include <algorithm>
#include <cstddef> #include <cstddef>
#include "third_party/capstone/include/capstone/capstone.h" #include "third_party/capstone/include/capstone/capstone.h"
#include "third_party/capstone/include/capstone/x86.h" #include "third_party/capstone/include/capstone/x86.h"
@ -636,7 +635,7 @@ HostToGuestThunk X64HelperEmitter::EmitHostToGuestThunk() {
_code_offsets code_offsets = {}; _code_offsets code_offsets = {};
const size_t stack_size = StackLayout::THUNK_STACK_SIZE; constexpr size_t stack_size = StackLayout::THUNK_STACK_SIZE;
code_offsets.prolog = getSize(); code_offsets.prolog = getSize();
@ -681,13 +680,10 @@ HostToGuestThunk X64HelperEmitter::EmitHostToGuestThunk() {
size_t tail; size_t tail;
} code_offsets = {}; } code_offsets = {};
const size_t stack_size = StackLayout::THUNK_STACK_SIZE; constexpr size_t stack_size = StackLayout::THUNK_STACK_SIZE;
code_offsets.prolog = getSize(); code_offsets.prolog = getSize();
// rsp + 0 = return address // rsp + 0 = return address
mov(qword[rsp + 8 * 3], rdx);
mov(qword[rsp + 8 * 2], rsi);
mov(qword[rsp + 8 * 1], rdi);
sub(rsp, stack_size); sub(rsp, stack_size);
code_offsets.prolog_stack_alloc = getSize(); code_offsets.prolog_stack_alloc = getSize();
@ -707,9 +703,6 @@ HostToGuestThunk X64HelperEmitter::EmitHostToGuestThunk() {
code_offsets.epilog = getSize(); code_offsets.epilog = getSize();
add(rsp, stack_size); add(rsp, stack_size);
mov(rdi, qword[rsp + 8 * 1]);
mov(rsi, qword[rsp + 8 * 2]);
mov(rdx, qword[rsp + 8 * 3]);
ret(); ret();
#else #else
assert_always("Unknown platform ABI in host to guest thunk!"); assert_always("Unknown platform ABI in host to guest thunk!");
@ -741,7 +734,7 @@ GuestToHostThunk X64HelperEmitter::EmitGuestToHostThunk() {
_code_offsets code_offsets = {}; _code_offsets code_offsets = {};
const size_t stack_size = StackLayout::THUNK_STACK_SIZE; constexpr size_t stack_size = StackLayout::THUNK_STACK_SIZE;
code_offsets.prolog = getSize(); code_offsets.prolog = getSize();
@ -787,7 +780,7 @@ GuestToHostThunk X64HelperEmitter::EmitGuestToHostThunk() {
size_t tail; size_t tail;
} code_offsets = {}; } code_offsets = {};
const size_t stack_size = StackLayout::THUNK_STACK_SIZE; constexpr size_t stack_size = StackLayout::THUNK_STACK_SIZE;
code_offsets.prolog = getSize(); code_offsets.prolog = getSize();
@ -844,7 +837,7 @@ ResolveFunctionThunk X64HelperEmitter::EmitResolveFunctionThunk() {
_code_offsets code_offsets = {}; _code_offsets code_offsets = {};
const size_t stack_size = StackLayout::THUNK_STACK_SIZE; constexpr size_t stack_size = StackLayout::THUNK_STACK_SIZE;
code_offsets.prolog = getSize(); code_offsets.prolog = getSize();
@ -884,7 +877,7 @@ ResolveFunctionThunk X64HelperEmitter::EmitResolveFunctionThunk() {
size_t epilog; size_t epilog;
size_t tail; size_t tail;
} code_offsets = {}; } code_offsets = {};
const size_t stack_size = StackLayout::THUNK_STACK_SIZE; constexpr size_t stack_size = StackLayout::THUNK_STACK_SIZE;
code_offsets.prolog = getSize(); code_offsets.prolog = getSize();
@ -1743,7 +1736,7 @@ void X64Backend::PrepareForReentry(void* ctx) {
bctx->current_stackpoint_depth = 0; bctx->current_stackpoint_depth = 0;
} }
const uint32_t mxcsr_table[8] = { constexpr uint32_t mxcsr_table[8] = {
0x1F80, 0x7F80, 0x5F80, 0x3F80, 0x9F80, 0xFF80, 0xDF80, 0xBF80, 0x1F80, 0x7F80, 0x5F80, 0x3F80, 0x9F80, 0xFF80, 0xDF80, 0xBF80,
}; };

View File

@ -120,7 +120,7 @@ constexpr unsigned int DEFAULT_FPU_MXCSR = 0x1F80;
extern const uint32_t mxcsr_table[8]; extern const uint32_t mxcsr_table[8];
class X64Backend : public Backend { class X64Backend : public Backend {
public: public:
static const uint32_t kForceReturnAddress = 0x9FFF0000u; static constexpr uint32_t kForceReturnAddress = 0x9FFF0000u;
explicit X64Backend(); explicit X64Backend();
~X64Backend() override; ~X64Backend() override;

View File

@ -79,13 +79,13 @@ class X64CodeCache : public CodeCache {
protected: protected:
// All executable code falls within 0x80000000 to 0x9FFFFFFF, so we can // All executable code falls within 0x80000000 to 0x9FFFFFFF, so we can
// only map enough for lookups within that range. // only map enough for lookups within that range.
static const size_t kIndirectionTableSize = 0x1FFFFFFF; static constexpr size_t kIndirectionTableSize = 0x1FFFFFFF;
static const uintptr_t kIndirectionTableBase = 0x80000000; static constexpr uintptr_t kIndirectionTableBase = 0x80000000;
// The code range is 512MB, but we know the total code games will have is // The code range is 512MB, but we know the total code games will have is
// pretty small (dozens of mb at most) and our expansion is reasonablish // pretty small (dozens of mb at most) and our expansion is reasonablish
// so 256MB should be more than enough. // so 256MB should be more than enough.
static const size_t kGeneratedCodeSize = 0x0FFFFFFF; static constexpr size_t kGeneratedCodeSize = 0x0FFFFFFF;
static const uintptr_t kGeneratedCodeExecuteBase = 0xA0000000; static constexpr uintptr_t kGeneratedCodeExecuteBase = 0xA0000000;
// Used for writing when PageAccess::kExecuteReadWrite is not supported. // Used for writing when PageAccess::kExecuteReadWrite is not supported.
static const uintptr_t kGeneratedCodeWriteBase = static const uintptr_t kGeneratedCodeWriteBase =
kGeneratedCodeExecuteBase + kGeneratedCodeSize + 1; kGeneratedCodeExecuteBase + kGeneratedCodeSize + 1;
@ -95,7 +95,7 @@ class X64CodeCache : public CodeCache {
// in analysis triggering. // in analysis triggering.
// chrispy: raised this, some games that were compiled with low optimization // chrispy: raised this, some games that were compiled with low optimization
// levels can exceed this // levels can exceed this
static const size_t kMaximumFunctionCount = 1000000; static constexpr size_t kMaximumFunctionCount = 1000000;
struct UnwindReservation { struct UnwindReservation {
size_t data_size = 0; size_t data_size = 0;

View File

@ -48,4 +48,4 @@ bool PosixX64CodeCache::Initialize() { return X64CodeCache::Initialize(); }
} // namespace x64 } // namespace x64
} // namespace backend } // namespace backend
} // namespace cpu } // namespace cpu
} // namespace xe } // namespace xe

View File

@ -92,7 +92,7 @@ typedef struct _UNWIND_INFO {
// Size of unwind info per function. // Size of unwind info per function.
// TODO(benvanik): move this to emitter. // TODO(benvanik): move this to emitter.
static const uint32_t kUnwindInfoSize = static constexpr uint32_t kUnwindInfoSize =
sizeof(UNWIND_INFO) + (sizeof(UNWIND_CODE) * (6 - 1)); sizeof(UNWIND_INFO) + (sizeof(UNWIND_CODE) * (6 - 1));
class Win32X64CodeCache : public X64CodeCache { class Win32X64CodeCache : public X64CodeCache {

View File

@ -72,17 +72,17 @@ using xe::cpu::hir::HIRBuilder;
using xe::cpu::hir::Instr; using xe::cpu::hir::Instr;
using namespace xe::literals; using namespace xe::literals;
static const size_t kMaxCodeSize = 1_MiB; static constexpr size_t kMaxCodeSize = 1_MiB;
// static const size_t kStashOffsetHigh = 32 + 32; // static const size_t kStashOffsetHigh = 32 + 32;
const uint32_t X64Emitter::gpr_reg_map_[X64Emitter::GPR_COUNT] = { constexpr uint32_t X64Emitter::gpr_reg_map_[X64Emitter::GPR_COUNT] = {
Xbyak::Operand::RBX, Xbyak::Operand::R10, Xbyak::Operand::R11, Xbyak::Operand::RBX, Xbyak::Operand::R10, Xbyak::Operand::R11,
Xbyak::Operand::R12, Xbyak::Operand::R13, Xbyak::Operand::R14, Xbyak::Operand::R12, Xbyak::Operand::R13, Xbyak::Operand::R14,
Xbyak::Operand::R15, Xbyak::Operand::R15,
}; };
const uint32_t X64Emitter::xmm_reg_map_[X64Emitter::XMM_COUNT] = { constexpr uint32_t X64Emitter::xmm_reg_map_[X64Emitter::XMM_COUNT] = {
4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
}; };
@ -1242,11 +1242,11 @@ void* X64Emitter::FindQwordConstantOffset(uint64_t qwordvalue) {
return nullptr; return nullptr;
} }
// First location to try and place constants. // First location to try and place constants.
static const uintptr_t kConstDataLocation = 0x20000000; static constexpr uintptr_t kConstDataLocation = 0x20000000;
static const uintptr_t kConstDataSize = sizeof(xmm_consts); static constexpr uintptr_t kConstDataSize = sizeof(xmm_consts);
// Increment the location by this amount for every allocation failure. // Increment the location by this amount for every allocation failure.
static const uintptr_t kConstDataIncrement = 0x00001000; static constexpr uintptr_t kConstDataIncrement = 0x00001000;
// This function places constant data that is used by the emitter later on. // This function places constant data that is used by the emitter later on.
// Only called once and used by multiple instances of the emitter. // Only called once and used by multiple instances of the emitter.

View File

@ -227,8 +227,8 @@ class X64Emitter : public Xbyak::CodeGenerator {
// xmm0-2 // xmm0-2
// Available: rbx, r10-r15 // Available: rbx, r10-r15
// xmm4-xmm15 (save to get xmm3) // xmm4-xmm15 (save to get xmm3)
static const int GPR_COUNT = 7; static constexpr int GPR_COUNT = 7;
static const int XMM_COUNT = 12; static constexpr int XMM_COUNT = 12;
static constexpr size_t kStashOffset = 32; static constexpr size_t kStashOffset = 32;
static void SetupReg(const hir::Value* v, Xbyak::Reg8& r) { static void SetupReg(const hir::Value* v, Xbyak::Reg8& r) {
auto idx = gpr_reg_map_[v->reg.index]; auto idx = gpr_reg_map_[v->reg.index];

View File

@ -123,7 +123,7 @@ struct OpBase {};
template <typename T, KeyType KEY_TYPE> template <typename T, KeyType KEY_TYPE>
struct Op : OpBase { struct Op : OpBase {
static const KeyType key_type = KEY_TYPE; static constexpr KeyType key_type = KEY_TYPE;
}; };
struct VoidOp : Op<VoidOp, KEY_TYPE_X> { struct VoidOp : Op<VoidOp, KEY_TYPE_X> {
@ -298,7 +298,7 @@ struct I;
template <hir::Opcode OPCODE, typename DEST> template <hir::Opcode OPCODE, typename DEST>
struct I<OPCODE, DEST> : DestField<DEST> { struct I<OPCODE, DEST> : DestField<DEST> {
typedef DestField<DEST> BASE; typedef DestField<DEST> BASE;
static const hir::Opcode opcode = OPCODE; static constexpr hir::Opcode opcode = OPCODE;
static const uint32_t key = static const uint32_t key =
InstrKey::Construct<OPCODE, DEST::key_type>::value; InstrKey::Construct<OPCODE, DEST::key_type>::value;
static const KeyType dest_type = DEST::key_type; static const KeyType dest_type = DEST::key_type;
@ -318,7 +318,7 @@ struct I<OPCODE, DEST> : DestField<DEST> {
template <hir::Opcode OPCODE, typename DEST, typename SRC1> template <hir::Opcode OPCODE, typename DEST, typename SRC1>
struct I<OPCODE, DEST, SRC1> : DestField<DEST> { struct I<OPCODE, DEST, SRC1> : DestField<DEST> {
typedef DestField<DEST> BASE; typedef DestField<DEST> BASE;
static const hir::Opcode opcode = OPCODE; static constexpr hir::Opcode opcode = OPCODE;
static const uint32_t key = static const uint32_t key =
InstrKey::Construct<OPCODE, DEST::key_type, SRC1::key_type>::value; InstrKey::Construct<OPCODE, DEST::key_type, SRC1::key_type>::value;
static const KeyType dest_type = DEST::key_type; static const KeyType dest_type = DEST::key_type;
@ -341,7 +341,7 @@ struct I<OPCODE, DEST, SRC1> : DestField<DEST> {
template <hir::Opcode OPCODE, typename DEST, typename SRC1, typename SRC2> template <hir::Opcode OPCODE, typename DEST, typename SRC1, typename SRC2>
struct I<OPCODE, DEST, SRC1, SRC2> : DestField<DEST> { struct I<OPCODE, DEST, SRC1, SRC2> : DestField<DEST> {
typedef DestField<DEST> BASE; typedef DestField<DEST> BASE;
static const hir::Opcode opcode = OPCODE; static constexpr hir::Opcode opcode = OPCODE;
static const uint32_t key = static const uint32_t key =
InstrKey::Construct<OPCODE, DEST::key_type, SRC1::key_type, InstrKey::Construct<OPCODE, DEST::key_type, SRC1::key_type,
SRC2::key_type>::value; SRC2::key_type>::value;
@ -369,7 +369,7 @@ template <hir::Opcode OPCODE, typename DEST, typename SRC1, typename SRC2,
typename SRC3> typename SRC3>
struct I<OPCODE, DEST, SRC1, SRC2, SRC3> : DestField<DEST> { struct I<OPCODE, DEST, SRC1, SRC2, SRC3> : DestField<DEST> {
typedef DestField<DEST> BASE; typedef DestField<DEST> BASE;
static const hir::Opcode opcode = OPCODE; static constexpr hir::Opcode opcode = OPCODE;
static const uint32_t key = static const uint32_t key =
InstrKey::Construct<OPCODE, DEST::key_type, SRC1::key_type, InstrKey::Construct<OPCODE, DEST::key_type, SRC1::key_type,
SRC2::key_type, SRC3::key_type>::value; SRC2::key_type, SRC3::key_type>::value;

View File

@ -611,4 +611,4 @@ EMITTER_OPCODE_TABLE(OPCODE_BRANCH_FALSE, BRANCH_FALSE_I8, BRANCH_FALSE_I16,
} // namespace x64 } // namespace x64
} // namespace backend } // namespace backend
} // namespace cpu } // namespace cpu
} // namespace xe } // namespace xe

View File

@ -9,7 +9,6 @@
#include "xenia/cpu/backend/x64/x64_sequences.h" #include "xenia/cpu/backend/x64/x64_sequences.h"
#include <algorithm>
#include <cstring> #include <cstring>
#include "xenia/base/cvar.h" #include "xenia/base/cvar.h"

View File

@ -24,9 +24,7 @@
#include "xenia/cpu/backend/x64/x64_sequences.h" #include "xenia/cpu/backend/x64/x64_sequences.h"
#include <algorithm>
#include <cstring> #include <cstring>
#include <unordered_map>
#include "xenia/base/assert.h" #include "xenia/base/assert.h"
#include "xenia/base/clock.h" #include "xenia/base/clock.h"

View File

@ -95,7 +95,7 @@ class StackLayout {
}); });
static_assert(sizeof(Thunk) % 16 == 0, static_assert(sizeof(Thunk) % 16 == 0,
"sizeof(Thunk) must be a multiple of 16!"); "sizeof(Thunk) must be a multiple of 16!");
static const size_t THUNK_STACK_SIZE = sizeof(Thunk) + 8; static constexpr size_t THUNK_STACK_SIZE = sizeof(Thunk) + 8;
/** /**
* *
@ -121,16 +121,16 @@ class StackLayout {
* +------------------+ * +------------------+
* *
*/ */
static const size_t GUEST_STACK_SIZE = 104; static constexpr size_t GUEST_STACK_SIZE = 104;
// was GUEST_CTX_HOME, can't remove because that'd throw stack alignment off. // was GUEST_CTX_HOME, can't remove because that'd throw stack alignment off.
// instead, can be used as a temporary in sequences // instead, can be used as a temporary in sequences
static const size_t GUEST_SCRATCH = 0; static constexpr size_t GUEST_SCRATCH = 0;
// when profiling is on, this stores the nanosecond time at the start of the // when profiling is on, this stores the nanosecond time at the start of the
// function // function
static const size_t GUEST_PROFILER_START = 80; static constexpr size_t GUEST_PROFILER_START = 80;
static const size_t GUEST_RET_ADDR = 88; static constexpr size_t GUEST_RET_ADDR = 88;
static const size_t GUEST_CALL_RET_ADDR = 96; static constexpr size_t GUEST_CALL_RET_ADDR = 96;
}; };
} // namespace x64 } // namespace x64

View File

@ -9,8 +9,6 @@
#include "xenia/cpu/backend/x64/x64_tracers.h" #include "xenia/cpu/backend/x64/x64_tracers.h"
#include <cinttypes>
#include "xenia/base/logging.h" #include "xenia/base/logging.h"
#include "xenia/base/vec128.h" #include "xenia/base/vec128.h"
#include "xenia/cpu/backend/x64/x64_emitter.h" #include "xenia/cpu/backend/x64/x64_emitter.h"

View File

@ -122,4 +122,4 @@ void Breakpoint::ForEachHostAddress(
} }
} // namespace cpu } // namespace cpu
} // namespace xe } // namespace xe

View File

@ -133,4 +133,4 @@ class Breakpoint {
} // namespace cpu } // namespace cpu
} // namespace xe } // namespace xe
#endif // XENIA_CPU_BREAKPOINT_H_ #endif // XENIA_CPU_BREAKPOINT_H_

Some files were not shown because too many files have changed in this diff Show More