Compare commits

..

82 Commits

Author SHA1 Message Date
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
Marco Rodolfi f58fab1d2c [compiler] Misc changes to make this emulator properly compile under Linux with Clang 2025-01-19 21:37:29 +01:00
248 changed files with 9447 additions and 3557 deletions

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

@ -0,0 +1,59 @@
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)
asset=xenia_canary_windows.zip
7z a $asset './xenia_canary_windows/*'
;;
linux)
asset=xenia_canary_linux.tar.gz
cd xenia_canary_linux
chmod +x xenia_canary
tar -cvpf ../$asset *
cd -
;;
esac
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
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 $asset --clobber
else
gh release create $tag $asset --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'
- '.gitattributes'
- '.gitignore'
- '.gdbinit'
- '.github/*'
- '.github/workflows/Windows_build.yml'
- '.github/*_TEMPLATE/**'
- '*.bat'
- '*.md'
- '*.yml'
- '*.ps1'
- '*.txt'
- '*.yml'
- 'docs/**'
- 'src/**/*_windows.*'
- 'src/**/*_android.*'
@ -25,13 +26,14 @@ on:
- '.drone.star'
- '.gitattributes'
- '.gitignore'
- '.gdbinit'
- '.github/*'
- '.github/workflows/Windows_build.yml'
- '.github/*_TEMPLATE/**'
- '*.bat'
- '*.md'
- '*.yml'
- '*.ps1'
- '*.txt'
- '*.yml'
- 'docs/**'
- 'src/**/*_windows.*'
- 'src/**/*_android.*'
@ -42,36 +44,68 @@ on:
jobs:
lint:
name: Lint
runs-on: windows-latest
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@main
- name: Check Clang-Format Version
run: clang-format --version
- name: Setup
run: |
LLVM_VERSION=18 # Same as Windows
UBUNTU_BASE=jammy
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
run: ./xb lint --all
build-linux:
name: Build (Linux) # runner.os can't be used here
build:
name: Build (LLVM ${{ matrix.LLVM_VERSION }})
needs: lint
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
LLVM_VERSION: [19]
steps:
- uses: actions/checkout@main
with:
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
run: |
UBUNTU_BASE=jammy
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 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 }} llvm-${{ matrix.LLVM_VERSION }} ninja-build
./xb setup
- name: Build
env:
CC: clang-${{ matrix.LLVM_VERSION }}
CXX: clang++-${{ matrix.LLVM_VERSION }}
AR: llvm-ar-${{ matrix.LLVM_VERSION }}
run: ./xb build --config=Release
- name: Prepare artifacts
id: prepare_artifacts
run: |
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
create-release:
name: Create release
needs: [lint, build]
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:
name: Lint
runs-on: windows-latest
env:
POWERSHELL_TELEMETRY_OPTOUT: 1
steps:
- uses: actions/checkout@main
- name: Check Clang-Format Version
run: clang-format --version
- name: Lint
run: .\xb lint --all
build-windows:
name: Build (Windows, VS${{ matrix.vsver }}) # runner.os can't be used here
build:
name: Build
needs: lint
strategy:
fail-fast: false
matrix:
vsver: [2022]
runs-on: windows-${{ matrix.vsver }}
runs-on: windows-2025
env:
POWERSHELL_TELEMETRY_OPTOUT: 1
steps:
@ -84,34 +80,21 @@ jobs:
If ($LastExitCode -le 7) { echo "LastExitCode = $LastExitCode";$LastExitCode = 0 }
- name: Upload xenia canary artifacts
if: steps.prepare_artifacts.outcome == 'success'
id: upload_artifacts
uses: actions/upload-artifact@main
with:
name: xenia_canary_vs${{ matrix.vsver }}
name: xenia_canary_windows
path: artifacts\xenia_canary
if-no-files-found: error
- name: Create release
if: |
github.repository == 'xenia-canary/xenia-canary' &&
github.event.action != 'pull_request' &&
github.ref == 'refs/heads/canary_experimental' &&
steps.upload_artifacts.outcome == 'success'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
$asset="xenia_canary.zip"
rm -recurse -force artifacts\xenia_canary\*.pdb # Ideally this would use xr, but I can't get it to work
7z a $asset .\artifacts\xenia_canary\*
If ($(Get-Item $asset).length -le 100000) {
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
create-release:
name: Create release
needs: [lint, build]
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: windows
secrets:
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}

5
.gitmodules vendored
View File

@ -42,7 +42,7 @@
url = https://github.com/libsdl-org/SDL.git
[submodule "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"]
path = third_party/fmt
url = https://github.com/fmtlib/fmt.git
@ -103,3 +103,6 @@
[submodule "third_party/pugixml"]
path = third_party/pugixml
url = https://github.com/zeux/pugixml.git
[submodule "third_party/libusb"]
path = third_party/libusb
url = https://github.com/libusb/libusb.git

View File

@ -20,7 +20,7 @@ Discussing illegal activities will get you banned.
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)
Netplay Build | | [Latest](https://github.com/AdrianCassar/xenia-canary/releases/latest)

View File

@ -7,6 +7,11 @@ location(build_root)
targetdir(build_bin)
objdir(build_obj)
-- Define variables for enabling specific submodules
-- Todo: Add changing from xb command
enableTests = false
enableMiscSubprojects = false
-- Define an ARCH variable
-- Only use this to enable architecture-specific functionality.
if os.istarget("linux") then
@ -30,6 +35,8 @@ cppdialect("C++20")
exceptionhandling("On")
rtti("On")
symbols("On")
characterset("Unicode")
fatalwarnings("All")
-- TODO(DrChat): Find a way to disable this on other architectures.
if ARCH ~= "ppc64" then
@ -38,11 +45,6 @@ if ARCH ~= "ppc64" then
filter({})
end
characterset("Unicode")
flags({
"FatalWarnings", -- Treat warnings as errors.
})
filter("kind:StaticLib")
defines({
"_LIB",
@ -50,23 +52,24 @@ filter("kind:StaticLib")
filter("configurations:Checked")
runtime("Debug")
sanitize("Address")
flags("NoIncrementalLink")
editandcontinue("Off")
staticruntime("Off")
optimize("Off")
defines({
"DEBUG",
})
filter({"configurations:Checked", "platforms:Windows"})
buildoptions({
"/RTCsu", -- Full Run-Time Checks.
})
filter({"configurations:Checked", "platforms:Linux"})
defines({
"_GLIBCXX_DEBUG", -- libstdc++ debug mode
})
filter({"configurations:Release", "platforms:Windows"})
buildoptions({
"/Gw",
"/Ob3",
})
filter("configurations:Debug")
runtime("Release")
@ -75,6 +78,7 @@ filter("configurations:Debug")
"DEBUG",
"_NO_DEBUG_HEAP=1",
})
filter({"configurations:Debug", "platforms:Linux"})
defines({
"_GLIBCXX_DEBUG", -- make dbg symbols work on some distros
@ -88,19 +92,28 @@ filter("configurations:Release")
})
optimize("Speed")
inlining("Auto")
flags({
"LinkTimeOptimization",
"NoBufferSecurityCheck",
})
editandcontinue("Off")
-- Not using floatingpoint("Fast") - NaN checks are used in some places
-- (though rarely), overall preferable to avoid any functional differences
-- between debug and release builds, and to have calculations involved in GPU
-- (especially anything that may affect vertex position invariance) and CPU
-- (such as constant propagation) emulation as predictable as possible,
-- including handling of specials since games make assumptions about them.
filter({"configurations:Release", "platforms:Windows"})
linktimeoptimization("On")
flags({
"NoBufferSecurityCheck"
})
buildoptions({
"/Gw",
"/Ob3",
})
filter("platforms:Linux")
system("linux")
toolset("clang")
vectorextensions("AVX2")
buildoptions({
-- "-mlzcnt", -- (don't) Assume lzcnt is supported.
})
@ -113,9 +126,6 @@ filter("platforms:Linux")
"rt",
})
filter({"platforms:Linux"})
vectorextensions("AVX2")
filter({"platforms:Linux", "kind:*App"})
linkgroups("On")
@ -145,6 +155,7 @@ filter({"platforms:Linux", "language:C++", "toolset:clang"})
"deprecated-volatile",
"switch",
"deprecated-enum-enum-conversion",
"attributes",
})
filter({"platforms:Linux", "language:C++", "toolset:clang", "files:*.cc or *.cpp"})
buildoptions({
@ -174,16 +185,8 @@ filter("platforms:Windows")
toolset("msc")
buildoptions({
"/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
"/wd4100", -- Unreferenced parameters 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({
"MultiProcessorCompile", -- Multiprocessor compilation.
@ -275,6 +278,10 @@ workspace("xenia")
include("third_party/zlib.lua")
include("third_party/pugixml.lua")
if os.istarget("windows") then
include("third_party/libusb.lua")
end
if not os.istarget("android") then
-- 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
@ -292,9 +299,7 @@ workspace("xenia")
removefiles({
"src/xenia/base/app_win32.manifest"
})
removeflags({
"FatalWarnings",
})
removefatalwarnings("All")
end
include("src/xenia")
@ -311,6 +316,7 @@ workspace("xenia")
include("src/xenia/gpu/vulkan")
include("src/xenia/hid")
include("src/xenia/hid/nop")
include("src/xenia/hid/skylander")
include("src/xenia/kernel")
include("src/xenia/patcher")
include("src/xenia/ui")

View File

@ -167,8 +167,8 @@ using xe::ui::UIEvent;
using namespace xe::hid;
using namespace xe::gpu;
const std::string kRecentlyPlayedTitlesFilename = "recent.toml";
const std::string kBaseTitle = "Xenia-canary";
constexpr std::string_view kRecentlyPlayedTitlesFilename = "recent.toml";
constexpr std::string_view kBaseTitle = "Xenia-canary";
EmulatorWindow::EmulatorWindow(Emulator* emulator,
ui::WindowedAppContext& app_context,
@ -181,7 +181,7 @@ EmulatorWindow::EmulatorWindow(Emulator* emulator,
std::make_unique<ui::ImGuiDrawer>(window_.get(), kZOrderImGui)),
display_config_game_config_load_callback_(
new DisplayConfigGameConfigLoadCallback(*emulator, *this)) {
base_title_ = kBaseTitle +
base_title_ = std::string(kBaseTitle) +
#ifdef DEBUG
#if _NO_DEBUG_HEAP == 1
" DEBUG"
@ -569,6 +569,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() {
window_->AddListener(&window_listener_);
window_->AddInputListener(&window_listener_, kZOrderEmulatorWindowInput);
@ -935,11 +1025,16 @@ void EmulatorWindow::OnMouseUp(const ui::MouseEvent& e) {
void EmulatorWindow::TakeScreenshot() {
xe::ui::RawImage image;
imgui_drawer_->EnableNotifications(false);
if (!GetGraphicsSystemPresenter()->CaptureGuestOutput(image) ||
GetGraphicsSystemPresenter() == nullptr) {
XELOGE("Failed to capture guest output for screenshot");
return;
}
imgui_drawer_->EnableNotifications(true);
ExportScreenshot(image);
}
@ -1006,9 +1101,9 @@ void EmulatorWindow::ToggleFullscreenOnDoubleClick() {
// this function tests if user has double clicked.
// if double click was achieved the fullscreen gets toggled
const auto now = steady_clock::now(); // current mouse event time
const int16_t mouse_down_max_threshold = 250;
const int16_t mouse_up_max_threshold = 250;
const int16_t mouse_up_down_max_delta = 100;
constexpr int16_t mouse_down_max_threshold = 250;
constexpr int16_t mouse_up_max_threshold = 250;
constexpr int16_t mouse_up_down_max_delta = 100;
// 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);
@ -1083,62 +1178,27 @@ void EmulatorWindow::InstallContent() {
return;
}
using content_installation_data =
std::tuple<X_STATUS, std::string, std::string>;
std::map<XContentType, std::vector<content_installation_data>>
content_installation_details;
std::shared_ptr<std::vector<Emulator::ContentInstallEntry>>
content_installation_status =
std::make_shared<std::vector<Emulator::ContentInstallEntry>>();
for (const auto& path : paths) {
// Normalize the path and make absolute.
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});
content_installation_status->push_back({path});
}
// Prepare installation process summary message
std::string summary = "Installation result: \n";
for (auto& entry : *content_installation_status) {
emulator_->ProcessContentPackageHeader(entry.path_, entry);
}
for (const auto& content_type : content_installation_details) {
if (XContentTypeMap.find(content_type.first) != XContentTypeMap.cend()) {
summary += XContentTypeMap.at(content_type.first) + ":\n";
} else {
summary += "Unknown:\n";
auto installationThread = std::thread([this, content_installation_status] {
for (auto& entry : *content_installation_status) {
emulator_->InstallContentPackage(entry.path_, entry);
}
});
installationThread.detach();
for (const auto& content_installation_entry : content_type.second) {
const std::string 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);
new ContentInstallDialog(imgui_drawer_.get(), *this,
content_installation_status);
}
void EmulatorWindow::ExtractZarchive() {
@ -1424,6 +1484,12 @@ void EmulatorWindow::ToggleControllerVibration() {
auto input_lock = input_sys->lock();
input_sys->ToggleVibration();
if (emulator_->kernel_state()) {
emulator_->kernel_state()->BroadcastNotification(
kXNotificationSystemProfileSettingChanged,
static_cast<uint32_t>(input_sys->GetConnectedSlots().count()));
}
}
}
@ -1624,7 +1690,7 @@ EmulatorWindow::ControllerHotKey EmulatorWindow::ProcessControllerHotkey(
}
// 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
// replace the Guide button with the Back button without redeclaring the key
@ -1794,10 +1860,11 @@ EmulatorWindow::ControllerHotKey EmulatorWindow::ProcessControllerHotkey(
}
if (!notificationTitle.empty()) {
app_context_.CallInUIThread([&]() {
new xe::ui::HostNotificationWindow(imgui_drawer(), notificationTitle,
notificationDesc, 0);
});
app_context_.CallInUIThread(
[imgui_drawer = imgui_drawer(), notificationTitle, notificationDesc]() {
new xe::ui::HostNotificationWindow(imgui_drawer, notificationTitle,
notificationDesc, 0);
});
}
xe::threading::Sleep(delay);
@ -1808,7 +1875,7 @@ EmulatorWindow::ControllerHotKey EmulatorWindow::ProcessControllerHotkey(
void EmulatorWindow::VibrateController(xe::hid::InputSystem* input_sys,
uint32_t user_index,
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,
// otherwise the rumble may fail.
@ -1830,7 +1897,7 @@ void EmulatorWindow::VibrateController(xe::hid::InputSystem* input_sys,
void EmulatorWindow::GamepadHotKeys() {
X_INPUT_STATE state;
const std::chrono::milliseconds thread_delay(75);
constexpr std::chrono::milliseconds thread_delay(75);
auto input_sys = emulator_->input_system();
@ -1889,8 +1956,7 @@ void EmulatorWindow::DisplayHotKeysConfig() {
if (!guide_enabled) {
pretty_text = std::regex_replace(
pretty_text,
std::regex("Guide", std::regex_constants::syntax_option_type::icase),
pretty_text, std::regex("Guide", std::regex_constants::icase),
"Back");
}

View File

@ -167,6 +167,34 @@ class EmulatorWindow {
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 {
public:
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
-- emulator windowed app.
kind("SharedLib")
links({
"xenia-gpu-vulkan-trace-viewer",
"xenia-hid-demo",
"xenia-ui-window-vulkan-demo",
})
if enableMiscSubprojects then
links({
"xenia-gpu-vulkan-trace-viewer",
"xenia-hid-demo",
"xenia-ui-window-vulkan-demo",
})
end
filter(NOT_SINGLE_LIBRARY_FILTER)
kind("WindowedApp")
@ -114,15 +116,13 @@ project("xenia-app")
"xenia-ui-d3d12",
})
filter({"platforms:Windows", SINGLE_LIBRARY_FILTER})
links({
"xenia-gpu-d3d12-trace-viewer",
"xenia-ui-window-d3d12-demo",
})
-- filter({"configurations:Release", "platforms:Windows"})
-- buildoptions({
-- "/O1",
-- })
if enableMiscSubprojects then
filter({"platforms:Windows", SINGLE_LIBRARY_FILTER})
links({
"xenia-gpu-d3d12-trace-viewer",
"xenia-ui-window-d3d12-demo",
})
end
filter("platforms:Windows")
-- Only create the .user file if it doesn't already exist.

View File

@ -95,9 +95,15 @@ UPDATE_from_bool(mount_cache, 2024, 8, 31, 20, false);
DEFINE_transient_path(target, "",
"Specifies the target .xex or .iso to execute.",
"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,
"Specifies if Xenia should run in portable mode.",
"General");
#endif
DECLARE_bool(debug);
@ -421,7 +427,7 @@ bool EmulatorApp::OnInitialize() {
if (!cvars::portable &&
!std::filesystem::exists(storage_root / "portable.txt")) {
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";
#else
// TODO(Triang3l): Point to the app's external storage "files" directory

View File

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

View File

@ -10,6 +10,7 @@
#ifndef XENIA_APU_AUDIO_MEDIA_PLAYER_H_
#define XENIA_APU_AUDIO_MEDIA_PLAYER_H_
#include "xenia/apu/audio_driver.h"
#include "xenia/apu/audio_system.h"
#include "xenia/kernel/xam/apps/xmp_app.h"

View File

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

View File

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

View File

@ -106,7 +106,7 @@ class XAudio2AudioDriver : public AudioDriver {
uint32_t frame_size_;
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];
uint32_t current_frame_ = 0;

View File

@ -160,23 +160,23 @@ static_assert_size(Xma2ExtraData, 34);
class XmaContext {
public:
static const uint32_t kBytesPerPacket = 2048;
static const uint32_t kBitsPerPacket = kBytesPerPacket * 8;
static const uint32_t kBitsPerHeader = 32;
static constexpr uint32_t kBytesPerPacket = 2048;
static constexpr uint32_t kBitsPerPacket = kBytesPerPacket * 8;
static constexpr uint32_t kBitsPerHeader = 32;
static const uint32_t kBytesPerSample = 2;
static const uint32_t kSamplesPerFrame = 512;
static const uint32_t kSamplesPerSubframe = 128;
static const uint32_t kBytesPerFrameChannel =
static constexpr uint32_t kBytesPerSample = 2;
static constexpr uint32_t kSamplesPerFrame = 512;
static constexpr uint32_t kSamplesPerSubframe = 128;
static constexpr uint32_t kBytesPerFrameChannel =
kSamplesPerFrame * kBytesPerSample;
static const uint32_t kBytesPerSubframeChannel =
static constexpr uint32_t kBytesPerSubframeChannel =
kSamplesPerSubframe * kBytesPerSample;
// static const uint32_t kOutputBytesPerBlock = 256;
// static const uint32_t kOutputMaxSizeBytes = 31 * kOutputBytesPerBlock;
explicit XmaContext();
~XmaContext();
virtual ~XmaContext();
virtual int Setup(uint32_t id, Memory* memory, uint32_t guest_ptr) {
return 0;

View File

@ -45,28 +45,28 @@ static constexpr int kIdToSampleRate[4] = {24000, 32000, 44100, 48000};
class XmaContextNew : public XmaContext {
public:
static const uint32_t kBytesPerPacket = 2048;
static const uint32_t kBytesPerPacketHeader = 4;
static const uint32_t kBytesPerPacketData =
static constexpr uint32_t kBytesPerPacket = 2048;
static constexpr uint32_t kBytesPerPacketHeader = 4;
static constexpr uint32_t kBytesPerPacketData =
kBytesPerPacket - kBytesPerPacketHeader;
static const uint32_t kBitsPerPacket = kBytesPerPacket * 8;
static const uint32_t kBitsPerPacketHeader = 32;
static const uint32_t kBitsPerFrameHeader = 15;
static constexpr uint32_t kBitsPerPacket = kBytesPerPacket * 8;
static constexpr uint32_t kBitsPerPacketHeader = 32;
static constexpr uint32_t kBitsPerFrameHeader = 15;
static const uint32_t kBytesPerSample = 2;
static const uint32_t kSamplesPerFrame = 512;
static const uint32_t kSamplesPerSubframe = 128;
static const uint32_t kBytesPerFrameChannel =
static constexpr uint32_t kBytesPerSample = 2;
static constexpr uint32_t kSamplesPerFrame = 512;
static constexpr uint32_t kSamplesPerSubframe = 128;
static constexpr uint32_t kBytesPerFrameChannel =
kSamplesPerFrame * kBytesPerSample;
static const uint32_t kBytesPerSubframeChannel =
static constexpr uint32_t kBytesPerSubframeChannel =
kSamplesPerSubframe * kBytesPerSample;
static const uint32_t kOutputBytesPerBlock = 256;
static const uint32_t kOutputMaxSizeBytes = 31 * kOutputBytesPerBlock;
static constexpr uint32_t kOutputBytesPerBlock = 256;
static constexpr uint32_t kOutputMaxSizeBytes = 31 * kOutputBytesPerBlock;
static const uint32_t kLastFrameMarker = 0x7FFF;
static const uint32_t kMaxFrameSizeinBits = 0x4000 - kBitsPerPacketHeader;
static constexpr uint32_t kLastFrameMarker = 0x7FFF;
static constexpr uint32_t kMaxFrameSizeinBits = 0x4000 - kBitsPerPacketHeader;
explicit XmaContextNew();
~XmaContextNew();

View File

@ -18,7 +18,7 @@ namespace xe {
namespace apu {
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
// packets

View File

@ -32,7 +32,7 @@ class XmaRegisterFile {
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 operator[](uint32_t reg) const { return values[reg]; }

View File

@ -46,8 +46,8 @@ class BitMap {
std::vector<uint64_t>& data() { return data_; }
private:
const static size_t kDataSize = 8;
const static size_t kDataSizeBits = kDataSize * 8;
constexpr static size_t kDataSize = 8;
constexpr static size_t kDataSizeBits = kDataSize * 8;
std::vector<uint64_t> data_;
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));
}
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_last = last / block_bits;
size_t range_start = SIZE_MAX;
@ -80,7 +80,7 @@ void SetRange(Block* bits, size_t first, size_t length) {
return;
}
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_last = last / block_bits;
Block set_first = ~((Block(1) << (first & (block_bits - 1))) - 1);

View File

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

View File

@ -9,7 +9,7 @@
#include "xenia/base/cvar.h"
#include <iostream>
#define UTF_CPP_CPLUSPLUS 201703L
#define UTF_CPP_CPLUSPLUS 202002L
#include "third_party/utfcpp/source/utf8.h"
#include "xenia/base/console.h"
@ -125,9 +125,9 @@ std::string EscapeBasicString(const std::string_view view) {
result += "\\\\";
} else if (c < 0x20 || c == 0x7F) {
if (c <= 0xFFFF) {
result += fmt::format("\\u{:04X}", c);
result += fmt::format("\\u{:04X}", static_cast<uint32_t>(c));
} else {
result += fmt::format("\\u{:08X}", c);
result += fmt::format("\\u{:08X}", static_cast<uint32_t>(c));
}
} else {
utfcpp::append(static_cast<char32_t>(c), result);
@ -159,7 +159,7 @@ std::string EscapeMultilineBasicString(const std::string_view view) {
if (c == '\b') {
result += "\\b";
} else if (c == '\t' || c == '\n') {
result += c;
result += static_cast<uint32_t>(c);
} else if (c == '\f') {
result += "\\f";
} else if (c == '\r') {
@ -171,9 +171,9 @@ std::string EscapeMultilineBasicString(const std::string_view view) {
result += "\\\\";
} else if (c < 0x20 || c == 0x7F) {
if (c <= 0xFFFF) {
result += fmt::format("\\u{:04X}", c);
result += fmt::format("\\u{:04X}", static_cast<uint32_t>(c));
} else {
result += fmt::format("\\u{:08X}", c);
result += fmt::format("\\u{:08X}", static_cast<uint32_t>(c));
}
} else {
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) {
const auto multiline_chars = std::string_view("\r\n");
const auto escape_chars = std::string_view(
constexpr auto multiline_chars = std::string_view("\r\n");
constexpr auto escape_chars = std::string_view(
"\0\b\v\f"
"\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"

View File

@ -168,7 +168,7 @@ static void ExceptionHandlerCallback(int signal_number, siginfo_t* signal_info,
mcontext.gregs[REG_EFL] = greg_t(thread_context.eflags);
uint32_t modified_register_index;
// 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_RSI, REG_RDI, REG_R8, REG_R9, REG_R10, REG_R11,
REG_R12, REG_R13, REG_R14, REG_R15,

View File

@ -24,5 +24,42 @@ bool CreateParentFolder(const std::filesystem::path& path) {
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 xe

View File

@ -45,6 +45,10 @@ std::filesystem::path GetUserFolder();
// attempting to create it.
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.
bool CreateEmptyFile(const std::filesystem::path& path);
@ -65,14 +69,14 @@ bool TruncateStdioFile(FILE* file, uint64_t length);
struct FileAccess {
// Implies kFileReadData.
static const uint32_t kGenericRead = 0x80000000;
static constexpr uint32_t kGenericRead = 0x80000000;
// Implies kFileWriteData.
static const uint32_t kGenericWrite = 0x40000000;
static const uint32_t kGenericExecute = 0x20000000;
static const uint32_t kGenericAll = 0x10000000;
static const uint32_t kFileReadData = 0x00000001;
static const uint32_t kFileWriteData = 0x00000002;
static const uint32_t kFileAppendData = 0x00000004;
static constexpr uint32_t kGenericWrite = 0x40000000;
static constexpr uint32_t kGenericExecute = 0x20000000;
static constexpr uint32_t kGenericAll = 0x10000000;
static constexpr uint32_t kFileReadData = 0x00000001;
static constexpr uint32_t kFileWriteData = 0x00000002;
static constexpr uint32_t kFileAppendData = 0x00000004;
};
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
// starting from content: (as this is the main purpose of this code -
// 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;
return source.size() >= kContentSchemaLength &&
!xe_strncasecmp(source.data(), kContentSchema, kContentSchemaLength);

View File

@ -192,20 +192,26 @@ std::unique_ptr<FileHandle> FileHandle::OpenExisting(
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;
if (stat(path.c_str(), &st) == 0) {
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 {
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);
out_info->access_timestamp = convertUnixtimeToWinFiletime(st.st_atime);
out_info->write_timestamp = convertUnixtimeToWinFiletime(st.st_mtime);
return true;
info.path = path.parent_path();
info.name = path.filename();
info.create_timestamp = convertUnixtimeToWinFiletime(st.st_ctime);
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) {
@ -240,7 +246,7 @@ std::vector<FileInfo> ListFiles(const std::filesystem::path& path) {
result.push_back(info);
}
closedir(dir);
return result;
return std::move(result);
}
bool SetAttributes(const std::filesystem::path& path, uint64_t attributes) {

View File

@ -263,30 +263,6 @@ std::vector<FileInfo> ListFiles(const std::filesystem::path& path) {
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) {
return SetFileAttributes(path.c_str(), static_cast<DWORD>(attributes));
}

View File

@ -14,23 +14,23 @@
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;
}
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;
}
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;
}
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;
}
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;
}

View File

@ -244,12 +244,12 @@ class Logger {
}
private:
static const size_t kBufferSize = 8_MiB;
static constexpr size_t kBufferSize = 8_MiB;
uint8_t buffer_[kBufferSize];
static const size_t kBlockSize = 256;
static const size_t kBlockCount = kBufferSize / kBlockSize;
static const size_t kBlockIndexMask = kBlockCount - 1;
static constexpr size_t kBlockSize = 256;
static constexpr size_t kBlockCount = kBufferSize / kBlockSize;
static constexpr size_t kBlockIndexMask = kBlockCount - 1;
static const size_t kClaimStrategyFootprint =
sizeof(std::atomic<dp::sequence_t>[kBlockCount]);
@ -353,14 +353,14 @@ class Logger {
? line_range.second[line_range.second_length - 1]
: line_range.first[line_range.first_length - 1];
if (last_char != '\n') {
const char suffix[1] = {'\n'};
constexpr char suffix[1] = {'\n'};
Write(suffix, 1);
}
rb.EndRead(std::move(line_range));
} else {
// Always ensure there is a newline.
const char suffix[1] = {'\n'};
constexpr char suffix[1] = {'\n'};
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

@ -60,7 +60,7 @@ static void RequestWin32HighResolutionTimer() {
ULONG minimum_resolution, maximum_resolution, current_resolution;
nt_query_timer_resolution(&minimum_resolution, &maximum_resolution,
&current_resolution);
nt_set_timer_resolution(maximum_resolution, TRUE, &current_resolution);
nt_set_timer_resolution(maximum_resolution, true, &current_resolution);
}
static void RequestWin32MMCSS() {
@ -74,7 +74,7 @@ static void RequestWin32MMCSS() {
dwm_enable_mmcss = reinterpret_cast<decltype(dwm_enable_mmcss)>(
GetProcAddress(dwmapi_module, "DwmEnableMMCSS"));
if (dwm_enable_mmcss) {
dwm_enable_mmcss(TRUE);
dwm_enable_mmcss(true);
}
FreeLibrary(dwmapi_module);
}

View File

@ -29,7 +29,7 @@ class Win32MappedMemory : public MappedMemory {
public:
// CreateFile returns INVALID_HANDLE_VALUE in case of failure.
// 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.
static constexpr HANDLE kMappingHandleInvalid = nullptr;

View File

@ -473,7 +473,7 @@ void copy_and_swap_16_unaligned(void* dst_ptr, const void* src_ptr,
auto dst = reinterpret_cast<uint8_t*>(dst_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)),
vcreate_u8(UINT64_C(0x0E0F0C0D0A0B0809)));
@ -507,7 +507,7 @@ void copy_and_swap_32_unaligned(void* dst_ptr, const void* src_ptr,
auto dst = reinterpret_cast<uint8_t*>(dst_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)),
vcreate_u8(UINT64_C(0x0C0D0E0F08090A0B)));
@ -539,7 +539,7 @@ void copy_and_swap_64_unaligned(void* dst_ptr, const void* src_ptr,
auto dst = reinterpret_cast<uint8_t*>(dst_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)),
vcreate_u8(UINT64_C(0x08090A0B0C0D0E0F)));

View File

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

View File

@ -13,6 +13,9 @@
#include <sys/mman.h>
#include <unistd.h>
#include <cstddef>
#include <fstream>
#include <mutex>
#include <sstream>
#include "xenia/base/math.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; }
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,
AllocationType allocation_type, PageAccess access) {
// mmap does not support reserve / commit, so ignore allocation_type.
uint32_t prot = ToPosixProtectFlags(access);
int flags = 0;
int flags = MAP_PRIVATE | MAP_ANONYMOUS;
if (base_address != nullptr) {
flags = MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS;
} else {
flags = MAP_PRIVATE | MAP_ANONYMOUS;
if (allocation_type == AllocationType::kCommit) {
if (Protect(base_address, length, access)) {
return base_address;
}
return nullptr;
}
flags |= MAP_FIXED_NOREPLACE;
}
void* result = mmap(base_address, length, prot, flags, -1, 0);
if (result != MAP_FAILED) {
return result;
}
@ -100,19 +134,90 @@ void* AllocFixed(void* base_address, size_t length,
bool DeallocFixed(void* base_address, size_t length,
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,
PageAccess* out_old_access) {
// Linux does not have a syscall to query memory permissions.
assert_null(out_old_access);
if (out_old_access) {
size_t length_copy = length;
QueryProtect(base_address, length_copy, *out_old_access);
}
uint32_t prot = ToPosixProtectFlags(access);
return mprotect(base_address, length, prot) == 0;
}
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;
}
@ -182,12 +287,41 @@ void CloseFileMappingHandle(FileMappingHandle handle,
void* MapFileView(FileMappingHandle handle, void* base_address, size_t length,
PageAccess access, size_t file_offset) {
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,
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;
}

View File

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

View File

@ -17,4 +17,6 @@ project("xenia-base")
"debug_visualizers.natvis",
})
include("testing")
if enableTests then
include("testing")
end

View File

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

View File

@ -22,7 +22,7 @@
#include <strings.h>
#endif // !XE_PLATFORM_WIN32
#define UTF_CPP_CPLUSPLUS 201703L
#define UTF_CPP_CPLUSPLUS 202002L
#include "third_party/utfcpp/source/utf8.h"
namespace utfcpp = utf8;

View File

@ -16,6 +16,7 @@
#include <cstring>
#include <regex>
#include <string>
#include <variant>
#include "third_party/fmt/include/fmt/format.h"
#include "xenia/base/assert.h"
@ -428,6 +429,28 @@ inline vec128_t from_string<vec128_t>(const std::string_view value,
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 xe

View File

@ -65,8 +65,8 @@ bool SetProcessPriorityClass(const uint32_t priority_class) {
}
bool IsUseNexusForGameBarEnabled() {
const LPCWSTR reg_path = L"SOFTWARE\\Microsoft\\GameBar";
const LPCWSTR key = L"UseNexusForGameBarEnabled";
constexpr LPCWSTR reg_path = L"SOFTWARE\\Microsoft\\GameBar";
constexpr LPCWSTR key = L"UseNexusForGameBarEnabled";
DWORD value = 0;
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]") {
auto path = fmt::format("xenia_test_{}", Clock::QueryHostTickCount());
const size_t length = 0x100;
constexpr size_t length = 0x100;
auto memory = xe::memory::CreateFileMappingHandle(
path, length, xe::memory::PageAccess::kReadWrite, true);
REQUIRE(memory != xe::memory::kFileMappingHandleInvalid);
@ -532,7 +532,7 @@ TEST_CASE("map_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 memory = xe::memory::CreateFileMappingHandle(
path, length, xe::memory::PageAccess::kReadWrite, true);

View File

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

View File

@ -82,8 +82,7 @@ void AndroidShutdown() {
#endif
template <typename _Rep, typename _Period>
inline timespec DurationToTimeSpec(
std::chrono::duration<_Rep, _Period> duration) {
timespec DurationToTimeSpec(std::chrono::duration<_Rep, _Period> duration) {
auto nanoseconds =
std::chrono::duration_cast<std::chrono::nanoseconds>(duration);
auto div = ldiv(nanoseconds.count(), 1000000000L);
@ -161,6 +160,8 @@ void Sleep(std::chrono::microseconds duration) {
} 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
thread_local bool alertable_state_ = false;
SleepResult AlertableSleep(std::chrono::microseconds duration) {
@ -178,28 +179,25 @@ TlsHandle AllocateTlsHandle() {
return static_cast<TlsHandle>(key);
}
bool FreeTlsHandle(TlsHandle handle) {
return pthread_key_delete(static_cast<pthread_key_t>(handle)) == 0;
}
bool FreeTlsHandle(TlsHandle handle) { return pthread_key_delete(handle) == 0; }
uintptr_t GetTlsValue(TlsHandle handle) {
return reinterpret_cast<uintptr_t>(
pthread_getspecific(static_cast<pthread_key_t>(handle)));
return reinterpret_cast<uintptr_t>(pthread_getspecific(handle));
}
bool SetTlsValue(TlsHandle handle, uintptr_t value) {
return pthread_setspecific(static_cast<pthread_key_t>(handle),
reinterpret_cast<void*>(value)) == 0;
return pthread_setspecific(handle, reinterpret_cast<void*>(value)) == 0;
}
class PosixConditionBase {
public:
virtual ~PosixConditionBase() = default;
virtual bool Signal() = 0;
WaitResult Wait(std::chrono::milliseconds timeout) {
bool executed;
auto predicate = [this] { return this->signaled(); };
auto lock = std::unique_lock<std::mutex>(mutex_);
auto lock = std::unique_lock(mutex_);
if (predicate()) {
executed = true;
} else {
@ -213,15 +211,14 @@ class PosixConditionBase {
if (executed) {
post_execution();
return WaitResult::kSuccess;
} else {
return WaitResult::kTimeout;
}
return WaitResult::kTimeout;
}
static std::pair<WaitResult, size_t> WaitMultiple(
std::vector<PosixConditionBase*>&& handles, bool wait_all,
std::chrono::milliseconds timeout) {
assert_true(handles.size() > 0);
assert_true(!handles.empty());
// Construct a condition for all or any depending on wait_all
std::function<bool()> predicate;
@ -239,17 +236,16 @@ class PosixConditionBase {
// TODO(bwrsandman, Triang3l) This is controversial, see issue #1677
// This will probably cause a deadlock on the next thread doing any 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;
// If the timeout is infinite, wait without timeout.
// The predicate will be checked before beginning the wait
if (timeout == std::chrono::milliseconds::max()) {
PosixConditionBase::cond_.wait(lock, predicate);
cond_.wait(lock, predicate);
} else {
// Wait with timeout.
wait_success =
PosixConditionBase::cond_.wait_for(lock, timeout, predicate);
wait_success = cond_.wait_for(lock, timeout, predicate);
}
if (wait_success) {
auto first_signaled = std::numeric_limits<size_t>::max();
@ -264,15 +260,16 @@ class PosixConditionBase {
}
assert_true(std::numeric_limits<size_t>::max() != 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:
inline virtual bool signaled() const = 0;
[[nodiscard]] inline virtual bool signaled() const = 0;
inline virtual void post_execution() = 0;
static std::condition_variable cond_;
static std::mutex mutex_;
@ -293,23 +290,23 @@ class PosixCondition<Event> : public PosixConditionBase {
public:
PosixCondition(bool manual_reset, bool initial_state)
: signal_(initial_state), manual_reset_(manual_reset) {}
virtual ~PosixCondition() = default;
~PosixCondition() override = default;
bool Signal() override {
auto lock = std::unique_lock<std::mutex>(mutex_);
auto lock = std::unique_lock(mutex_);
signal_ = true;
cond_.notify_all();
return true;
}
void Reset() {
auto lock = std::unique_lock<std::mutex>(mutex_);
auto lock = std::unique_lock(mutex_);
signal_ = false;
}
private:
inline bool signaled() const override { return signal_; }
inline void post_execution() override {
[[nodiscard]] bool signaled() const override { return signal_; }
void post_execution() override {
if (!manual_reset_) {
signal_ = false;
}
@ -319,7 +316,7 @@ class PosixCondition<Event> : public PosixConditionBase {
};
template <>
class PosixCondition<Semaphore> : public PosixConditionBase {
class PosixCondition<Semaphore> final : public PosixConditionBase {
public:
PosixCondition(uint32_t initial_count, uint32_t maximum_count)
: count_(initial_count), maximum_count_(maximum_count) {}
@ -328,7 +325,7 @@ class PosixCondition<Semaphore> : public PosixConditionBase {
bool Release(uint32_t release_count, int* out_previous_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_;
count_ += release_count;
cond_.notify_all();
@ -338,8 +335,8 @@ class PosixCondition<Semaphore> : public PosixConditionBase {
}
private:
inline bool signaled() const override { return count_ > 0; }
inline void post_execution() override {
[[nodiscard]] bool signaled() const override { return count_ > 0; }
void post_execution() override {
count_--;
cond_.notify_all();
}
@ -348,7 +345,7 @@ class PosixCondition<Semaphore> : public PosixConditionBase {
};
template <>
class PosixCondition<Mutant> : public PosixConditionBase {
class PosixCondition<Mutant> final : public PosixConditionBase {
public:
explicit PosixCondition(bool initial_owner) : count_(0) {
if (initial_owner) {
@ -361,7 +358,7 @@ class PosixCondition<Mutant> : public PosixConditionBase {
bool Release() {
if (owner_ == std::this_thread::get_id() && count_ > 0) {
auto lock = std::unique_lock<std::mutex>(mutex_);
auto lock = std::unique_lock(mutex_);
--count_;
// Free to be acquired by another thread
if (count_ == 0) {
@ -372,13 +369,15 @@ class PosixCondition<Mutant> : public PosixConditionBase {
return false;
}
void* native_handle() const override { return mutex_.native_handle(); }
[[nodiscard]] void* native_handle() const override {
return mutex_.native_handle();
}
private:
inline bool signaled() const override {
[[nodiscard]] bool signaled() const override {
return count_ == 0 || owner_ == std::this_thread::get_id();
}
inline void post_execution() override {
void post_execution() override {
count_++;
owner_ = std::this_thread::get_id();
}
@ -387,15 +386,15 @@ class PosixCondition<Mutant> : public PosixConditionBase {
};
template <>
class PosixCondition<Timer> : public PosixConditionBase {
class PosixCondition<Timer> final : public PosixConditionBase {
public:
explicit PosixCondition(bool manual_reset)
: callback_(nullptr), signal_(false), manual_reset_(manual_reset) {}
virtual ~PosixCondition() { Cancel(); }
~PosixCondition() override { Cancel(); }
bool Signal() override {
std::lock_guard<std::mutex> lock(mutex_);
std::lock_guard lock(mutex_);
signal_ = true;
cond_.notify_all();
return true;
@ -405,7 +404,7 @@ class PosixCondition<Timer> : public PosixConditionBase {
std::function<void()> opt_callback) {
Cancel();
std::lock_guard<std::mutex> lock(mutex_);
std::lock_guard lock(mutex_);
callback_ = std::move(opt_callback);
signal_ = false;
@ -417,7 +416,7 @@ class PosixCondition<Timer> : public PosixConditionBase {
std::function<void()> opt_callback) {
Cancel();
std::lock_guard<std::mutex> lock(mutex_);
std::lock_guard lock(mutex_);
callback_ = std::move(opt_callback);
signal_ = false;
@ -425,13 +424,13 @@ class PosixCondition<Timer> : public PosixConditionBase {
QueueTimerRecurring(&CompletionRoutine, this, due_time, period);
}
void Cancel() {
void Cancel() const {
if (auto wait_item = wait_item_.lock()) {
wait_item->Disarm();
}
}
void* native_handle() const override {
[[nodiscard]] void* native_handle() const override {
assert_always();
return nullptr;
}
@ -439,12 +438,12 @@ class PosixCondition<Timer> : public PosixConditionBase {
private:
static void CompletionRoutine(void* userdata) {
assert_not_null(userdata);
auto timer = reinterpret_cast<PosixCondition<Timer>*>(userdata);
auto timer = static_cast<PosixCondition*>(userdata);
timer->Signal();
// As the callback may reset the timer, store local.
std::function<void()> callback;
{
std::lock_guard<std::mutex> lock(timer->mutex_);
std::lock_guard lock(timer->mutex_);
callback = timer->callback_;
}
if (callback) {
@ -452,9 +451,8 @@ class PosixCondition<Timer> : public PosixConditionBase {
}
}
private:
inline bool signaled() const override { return signal_; }
inline void post_execution() override {
[[nodiscard]] bool signaled() const override { return signal_; }
void post_execution() override {
if (!manual_reset_) {
signal_ = false;
}
@ -472,7 +470,7 @@ struct ThreadStartData {
};
template <>
class PosixCondition<Thread> : public PosixConditionBase {
class PosixCondition<Thread> final : public PosixConditionBase {
enum class State {
kUninitialized,
kRunning,
@ -526,13 +524,18 @@ class PosixCondition<Thread> : public PosixConditionBase {
: thread_(thread),
signaled_(false),
exit_code_(0),
state_(State::kRunning) {
state_(State::kRunning),
suspend_count_(0) {
#if XE_PLATFORM_ANDROID
android_pre_api_26_name_[0] = '\0';
#endif
}
virtual ~PosixCondition() {
~PosixCondition() override {
// FIXME(RodoMa92): This causes random crashes.
// The proper way to handle them according to the webs is properly shutdown
// instead on relying on killing them using pthread_cancel.
/*
if (thread_ && !signaled_) {
#if XE_PLATFORM_ANDROID
if (pthread_kill(thread_,
@ -548,6 +551,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
assert_always();
}
}
*/
}
bool Signal() override { return true; }
@ -555,7 +559,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
std::string name() const {
WaitStarted();
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 XE_PLATFORM_ANDROID
// pthread_getname_np was added in API 26 - below that, store the name in
@ -579,7 +583,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
return std::string(result.data());
}
void set_name(const std::string& name) {
void set_name(const std::string& name) const {
WaitStarted();
std::unique_lock<std::mutex> lock(state_mutex_);
if (state_ != State::kUninitialized && state_ != State::kFinished) {
@ -603,7 +607,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
uint32_t system_id() const { return static_cast<uint32_t>(thread_); }
uint64_t affinity_mask() {
uint64_t affinity_mask() const {
WaitStarted();
cpu_set_t cpu_set;
#if XE_PLATFORM_ANDROID
@ -625,7 +629,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
return result;
}
void set_affinity_mask(uint64_t mask) {
void set_affinity_mask(uint64_t mask) const {
WaitStarted();
cpu_set_t cpu_set;
CPU_ZERO(&cpu_set);
@ -646,7 +650,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
#endif
}
int priority() {
int priority() const {
WaitStarted();
int policy;
sched_param param{};
@ -658,7 +662,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
return param.sched_priority;
}
void set_priority(int new_priority) {
void set_priority(int new_priority) const {
WaitStarted();
sched_param param{};
param.sched_priority = new_priority;
@ -678,7 +682,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
void QueueUserCallback(std::function<void()> callback) {
WaitStarted();
std::unique_lock<std::mutex> lock(callback_mutex_);
std::unique_lock lock(callback_mutex_);
user_callback_ = std::move(callback);
sigval value{};
value.sival_ptr = this;
@ -691,8 +695,8 @@ class PosixCondition<Thread> : public PosixConditionBase {
#endif
}
void CallUserCallback() {
std::unique_lock<std::mutex> lock(callback_mutex_);
void CallUserCallback() const {
std::unique_lock lock(callback_mutex_);
user_callback_();
}
@ -701,7 +705,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
*out_previous_suspend_count = 0;
}
WaitStarted();
std::unique_lock<std::mutex> lock(state_mutex_);
std::unique_lock lock(state_mutex_);
if (state_ != State::kSuspended) return false;
if (out_previous_suspend_count) {
*out_previous_suspend_count = suspend_count_;
@ -731,7 +735,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
void Terminate(int exit_code) {
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 (is_current_thread) {
// This is really bad. Some thread must have called Terminate() on us
@ -747,7 +751,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
}
{
std::lock_guard<std::mutex> lock(mutex_);
std::lock_guard lock(mutex_);
exit_code_ = exit_code;
signaled_ = true;
@ -755,29 +759,28 @@ class PosixCondition<Thread> : public PosixConditionBase {
}
if (is_current_thread) {
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 {
std::unique_lock<std::mutex> lock(state_mutex_);
std::unique_lock lock(state_mutex_);
state_signal_.wait(lock,
[this] { return state_ != State::kUninitialized; });
}
/// Set state to suspended and wait until it reset by another thread
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_ = State::kRunning;
}
@ -788,8 +791,8 @@ class PosixCondition<Thread> : public PosixConditionBase {
private:
static void* ThreadStartRoutine(void* parameter);
inline bool signaled() const override { return signaled_; }
inline void post_execution() override {
bool signaled() const override { return signaled_; }
void post_execution() override {
if (thread_) {
pthread_join(thread_, nullptr);
}
@ -813,6 +816,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
class PosixWaitHandle {
public:
virtual ~PosixWaitHandle() = default;
virtual PosixConditionBase& condition() = 0;
};
@ -829,7 +833,9 @@ class PosixConditionHandle : public T, public PosixWaitHandle {
~PosixConditionHandle() override = default;
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:
PosixCondition<T> handle_;
@ -910,7 +916,7 @@ std::pair<WaitResult, size_t> WaitMultiple(WaitHandle* wait_handles[],
return result;
}
class PosixEvent : public PosixConditionHandle<Event> {
class PosixEvent final : public PosixConditionHandle<Event> {
public:
PosixEvent(bool manual_reset, bool initial_state)
: PosixConditionHandle(manual_reset, initial_state) {}
@ -939,7 +945,7 @@ std::unique_ptr<Event> Event::CreateAutoResetEvent(bool initial_state) {
return std::make_unique<PosixEvent>(false, initial_state);
}
class PosixSemaphore : public PosixConditionHandle<Semaphore> {
class PosixSemaphore final : public PosixConditionHandle<Semaphore> {
public:
PosixSemaphore(int initial_count, int maximum_count)
: PosixConditionHandle(static_cast<uint32_t>(initial_count),
@ -963,7 +969,7 @@ std::unique_ptr<Semaphore> Semaphore::Create(int initial_count,
return std::make_unique<PosixSemaphore>(initial_count, maximum_count);
}
class PosixMutant : public PosixConditionHandle<Mutant> {
class PosixMutant final : public PosixConditionHandle<Mutant> {
public:
explicit PosixMutant(bool initial_owner)
: PosixConditionHandle(initial_owner) {}
@ -975,9 +981,9 @@ std::unique_ptr<Mutant> Mutant::Create(bool initial_owner) {
return std::make_unique<PosixMutant>(initial_owner);
}
class PosixTimer : public PosixConditionHandle<Timer> {
using WClock_ = Timer::WClock_;
using GClock_ = Timer::GClock_;
class PosixTimer final : public PosixConditionHandle<Timer> {
using WClock_ = WClock_;
using GClock_ = GClock_;
public:
explicit PosixTimer(bool manual_reset) : PosixConditionHandle(manual_reset) {}
@ -1030,7 +1036,7 @@ std::unique_ptr<Timer> Timer::CreateSynchronizationTimer() {
return std::make_unique<PosixTimer>(false);
}
class PosixThread : public PosixConditionHandle<Thread> {
class PosixThread final : public PosixConditionHandle<Thread> {
public:
PosixThread() = default;
explicit PosixThread(pthread_t thread) : PosixConditionHandle(thread) {}
@ -1102,14 +1108,14 @@ void* PosixCondition<Thread>::ThreadStartRoutine(void* parameter) {
current_thread_ = thread;
{
std::unique_lock<std::mutex> lock(thread->handle_.state_mutex_);
std::unique_lock lock(thread->handle_.state_mutex_);
thread->handle_.state_ =
create_suspended ? State::kSuspended : State::kRunning;
thread->handle_.state_signal_.notify_all();
}
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_.state_signal_.wait(
lock, [thread] { return thread->handle_.suspend_count_ == 0; });
@ -1118,11 +1124,11 @@ void* PosixCondition<Thread>::ThreadStartRoutine(void* parameter) {
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;
}
std::unique_lock<std::mutex> lock(mutex_);
std::unique_lock lock(mutex_);
thread->handle_.exit_code_ = 0;
thread->handle_.signaled_ = true;
cond_.notify_all();

View File

@ -170,7 +170,7 @@ void Sleep(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) {
return SleepResult::kAlerted;
}
@ -211,7 +211,7 @@ WaitResult Wait(WaitHandle* wait_handle, bool is_alertable,
HANDLE handle = wait_handle->native_handle();
DWORD result;
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
// alertable, just need to study whether
// 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();
DWORD result =
SignalObjectAndWait(handle_to_signal, handle_to_wait_on,
DWORD(timeout.count()), is_alertable ? TRUE : FALSE);
DWORD(timeout.count()), is_alertable ? true : false);
switch (result) {
case WAIT_OBJECT_0:
return WaitResult::kSuccess;
@ -278,8 +278,8 @@ std::pair<WaitResult, size_t> WaitMultiple(WaitHandle* wait_handles[],
handles[i] = wait_handles[i]->native_handle();
}
DWORD result = WaitForMultipleObjectsEx(
static_cast<DWORD>(wait_handle_count), handles, wait_all ? TRUE : FALSE,
DWORD(timeout.count()), is_alertable ? TRUE : FALSE);
static_cast<DWORD>(wait_handle_count), handles, wait_all ? true : false,
DWORD(timeout.count()), is_alertable ? true : false);
if (result >= WAIT_OBJECT_0 && result < WAIT_OBJECT_0 + wait_handle_count) {
return std::pair<WaitResult, size_t>(WaitResult::kSuccess,
result - WAIT_OBJECT_0);
@ -339,7 +339,7 @@ class Win32Event : public Win32Handle<Event> {
std::unique_ptr<Event> Event::CreateManualResetEvent(bool initial_state) {
HANDLE handle =
CreateEvent(nullptr, TRUE, initial_state ? TRUE : FALSE, nullptr);
CreateEvent(nullptr, true, initial_state ? true : false, nullptr);
if (handle) {
return std::make_unique<Win32Event>(handle);
} else {
@ -351,7 +351,7 @@ std::unique_ptr<Event> Event::CreateManualResetEvent(bool initial_state) {
std::unique_ptr<Event> Event::CreateAutoResetEvent(bool initial_state) {
HANDLE handle =
CreateEvent(nullptr, FALSE, initial_state ? TRUE : FALSE, nullptr);
CreateEvent(nullptr, false, initial_state ? true : false, nullptr);
if (handle) {
return std::make_unique<Win32Event>(handle);
} else {
@ -397,7 +397,7 @@ class Win32Mutant : public Win32Handle<Mutant> {
};
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) {
return std::make_unique<Win32Mutant>(handle);
} else {
@ -433,7 +433,7 @@ class Win32Timer : public Win32Handle<Timer> {
callback_ ? reinterpret_cast<PTIMERAPCROUTINE>(CompletionRoutine)
: NULL;
return SetWaitableTimer(handle_, &due_time_li, 0, completion_routine, this,
FALSE)
false)
? true
: false;
}
@ -461,7 +461,7 @@ class Win32Timer : public Win32Handle<Timer> {
callback_ ? reinterpret_cast<PTIMERAPCROUTINE>(CompletionRoutine)
: NULL;
return SetWaitableTimer(handle_, &due_time_li, int32_t(period.count()),
completion_routine, this, FALSE)
completion_routine, this, false)
? true
: false;
}
@ -490,7 +490,7 @@ class Win32Timer : public Win32Handle<Timer> {
};
std::unique_ptr<Timer> Timer::CreateManualResetTimer() {
HANDLE handle = CreateWaitableTimer(NULL, TRUE, NULL);
HANDLE handle = CreateWaitableTimer(NULL, true, NULL);
if (handle) {
return std::make_unique<Win32Timer>(handle);
} else {
@ -500,7 +500,7 @@ std::unique_ptr<Timer> Timer::CreateManualResetTimer() {
}
std::unique_ptr<Timer> Timer::CreateSynchronizationTimer() {
HANDLE handle = CreateWaitableTimer(NULL, FALSE, NULL);
HANDLE handle = CreateWaitableTimer(NULL, false, NULL);
if (handle) {
return std::make_unique<Win32Timer>(handle);
} else {

View File

@ -15,7 +15,7 @@
#include <numeric>
#include <tuple>
#define UTF_CPP_CPLUSPLUS 201703L
#define UTF_CPP_CPLUSPLUS 202002L
#include "third_party/utfcpp/source/utf8.h"
namespace utfcpp = utf8;
@ -82,10 +82,10 @@ std::string upper_ascii(const std::string_view view) {
template <bool LOWER>
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
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 *= prime;
return hash;

View File

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

View File

@ -636,7 +636,7 @@ HostToGuestThunk X64HelperEmitter::EmitHostToGuestThunk() {
_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();
@ -681,13 +681,10 @@ HostToGuestThunk X64HelperEmitter::EmitHostToGuestThunk() {
size_t tail;
} code_offsets = {};
const size_t stack_size = StackLayout::THUNK_STACK_SIZE;
constexpr size_t stack_size = StackLayout::THUNK_STACK_SIZE;
code_offsets.prolog = getSize();
// 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);
code_offsets.prolog_stack_alloc = getSize();
@ -707,9 +704,6 @@ HostToGuestThunk X64HelperEmitter::EmitHostToGuestThunk() {
code_offsets.epilog = getSize();
add(rsp, stack_size);
mov(rdi, qword[rsp + 8 * 1]);
mov(rsi, qword[rsp + 8 * 2]);
mov(rdx, qword[rsp + 8 * 3]);
ret();
#else
assert_always("Unknown platform ABI in host to guest thunk!");
@ -741,7 +735,7 @@ GuestToHostThunk X64HelperEmitter::EmitGuestToHostThunk() {
_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();
@ -787,7 +781,7 @@ GuestToHostThunk X64HelperEmitter::EmitGuestToHostThunk() {
size_t tail;
} code_offsets = {};
const size_t stack_size = StackLayout::THUNK_STACK_SIZE;
constexpr size_t stack_size = StackLayout::THUNK_STACK_SIZE;
code_offsets.prolog = getSize();
@ -844,7 +838,7 @@ ResolveFunctionThunk X64HelperEmitter::EmitResolveFunctionThunk() {
_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();
@ -884,7 +878,7 @@ ResolveFunctionThunk X64HelperEmitter::EmitResolveFunctionThunk() {
size_t epilog;
size_t tail;
} code_offsets = {};
const size_t stack_size = StackLayout::THUNK_STACK_SIZE;
constexpr size_t stack_size = StackLayout::THUNK_STACK_SIZE;
code_offsets.prolog = getSize();
@ -1743,7 +1737,7 @@ void X64Backend::PrepareForReentry(void* ctx) {
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,
};

View File

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

View File

@ -79,13 +79,13 @@ class X64CodeCache : public CodeCache {
protected:
// All executable code falls within 0x80000000 to 0x9FFFFFFF, so we can
// only map enough for lookups within that range.
static const size_t kIndirectionTableSize = 0x1FFFFFFF;
static const uintptr_t kIndirectionTableBase = 0x80000000;
static constexpr size_t kIndirectionTableSize = 0x1FFFFFFF;
static constexpr uintptr_t kIndirectionTableBase = 0x80000000;
// 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
// so 256MB should be more than enough.
static const size_t kGeneratedCodeSize = 0x0FFFFFFF;
static const uintptr_t kGeneratedCodeExecuteBase = 0xA0000000;
static constexpr size_t kGeneratedCodeSize = 0x0FFFFFFF;
static constexpr uintptr_t kGeneratedCodeExecuteBase = 0xA0000000;
// Used for writing when PageAccess::kExecuteReadWrite is not supported.
static const uintptr_t kGeneratedCodeWriteBase =
kGeneratedCodeExecuteBase + kGeneratedCodeSize + 1;
@ -95,7 +95,7 @@ class X64CodeCache : public CodeCache {
// in analysis triggering.
// chrispy: raised this, some games that were compiled with low optimization
// levels can exceed this
static const size_t kMaximumFunctionCount = 1000000;
static constexpr size_t kMaximumFunctionCount = 1000000;
struct UnwindReservation {
size_t data_size = 0;

View File

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

View File

@ -72,17 +72,17 @@ using xe::cpu::hir::HIRBuilder;
using xe::cpu::hir::Instr;
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;
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::R12, Xbyak::Operand::R13, Xbyak::Operand::R14,
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,
};
@ -1242,11 +1242,11 @@ void* X64Emitter::FindQwordConstantOffset(uint64_t qwordvalue) {
return nullptr;
}
// First location to try and place constants.
static const uintptr_t kConstDataLocation = 0x20000000;
static const uintptr_t kConstDataSize = sizeof(xmm_consts);
static constexpr uintptr_t kConstDataLocation = 0x20000000;
static constexpr uintptr_t kConstDataSize = sizeof(xmm_consts);
// 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.
// Only called once and used by multiple instances of the emitter.

View File

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

View File

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

View File

@ -95,7 +95,7 @@ class StackLayout {
});
static_assert(sizeof(Thunk) % 16 == 0,
"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.
// 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
// function
static const size_t GUEST_PROFILER_START = 80;
static const size_t GUEST_RET_ADDR = 88;
static const size_t GUEST_CALL_RET_ADDR = 96;
static constexpr size_t GUEST_PROFILER_START = 80;
static constexpr size_t GUEST_RET_ADDR = 88;
static constexpr size_t GUEST_CALL_RET_ADDR = 96;
};
} // namespace x64

View File

@ -48,7 +48,7 @@ bool ControlFlowSimplificationPass::Run(HIRBuilder* builder) {
block = builder->last_block();
while (block) {
auto prev_block = block->prev;
const uint32_t expected = Edge::DOMINATES | Edge::UNCONDITIONAL;
constexpr uint32_t expected = Edge::DOMINATES | Edge::UNCONDITIONAL;
if (block->incoming_edge_head &&
(block->incoming_edge_head->flags & expected) == expected) {
// Dominated by the incoming block.

View File

@ -33,8 +33,15 @@ DEFINE_bool(trace_function_data, false,
DEFINE_bool(validate_hir, false,
"Perform validation checks on the HIR during compilation.", "CPU");
// https://github.com/bitsh1ft3r/Xenon/blob/091e8cd4dc4a7c697b4979eb200be7c9dee3590b/Xenon/Core/XCPU/PPU/PowerPC.h#L370
DEFINE_uint64(
pvr, 0x710700,
"Known PVR's.\n"
" 0x710200 = Used by Zephyr \n"
" 0x710300 = Used by Zephyr\n"
" 0x710500 = Used by Jasper\n"
" 0x710700 = Default\n"
" 0x710800 = Used by Corona V1 & V2\n"
"Processor version and revision number.\nBits 0 to 15 are the version "
"number.\nBits 16 to 31 are the revision number.\nNote: Some XEXs (such as "
"mfgbootlauncher.xex) may check for a value that's less than 0x710700.",

View File

@ -2100,7 +2100,7 @@ Value* HIRBuilder::CountLeadingZeros(Value* value) {
ASSERT_INTEGER_TYPE(value);
if (value->IsConstantZero()) {
static const uint8_t zeros[] = {
static constexpr uint8_t zeros[] = {
8,
16,
32,

View File

@ -14,7 +14,7 @@ namespace cpu {
namespace hir {
#define DEFINE_OPCODE(num, name, sig, flags) \
const OpcodeInfo num##_info = { \
constexpr OpcodeInfo num##_info = { \
num, \
flags, \
sig, \

View File

@ -20,8 +20,8 @@ namespace cpu {
namespace ppc {
constexpr size_t kNamePad = 11;
const uint8_t kSpaces[kNamePad] = {0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20};
constexpr uint8_t kSpaces[kNamePad] = {0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20};
void PadStringBuffer(StringBuffer* str, size_t base, size_t pad);
void PrintDisasm_bcx(const PPCDecodeData& d, StringBuffer* str);

View File

@ -44,7 +44,7 @@ using namespace xe::literals;
typedef std::vector<std::pair<std::string, std::string>> AnnotationList;
const uint32_t START_ADDRESS = 0x80000000;
constexpr uint32_t START_ADDRESS = 0x80000000;
struct TestCase {
TestCase(uint32_t address, std::string& name)

View File

@ -43,7 +43,7 @@ struct Context {
typedef std::vector<std::pair<std::string, std::string>> AnnotationList;
const uint32_t START_ADDRESS = 0x00000000;
constexpr uint32_t START_ADDRESS = 0x00000000;
struct TestCase {
TestCase(uint32_t address, std::string& name)

View File

@ -17,6 +17,7 @@ project("xenia-cpu-ppc-tests")
"xenia-base",
"xenia-kernel",
"xenia-patcher",
"xenia-hid-skylander",
})
files({
"ppc_testing_main.cc",

View File

@ -21,9 +21,7 @@ project("xenia-cpu")
local_platform_files("hir")
local_platform_files("ppc")
include("testing")
include("ppc/testing")
-- filter({"configurations:Release", "platforms:Windows"})
-- buildoptions({
-- "/O1",
-- })
if enableTests then
include("testing")
include("ppc/testing")
end

View File

@ -104,7 +104,7 @@ bool InitializeStackWalker() {
options |= SYMOPT_LOAD_LINES;
options |= SYMOPT_FAIL_CRITICAL_ERRORS;
sym_set_options_(options);
if (!sym_initialize_(GetCurrentProcess(), nullptr, TRUE)) {
if (!sym_initialize_(GetCurrentProcess(), nullptr, true)) {
XELOGE("Unable to initialize symbol services - already in use?");
return false;
}
@ -192,7 +192,7 @@ class Win32StackWalker : public StackWalker {
}
// Setup the frame for walking.
STACKFRAME64 stack_frame = {0};
STACKFRAME64 stack_frame = {};
stack_frame.AddrPC.Mode = AddrModeFlat;
stack_frame.AddrPC.Offset = thread_context.Rip;
stack_frame.AddrFrame.Mode = AddrModeFlat;

View File

@ -10,6 +10,7 @@ test_suite("xenia-cpu-tests", project_root, ".", {
"xenia-core",
"xenia-cpu",
"xenia-gpu",
"xenia-hid-skylander",
-- TODO(benvanik): cut these dependencies?
"xenia-kernel",

View File

@ -50,10 +50,10 @@ DEFINE_bool(
DECLARE_bool(allow_plugins);
static const uint8_t xe_xex2_retail_key[16] = {
static constexpr uint8_t xe_xex2_retail_key[16] = {
0x20, 0xB1, 0x85, 0xA5, 0x9D, 0x28, 0xFD, 0xC3,
0x40, 0x58, 0x3F, 0xBB, 0x08, 0x96, 0xBF, 0x91};
static const uint8_t xe_xex2_devkit_key[16] = {
static constexpr uint8_t xe_xex2_devkit_key[16] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
@ -1505,13 +1505,13 @@ std::vector<uint32_t> XexModule::PreanalyzeCode() {
uint32_t* range_end = (uint32_t*)memory()->TranslateVirtual(
high_8_aligned); // align down to multiple of 8
const uint8_t mfspr_r12_lr[4] = {0x7D, 0x88, 0x02, 0xA6};
constexpr uint8_t mfspr_r12_lr[4] = {0x7D, 0x88, 0x02, 0xA6};
// a blr instruction, with 4 zero bytes afterwards to pad the next address
// to 8 byte alignment
// if we see this prior to our address, we can assume we are a function
// start
const uint8_t blr[4] = {0x4E, 0x80, 0x0, 0x20};
constexpr uint8_t blr[4] = {0x4E, 0x80, 0x0, 0x20};
uint32_t blr32 = *reinterpret_cast<const uint32_t*>(&blr[0]);
@ -1631,7 +1631,7 @@ bool XexModule::FindSaveRest() {
// special codegen.
// __savegprlr_14 to __savegprlr_31
// __restgprlr_14 to __restgprlr_31
static const uint32_t gprlr_code_values[] = {
static constexpr uint32_t gprlr_code_values[] = {
0x68FFC1F9, // __savegprlr_14
0x70FFE1F9, // __savegprlr_15
0x78FF01FA, // __savegprlr_16
@ -1673,7 +1673,7 @@ bool XexModule::FindSaveRest() {
};
// __savefpr_14 to __savefpr_31
// __restfpr_14 to __restfpr_31
static const uint32_t fpr_code_values[] = {
static constexpr uint32_t fpr_code_values[] = {
0x70FFCCD9, // __savefpr_14
0x78FFECD9, // __savefpr_15
0x80FF0CDA, // __savefpr_16
@ -1717,7 +1717,7 @@ bool XexModule::FindSaveRest() {
// __savevmx_64 to __savevmx_127
// __restvmx_14 to __restvmx_31
// __restvmx_64 to __restvmx_127
static const uint32_t vmx_code_values[] = {
static constexpr uint32_t vmx_code_values[] = {
0xE0FE6039, // __savevmx_14
0xCE61CB7D, 0xF0FE6039, 0xCE61EB7D, 0x00FF6039, 0xCE610B7E, 0x10FF6039,
0xCE612B7E, 0x20FF6039, 0xCE614B7E, 0x30FF6039, 0xCE616B7E, 0x40FF6039,

View File

@ -55,7 +55,7 @@ void DebugWindow::DebugDialog::OnDraw(ImGuiIO& io) {
debug_window_.DrawFrame(io);
}
static const std::string kBaseTitle = "Xenia Debugger";
static constexpr std::string_view kBaseTitle = "Xenia Debugger";
DebugWindow::DebugWindow(Emulator* emulator,
xe::ui::WindowedAppContext& app_context)
@ -1460,7 +1460,7 @@ void DebugWindow::UpdateCache() {
auto object_table = kernel_state->object_table();
app_context_.CallInUIThread([this]() {
std::string title = kBaseTitle;
std::string title = std::string(kBaseTitle);
switch (processor_->execution_state()) {
case cpu::ExecutionState::kEnded:
title += " (ended)";

View File

@ -137,8 +137,8 @@ class DebugWindow : public cpu::DebugListener {
// The current state of the UI. Use this to synchronize multiple parts of the
// UI.
struct ImState {
static const int kRightPaneThreads = 0;
static const int kRightPaneMemory = 1;
static constexpr int kRightPaneThreads = 0;
static constexpr int kRightPaneMemory = 1;
int right_pane_tab = kRightPaneThreads;
cpu::ThreadDebugInfo* thread_info = nullptr;

View File

@ -41,9 +41,9 @@
#include "xenia/hid/input_system.h"
#include "xenia/kernel/kernel_state.h"
#include "xenia/kernel/user_module.h"
#include "xenia/kernel/util/xdbf_utils.h"
#include "xenia/kernel/xam/achievement_manager.h"
#include "xenia/kernel/xam/xam_module.h"
#include "xenia/kernel/xam/xdbf/spa_info.h"
#include "xenia/kernel/xbdm/xbdm_module.h"
#include "xenia/kernel/xboxkrnl/xboxkrnl_module.h"
#include "xenia/memory.h"
@ -215,12 +215,15 @@ X_STATUS Emulator::Setup(
// logical processors.
xe::threading::EnableAffinityConfiguration();
XELOGI("{}: Initializing Memory...", __func__);
// Create memory system first, as it is required for other systems.
memory_ = std::make_unique<Memory>();
if (!memory_->Initialize()) {
return false;
XELOGE("{}: Cannot initalize memory!", __func__);
return result;
}
XELOGI("{}: Initializing Exports...", __func__);
// Shared export resolver used to attach and query for HLE exports.
export_resolver_ = std::make_unique<xe::cpu::ExportResolver>();
@ -241,30 +244,38 @@ X_STATUS Emulator::Setup(
backend.reset(new xe::cpu::backend::NullBackend());
}
XELOGI("{}: Initializing Processor...", __func__);
// Initialize the CPU.
processor_ = std::make_unique<xe::cpu::Processor>(memory_.get(),
export_resolver_.get());
if (!processor_->Setup(std::move(backend))) {
XELOGE("{}: Cannot initalize processor!", __func__);
return X_STATUS_UNSUCCESSFUL;
}
XELOGI("{}: Initializing Audio...", __func__);
// Initialize the APU.
if (audio_system_factory) {
audio_system_ = audio_system_factory(processor_.get());
if (!audio_system_) {
XELOGE("{}: Cannot initalize audio_system!", __func__);
return X_STATUS_NOT_IMPLEMENTED;
}
}
XELOGI("{}: Initializing Graphics...", __func__);
// Initialize the GPU.
graphics_system_ = graphics_system_factory();
if (!graphics_system_) {
XELOGE("{}: Cannot initalize graphics_system!", __func__);
return X_STATUS_NOT_IMPLEMENTED;
}
XELOGI("{}: Initializing HID...", __func__);
// Initialize the HID.
input_system_ = std::make_unique<xe::hid::InputSystem>(display_window_);
if (!input_system_) {
XELOGE("{}: Cannot initalize input_system!", __func__);
return X_STATUS_NOT_IMPLEMENTED;
}
if (input_driver_factory) {
@ -282,11 +293,13 @@ X_STATUS Emulator::Setup(
return result;
}
XELOGI("{}: Initializing VFS...", __func__);
// Bring up the virtual filesystem used by the kernel.
file_system_ = std::make_unique<xe::vfs::VirtualFileSystem>();
patcher_ = std::make_unique<xe::patcher::Patcher>(storage_root_);
XELOGI("{}: Initializing Kernel...", __func__);
// Shared kernel state.
kernel_state_ = std::make_unique<xe::kernel::KernelState>(this);
#define LOAD_KERNEL_MODULE(t) \
@ -299,18 +312,22 @@ X_STATUS Emulator::Setup(
plugin_loader_ = std::make_unique<xe::patcher::PluginLoader>(
kernel_state_.get(), storage_root() / "plugins");
XELOGI("{}: Starting graphics_system...", __func__);
// Setup the core components.
result = graphics_system_->Setup(
processor_.get(), kernel_state_.get(),
display_window_ ? &display_window_->app_context() : nullptr,
display_window_ != nullptr);
if (result) {
XELOGE("{}: Failed to setup graphics_system!", __func__);
return result;
}
if (audio_system_) {
XELOGI("{}: Starting audio_system...", __func__);
result = audio_system_->Setup(kernel_state_.get());
if (result) {
XELOGE("{}: Failed to setup audio_system!", __func__);
return result;
}
audio_media_player_ = std::make_unique<apu::AudioMediaPlayer>(
@ -444,7 +461,7 @@ Emulator::FileSignatureType Emulator::GetFileSignature(
}
const uint64_t file_size = std::filesystem::file_size(path);
const int64_t header_size = 4;
constexpr int64_t header_size = 4;
if (file_size < header_size) {
return FileSignatureType::Unknown;
@ -768,53 +785,93 @@ X_STATUS Emulator::DataMigration(const uint64_t xuid) {
return X_STATUS_SUCCESS;
}
X_STATUS Emulator::InstallContentPackage(
const std::filesystem::path& path,
ContentInstallationInfo& installation_info) {
std::unique_ptr<vfs::Device> device =
vfs::XContentContainerDevice::CreateContentDevice("", path);
X_STATUS Emulator::ProcessContentPackageHeader(
const std::filesystem::path& path, ContentInstallEntry& installation_info) {
installation_info.name_ = "Invalid Content Package!";
installation_info.content_type_ = XContentType::kInvalid;
installation_info.data_installation_path_ = xe::path_to_utf8(path.filename());
installation_info.content_name = "Invalid Content Package!";
installation_info.content_type = static_cast<XContentType>(0);
installation_info.installation_path = xe::path_to_utf8(path.filename());
const auto header = vfs::XContentContainerDevice::ReadContainerHeader(path);
if (!device || !device->Initialize()) {
if (!header || !header->content_header.is_magic_valid()) {
installation_info.installation_state_ = InstallState::failed;
installation_info.installation_result_ = X_STATUS_INVALID_PARAMETER;
installation_info.installation_error_message_ = "Invalid Package Type!";
XELOGE("Failed to initialize device");
return X_STATUS_INVALID_PARAMETER;
}
const vfs::XContentContainerDevice* dev =
(vfs::XContentContainerDevice*)device.get();
// Always install savefiles to user signed to slot 0.
const auto profile =
kernel_state_->xam_state()->profile_manager()->GetProfile(
static_cast<uint8_t>(0));
uint64_t xuid = dev->xuid();
if (dev->content_type() == static_cast<uint32_t>(XContentType::kSavedGame) &&
uint64_t xuid = header->content_metadata.profile_id;
if (header->content_metadata.content_type == XContentType::kSavedGame &&
profile) {
xuid = profile->xuid();
}
std::filesystem::path installation_path =
content_root() / fmt::format("{:016X}", xuid) /
fmt::format("{:08X}", dev->title_id()) /
fmt::format("{:08X}", dev->content_type()) / path.filename();
installation_info.data_installation_path_ = fmt::format(
"{:016X}/{:08X}/{:08X}/{}", xuid,
header->content_metadata.execution_info.title_id.get(),
static_cast<uint32_t>(header->content_metadata.content_type.get()),
path.filename());
std::filesystem::path header_path =
content_root() / fmt::format("{:016X}", xuid) /
fmt::format("{:08X}", dev->title_id()) / "Headers" /
fmt::format("{:08X}", dev->content_type()) / path.filename();
installation_info.header_installation_path_ = fmt::format(
"{:016X}/{:08X}/Headers/{:08X}/{}", xuid,
header->content_metadata.execution_info.title_id.get(),
static_cast<uint32_t>(header->content_metadata.content_type.get()),
path.filename());
installation_info.installation_path =
fmt::format("{:016X}/{:08X}/{:08X}/{}", xuid, dev->title_id(),
dev->content_type(), path.filename());
installation_info.name_ =
xe::to_utf8(header->content_metadata.display_name(XLanguage::kEnglish));
installation_info.content_type_ =
static_cast<XContentType>(header->content_metadata.content_type);
installation_info.content_size_ = header->content_metadata.content_size;
installation_info.installation_state_ = InstallState::pending;
installation_info.content_name =
xe::to_utf8(dev->content_header().display_name());
installation_info.content_type =
static_cast<XContentType>(dev->content_type());
installation_info.icon_ = imgui_drawer_->LoadImGuiIcon(
std::span<const uint8_t>(header->content_metadata.title_thumbnail,
header->content_metadata.title_thumbnail_size));
return X_STATUS_SUCCESS;
}
X_STATUS Emulator::InstallContentPackage(
const std::filesystem::path& path, ContentInstallEntry& installation_info) {
installation_info.installation_state_ = InstallState::preparing;
std::unique_ptr<vfs::XContentContainerDevice> device =
vfs::XContentContainerDevice::CreateContentDevice("", path);
if (!device || !device->Initialize()) {
XELOGE("Failed to initialize device");
return X_STATUS_INVALID_PARAMETER;
}
const std::filesystem::path installation_path =
content_root() / installation_info.data_installation_path_;
const std::filesystem::path header_path =
content_root() / installation_info.header_installation_path_;
if (!std::filesystem::exists(content_root())) {
const std::error_code ec = xe::filesystem::CreateFolder(content_root());
if (ec) {
installation_info.installation_state_ = InstallState::failed;
installation_info.installation_error_message_ = ec.message();
installation_info.installation_result_ = X_STATUS_ACCESS_DENIED;
return X_STATUS_ACCESS_DENIED;
}
}
const auto disk_space = std::filesystem::space(content_root());
if (disk_space.available < installation_info.content_size_ * 1.1f) {
installation_info.installation_state_ = InstallState::failed;
installation_info.installation_error_message_ = "Insufficient disk space!";
installation_info.installation_result_ = X_STATUS_DISK_FULL;
return X_STATUS_DISK_FULL;
}
if (std::filesystem::exists(installation_path)) {
// TODO(Gliniak): Popup
@ -823,21 +880,35 @@ X_STATUS Emulator::InstallContentPackage(
std::error_code error_code;
std::filesystem::create_directories(installation_path, error_code);
if (error_code) {
installation_info.content_name = "Cannot Create Content Directory!";
installation_info.installation_state_ = InstallState::failed;
installation_info.installation_error_message_ =
"Cannot Create Content Directory!";
installation_info.installation_result_ = error_code.value();
return error_code.value();
}
}
installation_info.content_size_ = device->data_size();
installation_info.installation_state_ = InstallState::installing;
vfs::VirtualFileSystem::ExtractContentHeader(device.get(), header_path);
X_STATUS error_code = vfs::VirtualFileSystem::ExtractContentFiles(
device.get(), installation_path);
device.get(), installation_path,
installation_info.currently_installed_size_);
if (error_code != X_ERROR_SUCCESS) {
installation_info.installation_state_ = InstallState::failed;
return error_code;
}
installation_info.installation_state_ = InstallState::installed;
installation_info.currently_installed_size_ = installation_info.content_size_;
kernel_state()->BroadcastNotification(kXNotificationLiveContentInstalled, 0);
if (installation_info.content_type_ == XContentType::kProfile) {
kernel_state_->xam_state()->profile_manager()->ReloadProfiles();
}
return error_code;
}
@ -862,7 +933,9 @@ X_STATUS Emulator::ExtractZarchivePackage(
}
}
return vfs::VirtualFileSystem::ExtractContentFiles(device.get(), extract_dir);
uint64_t progress = 0;
return vfs::VirtualFileSystem::ExtractContentFiles(device.get(), extract_dir,
progress);
}
X_STATUS Emulator::CreateZarchivePackage(
@ -1316,19 +1389,9 @@ std::string Emulator::FindLaunchModule() {
}
static std::string format_version(xex2_version version) {
// fmt::format doesn't like bit fields
uint32_t major, minor, build, qfe;
major = version.major;
minor = version.minor;
build = version.build;
qfe = version.qfe;
if (qfe) {
return fmt::format("{}.{}.{}.{}", major, minor, build, qfe);
}
if (build) {
return fmt::format("{}.{}.{}", major, minor, build);
}
return fmt::format("{}.{}", major, minor);
// fmt::format doesn't like bit fields we use + to bypass it
return fmt::format("{}.{}.{}.{}", +version.major, +version.minor,
+version.build, +version.qfe);
}
X_STATUS Emulator::CompleteLaunch(const std::filesystem::path& path,
@ -1427,9 +1490,13 @@ X_STATUS Emulator::CompleteLaunch(const std::filesystem::path& path,
}
game_config_load_callback_loop_next_index_ = SIZE_MAX;
const kernel::util::XdbfGameData db = kernel_state_->module_xdbf(module);
const auto db = kernel_state_->module_xdbf(module);
game_info_database_ = std::make_unique<kernel::util::GameInfoDatabase>(&db);
game_info_database_ =
std::make_unique<kernel::util::GameInfoDatabase>(db.get());
kernel_state_->xam_state()->LoadSpaInfo(db.get());
kernel_state_->xam_state()->user_tracker()->AddTitleToPlayedList();
if (game_info_database_->IsValid()) {
title_name_ = game_info_database_->GetTitleName(
@ -1490,17 +1557,6 @@ X_STATUS Emulator::CompleteLaunch(const std::filesystem::path& path,
if (!icon_block.empty()) {
display_window_->SetIcon(icon_block.data(), icon_block.size());
}
for (uint8_t slot = 0; slot < XUserMaxUserCount; slot++) {
auto user =
kernel_state_->xam_state()->profile_manager()->GetProfile(slot);
if (user) {
kernel_state_->xam_state()
->achievement_manager()
->LoadTitleAchievements(user->xuid(), db);
}
}
}
}
@ -1526,7 +1582,8 @@ X_STATUS Emulator::CompleteLaunch(const std::filesystem::path& path,
if (cvars::allow_plugins) {
if (plugin_loader_->IsAnyPluginForTitleAvailable(title_id_.value(),
module->hash().value())) {
plugin_loader_->LoadTitlePlugins(title_id_.value());
plugin_loader_->LoadTitlePlugins(title_id_.value(),
module->hash().value());
}
}

View File

@ -26,6 +26,7 @@
#include "xenia/memory.h"
#include "xenia/patcher/patcher.h"
#include "xenia/patcher/plugin_loader.h"
#include "xenia/ui/immediate_drawer.h"
#include "xenia/vfs/device.h"
#include "xenia/vfs/virtual_file_system.h"
#include "xenia/xbox.h"
@ -55,8 +56,8 @@ class Window;
namespace xe {
constexpr fourcc_t kEmulatorSaveSignature = make_fourcc("XSAV");
static const std::string kDefaultGameSymbolicLink = "GAME:";
static const std::string kDefaultPartitionSymbolicLink = "D:";
static constexpr std::string_view kDefaultGameSymbolicLink = "GAME:";
static constexpr std::string_view kDefaultPartitionSymbolicLink = "D:";
// The main type that runs the whole emulator.
// This is responsible for initializing and managing all the various subsystems.
@ -171,6 +172,9 @@ class Emulator {
patcher::PluginLoader* plugin_loader() const { return plugin_loader_.get(); }
kernel::util::GameInfoDatabase* game_info_database() const {
return game_info_database_.get();
}
// Initializes the emulator and configures all components.
// The given window is used for display and the provided functions are used
// to create subsystems as required.
@ -231,18 +235,45 @@ class Emulator {
X_STATUS LaunchDefaultModule(const std::filesystem::path& path);
struct ContentInstallationInfo {
XContentType content_type;
std::string installation_path;
std::string content_name;
enum class InstallState : uint8_t {
preparing,
pending,
installing,
installed,
failed
};
constexpr static std::string_view installStateStringName[5] = {
"Preparing", "Pending", "Installing", "Success", "Failed"};
struct ContentInstallEntry {
ContentInstallEntry(std::filesystem::path path) : path_(path) {};
std::string name_{};
std::filesystem::path path_;
std::filesystem::path data_installation_path_;
std::filesystem::path header_installation_path_;
uint64_t content_size_ = 0;
uint64_t currently_installed_size_ = 0;
XContentType content_type_{};
InstallState installation_state_{};
X_STATUS installation_result_{};
std::string installation_error_message_{};
std::unique_ptr<ui::ImmediateTexture> icon_;
};
// Migrates data from content to content/xuid with respect to common data.
X_STATUS DataMigration(const uint64_t xuid);
X_STATUS ProcessContentPackageHeader(const std::filesystem::path& path,
ContentInstallEntry& installation_info);
// Extract content of package to content specific directory.
X_STATUS InstallContentPackage(const std::filesystem::path& path,
ContentInstallationInfo& installation_info);
ContentInstallEntry& installation_info);
// Extract content of zar package to desired directory.
X_STATUS ExtractZarchivePackage(const std::filesystem::path& path,

View File

@ -285,7 +285,7 @@ void CommandProcessor::WorkerThreadMain() {
do {
// If we spin around too much, revert to a "low-power" state.
if (loop_count > 500) {
const int wait_time_ms = 2;
constexpr int wait_time_ms = 2;
xe::threading::Wait(write_ptr_index_event_.get(), true,
std::chrono::milliseconds(wait_time_ms));
} else {

View File

@ -810,7 +810,7 @@ bool D3D12CommandProcessor::SetupContext() {
ID3D12Device* device = provider.GetDevice();
ID3D12CommandQueue* direct_queue = provider.GetDirectQueue();
fence_completion_event_ = CreateEvent(nullptr, FALSE, FALSE, nullptr);
fence_completion_event_ = CreateEvent(nullptr, false, false, nullptr);
if (fence_completion_event_ == nullptr) {
XELOGE("Failed to create the fence completion event");
return false;

View File

@ -109,7 +109,7 @@ namespace shaders {
#include "xenia/gpu/shaders/bytecode/d3d12_5_1/resolve_full_8bpp_scaled_cs.h"
} // namespace shaders
const D3D12RenderTargetCache::ResolveCopyShaderCode
constexpr D3D12RenderTargetCache::ResolveCopyShaderCode
D3D12RenderTargetCache::kResolveCopyShaders[size_t(
draw_util::ResolveCopyShaderIndex::kCount)] = {
{shaders::resolve_fast_32bpp_1x2xmsaa_cs,
@ -146,7 +146,7 @@ const D3D12RenderTargetCache::ResolveCopyShaderCode
sizeof(shaders::resolve_full_128bpp_scaled_cs)},
};
const uint32_t D3D12RenderTargetCache::kTransferUsedRootParameters[size_t(
constexpr uint32_t D3D12RenderTargetCache::kTransferUsedRootParameters[size_t(
TransferRootSignatureIndex::kCount)] = {
// kColor
kTransferUsedRootParameterColorSRVBit |
@ -184,7 +184,7 @@ const uint32_t D3D12RenderTargetCache::kTransferUsedRootParameters[size_t(
kTransferUsedRootParameterHostDepthAddressConstantBit,
};
const D3D12RenderTargetCache::TransferModeInfo
constexpr D3D12RenderTargetCache::TransferModeInfo
D3D12RenderTargetCache::kTransferModes[size_t(TransferMode::kCount)] = {
// kColorToDepth
{TransferOutput::kDepth, TransferRootSignatureIndex::kColor,
@ -467,7 +467,7 @@ bool D3D12RenderTargetCache::Initialize() {
// instead.
if (cvars::native_2x_msaa) {
msaa_2x_supported_ = true;
static const DXGI_FORMAT kRenderTargetDXGIFormats[] = {
static constexpr DXGI_FORMAT kRenderTargetDXGIFormats[] = {
DXGI_FORMAT_R16G16B16A16_FLOAT,
DXGI_FORMAT_R16G16B16A16_SNORM,
DXGI_FORMAT_R32G32_FLOAT,
@ -969,7 +969,7 @@ bool D3D12RenderTargetCache::Initialize() {
D3D12_FILL_MODE_SOLID;
uint32_rtv_clear_pipeline_desc.RasterizerState.CullMode =
D3D12_CULL_MODE_NONE;
uint32_rtv_clear_pipeline_desc.RasterizerState.DepthClipEnable = TRUE;
uint32_rtv_clear_pipeline_desc.RasterizerState.DepthClipEnable = true;
uint32_rtv_clear_pipeline_desc.PrimitiveTopologyType =
D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
uint32_rtv_clear_pipeline_desc.NumRenderTargets = 1;
@ -4327,12 +4327,12 @@ D3D12RenderTargetCache::GetOrCreateTransferPipelines(TransferShaderKey key) {
}
pipeline_desc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID;
pipeline_desc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE;
pipeline_desc.RasterizerState.DepthClipEnable = TRUE;
pipeline_desc.RasterizerState.DepthClipEnable = true;
pipeline_desc.InputLayout.pInputElementDescs = &pipeline_input_element_desc;
pipeline_desc.InputLayout.NumElements = 1;
pipeline_desc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
if (dest_is_stencil_bit) {
pipeline_desc.DepthStencilState.StencilEnable = TRUE;
pipeline_desc.DepthStencilState.StencilEnable = true;
pipeline_desc.DepthStencilState.FrontFace.StencilFailOp =
D3D12_STENCIL_OP_KEEP;
pipeline_desc.DepthStencilState.FrontFace.StencilDepthFailOp =
@ -4375,14 +4375,14 @@ D3D12RenderTargetCache::GetOrCreateTransferPipelines(TransferShaderKey key) {
pipeline_desc.RTVFormats[0] =
GetColorOwnershipTransferDXGIFormat(dest_color_format);
} else {
pipeline_desc.DepthStencilState.DepthEnable = TRUE;
pipeline_desc.DepthStencilState.DepthEnable = true;
pipeline_desc.DepthStencilState.DepthWriteMask =
D3D12_DEPTH_WRITE_MASK_ALL;
pipeline_desc.DepthStencilState.DepthFunc =
cvars::depth_transfer_not_equal_test ? D3D12_COMPARISON_FUNC_NOT_EQUAL
: D3D12_COMPARISON_FUNC_ALWAYS;
if (use_stencil_reference_output_) {
pipeline_desc.DepthStencilState.StencilEnable = TRUE;
pipeline_desc.DepthStencilState.StencilEnable = true;
pipeline_desc.DepthStencilState.StencilWriteMask = UINT8_MAX;
pipeline_desc.DepthStencilState.FrontFace.StencilFailOp =
D3D12_STENCIL_OP_KEEP;
@ -4804,7 +4804,7 @@ void D3D12RenderTargetCache::PerformTransfersAndResolveClears(
are_current_command_list_render_targets_valid_ = false;
if (dest_rt_key.is_depth) {
auto handle = dest_d3d12_rt.descriptor_draw().GetHandle();
command_list.D3DOMSetRenderTargets(0, nullptr, FALSE, &handle);
command_list.D3DOMSetRenderTargets(0, nullptr, false, &handle);
if (!use_stencil_reference_output_) {
command_processor_.SetStencilReference(UINT8_MAX);
}
@ -4812,7 +4812,7 @@ void D3D12RenderTargetCache::PerformTransfersAndResolveClears(
auto handle = dest_d3d12_rt.descriptor_load_separate().IsValid()
? dest_d3d12_rt.descriptor_load_separate().GetHandle()
: dest_d3d12_rt.descriptor_draw().GetHandle();
command_list.D3DOMSetRenderTargets(1, &handle, FALSE, nullptr);
command_list.D3DOMSetRenderTargets(1, &handle, false, nullptr);
}
uint32_t dest_pitch_tiles = dest_rt_key.GetPitchTiles();
@ -5432,7 +5432,7 @@ void D3D12RenderTargetCache::PerformTransfersAndResolveClears(
? dest_d3d12_rt.descriptor_load_separate().GetHandle()
: dest_d3d12_rt.descriptor_draw().GetHandle());
command_list.D3DOMSetRenderTargets(1, &handle, FALSE, nullptr);
command_list.D3DOMSetRenderTargets(1, &handle, false, nullptr);
are_current_command_list_render_targets_valid_ = true;
D3D12_VIEWPORT clear_viewport;
clear_viewport.TopLeftX = float(clear_rect.left);
@ -5553,7 +5553,7 @@ void D3D12RenderTargetCache::SetCommandListRenderTargets(
: d3d12_rt.descriptor_draw().GetHandle();
}
command_processor_.GetDeferredCommandList().D3DOMSetRenderTargets(
rtv_count, rtv_handles, FALSE,
rtv_count, rtv_handles, false,
depth_and_color_render_targets[0] ? &dsv_handle : nullptr);
are_current_command_list_render_targets_valid_ = true;
}

View File

@ -394,7 +394,7 @@ bool D3D12SharedMemory::AllocateSparseHostGpuMemoryRange(
region_start_coordinates.Subresource = 0;
D3D12_TILE_REGION_SIZE region_size;
region_size.NumTiles = length_bytes / D3D12_TILED_RESOURCE_TILE_SIZE_IN_BYTES;
region_size.UseBox = FALSE;
region_size.UseBox = false;
D3D12_TILE_RANGE_FLAGS range_flags = D3D12_TILE_RANGE_FLAG_NONE;
UINT heap_range_start_offset = 0;
direct_queue->UpdateTileMappings(

View File

@ -758,7 +758,7 @@ void D3D12TextureCache::WriteSampler(SamplerParameters parameters,
D3D12_FILTER_REDUCTION_TYPE_STANDARD);
desc.MaxAnisotropy = 1;
}
static const D3D12_TEXTURE_ADDRESS_MODE kAddressModeMap[] = {
static constexpr D3D12_TEXTURE_ADDRESS_MODE kAddressModeMap[] = {
/* kRepeat */ D3D12_TEXTURE_ADDRESS_MODE_WRAP,
/* kMirroredRepeat */ D3D12_TEXTURE_ADDRESS_MODE_MIRROR,
/* kClampToEdge */ D3D12_TEXTURE_ADDRESS_MODE_CLAMP,
@ -968,7 +968,7 @@ bool D3D12TextureCache::EnsureScaledResolveMemoryCommitted(
D3D12_TILE_REGION_SIZE region_size;
region_size.NumTiles =
kScaledResolveHeapSize / D3D12_TILED_RESOURCE_TILE_SIZE_IN_BYTES;
region_size.UseBox = FALSE;
region_size.UseBox = false;
D3D12_TILE_RANGE_FLAGS range_flags = D3D12_TILE_RANGE_FLAG_NONE;
UINT heap_range_start_offset = 0;
UINT range_tile_count =

View File

@ -144,7 +144,7 @@ void DeferredCommandList::Execute(ID3D12GraphicsCommandList* command_list,
*reinterpret_cast<const D3DOMSetRenderTargetsArguments*>(stream);
command_list->OMSetRenderTargets(
args.num_render_target_descriptors, args.render_target_descriptors,
args.rts_single_handle_to_descriptor_range ? TRUE : FALSE,
args.rts_single_handle_to_descriptor_range ? true : false,
args.depth_stencil ? &args.depth_stencil_descriptor : nullptr);
} break;
case Command::kD3DOMSetStencilRef: {

View File

@ -269,7 +269,7 @@ class DeferredCommandList {
return;
}
static_assert(alignof(D3D12_RESOURCE_BARRIER) <= alignof(uintmax_t));
const size_t header_size =
constexpr size_t header_size =
xe::align(sizeof(UINT), alignof(D3D12_RESOURCE_BARRIER));
uint8_t* args = reinterpret_cast<uint8_t*>(WriteCommand(
Command::kD3DResourceBarrier,

View File

@ -272,7 +272,7 @@ void PipelineCache::InitializeShaderStorage(
}
pipeline_storage_file_flush_needed_ = false;
// 'XEPS'.
const uint32_t pipeline_storage_magic = 0x53504558;
constexpr uint32_t pipeline_storage_magic = 0x53504558;
// 'DXRO' or 'DXRT'.
const uint32_t pipeline_storage_magic_api =
edram_rov_used ? 0x4F525844 : 0x54525844;
@ -367,7 +367,7 @@ void PipelineCache::InitializeShaderStorage(
uint32_t version_swapped;
} shader_storage_file_header;
// 'XESH'.
const uint32_t shader_storage_magic = 0x48534558;
constexpr uint32_t shader_storage_magic = 0x48534558;
if (fread(&shader_storage_file_header, sizeof(shader_storage_file_header), 1,
shader_storage_file_) &&
shader_storage_file_header.magic == shader_storage_magic &&
@ -1577,7 +1577,7 @@ bool PipelineCache::GetCurrentStateDescription(
// Render targets and blending state. 32 because of 0x1F mask, for safety
// (all unknown to zero).
static const PipelineBlendFactor kBlendFactorMap[32] = {
static constexpr PipelineBlendFactor kBlendFactorMap[32] = {
/* 0 */ PipelineBlendFactor::kZero,
/* 1 */ PipelineBlendFactor::kOne,
/* 2 */ PipelineBlendFactor::kZero, // ?
@ -1603,7 +1603,7 @@ bool PipelineCache::GetCurrentStateDescription(
// Like kBlendFactorMap, but with color modes changed to alpha. Some
// pipelines aren't created in 545407E0 because a color mode is used for
// alpha.
static const PipelineBlendFactor kBlendFactorAlphaMap[32] = {
static constexpr PipelineBlendFactor kBlendFactorAlphaMap[32] = {
/* 0 */ PipelineBlendFactor::kZero,
/* 1 */ PipelineBlendFactor::kOne,
/* 2 */ PipelineBlendFactor::kZero, // ?
@ -3029,7 +3029,7 @@ ID3D12PipelineState* PipelineCache::CreateD3D12Pipeline(
break;
}
state_desc.RasterizerState.FrontCounterClockwise =
description.front_counter_clockwise ? TRUE : FALSE;
description.front_counter_clockwise ? true : false;
state_desc.RasterizerState.DepthBias = description.depth_bias;
state_desc.RasterizerState.DepthBiasClamp = 0.0f;
// With non-square resolution scaling, make sure the worst-case impact is
@ -3041,7 +3041,7 @@ ID3D12PipelineState* PipelineCache::CreateD3D12Pipeline(
float(std::max(render_target_cache_.draw_resolution_scale_x(),
render_target_cache_.draw_resolution_scale_y()));
state_desc.RasterizerState.DepthClipEnable =
description.depth_clip ? TRUE : FALSE;
description.depth_clip ? true : false;
uint32_t msaa_sample_count = uint32_t(1)
<< uint32_t(description.host_msaa_samples);
if (edram_rov_used) {
@ -3082,7 +3082,7 @@ ID3D12PipelineState* PipelineCache::CreateD3D12Pipeline(
// Depth/stencil.
if (description.depth_func != xenos::CompareFunction::kAlways ||
description.depth_write) {
state_desc.DepthStencilState.DepthEnable = TRUE;
state_desc.DepthStencilState.DepthEnable = true;
state_desc.DepthStencilState.DepthWriteMask =
description.depth_write ? D3D12_DEPTH_WRITE_MASK_ALL
: D3D12_DEPTH_WRITE_MASK_ZERO;
@ -3093,7 +3093,7 @@ ID3D12PipelineState* PipelineCache::CreateD3D12Pipeline(
uint32_t(description.depth_func));
}
if (description.stencil_enable) {
state_desc.DepthStencilState.StencilEnable = TRUE;
state_desc.DepthStencilState.StencilEnable = true;
state_desc.DepthStencilState.StencilReadMask =
description.stencil_read_mask;
state_desc.DepthStencilState.StencilWriteMask =
@ -3131,8 +3131,8 @@ ID3D12PipelineState* PipelineCache::CreateD3D12Pipeline(
}
// Render targets and blending.
state_desc.BlendState.IndependentBlendEnable = TRUE;
static const D3D12_BLEND kBlendFactorMap[] = {
state_desc.BlendState.IndependentBlendEnable = true;
static constexpr D3D12_BLEND kBlendFactorMap[] = {
D3D12_BLEND_ZERO, D3D12_BLEND_ONE,
D3D12_BLEND_SRC_COLOR, D3D12_BLEND_INV_SRC_COLOR,
D3D12_BLEND_SRC_ALPHA, D3D12_BLEND_INV_SRC_ALPHA,
@ -3142,7 +3142,7 @@ ID3D12PipelineState* PipelineCache::CreateD3D12Pipeline(
D3D12_BLEND_SRC_ALPHA_SAT,
};
// 8 entries for safety since 3 bits from the guest are passed directly.
static const D3D12_BLEND_OP kBlendOpMap[] = {
static constexpr D3D12_BLEND_OP kBlendOpMap[] = {
D3D12_BLEND_OP_ADD, D3D12_BLEND_OP_SUBTRACT, D3D12_BLEND_OP_MIN,
D3D12_BLEND_OP_MAX, D3D12_BLEND_OP_REV_SUBTRACT, D3D12_BLEND_OP_ADD,
D3D12_BLEND_OP_ADD, D3D12_BLEND_OP_ADD};
@ -3169,7 +3169,7 @@ ID3D12PipelineState* PipelineCache::CreateD3D12Pipeline(
rt.src_blend_alpha != PipelineBlendFactor::kOne ||
rt.dest_blend_alpha != PipelineBlendFactor::kZero ||
rt.blend_op_alpha != xenos::BlendOp::kAdd) {
blend_desc.BlendEnable = TRUE;
blend_desc.BlendEnable = true;
blend_desc.SrcBlend = kBlendFactorMap[uint32_t(rt.src_blend)];
blend_desc.DestBlend = kBlendFactorMap[uint32_t(rt.dest_blend)];
blend_desc.BlendOp = kBlendOpMap[uint32_t(rt.blend_op)];
@ -3196,8 +3196,8 @@ ID3D12PipelineState* PipelineCache::CreateD3D12Pipeline(
if (description.cull_mode == PipelineCullMode::kDisableRasterization) {
state_desc.PS.pShaderBytecode = nullptr;
state_desc.PS.BytecodeLength = 0;
state_desc.DepthStencilState.DepthEnable = FALSE;
state_desc.DepthStencilState.StencilEnable = FALSE;
state_desc.DepthStencilState.DepthEnable = false;
state_desc.DepthStencilState.StencilEnable = false;
}
// Create the D3D12 pipeline state object.

View File

@ -19,106 +19,110 @@ project("xenia-gpu-d3d12")
"../shaders/bytecode/d3d12_5_1/*.h",
})
group("src")
project("xenia-gpu-d3d12-trace-viewer")
uuid("7b5b9fcb-7bf1-43ff-a774-d4c41c8706be")
single_library_windowed_app_kind()
language("C++")
links({
"xenia-apu",
"xenia-apu-nop",
"xenia-base",
"xenia-core",
"xenia-cpu",
"xenia-gpu",
"xenia-gpu-d3d12",
"xenia-hid",
"xenia-hid-nop",
"xenia-kernel",
"xenia-patcher",
"xenia-ui",
"xenia-ui-d3d12",
"xenia-vfs",
})
links({
"aes_128",
"capstone",
"dxbc",
"fmt",
"imgui",
"libavcodec",
"libavutil",
"mspack",
"snappy",
"xxhash",
})
files({
"d3d12_trace_viewer_main.cc",
"../../ui/windowed_app_main_"..platform_suffix..".cc",
})
-- Only create the .user file if it doesn't already exist.
local user_file = project_root.."/build/xenia-gpu-d3d12-trace-viewer.vcxproj.user"
if not os.isfile(user_file) then
debugdir(project_root)
debugargs({
"2>&1",
"1>scratch/stdout-trace-viewer.txt",
})
end
filter("architecture:x86_64")
if enableMiscSubprojects then
group("src")
project("xenia-gpu-d3d12-trace-viewer")
uuid("7b5b9fcb-7bf1-43ff-a774-d4c41c8706be")
single_library_windowed_app_kind()
language("C++")
links({
"xenia-cpu-backend-x64",
"xenia-apu",
"xenia-apu-nop",
"xenia-base",
"xenia-core",
"xenia-cpu",
"xenia-gpu",
"xenia-gpu-d3d12",
"xenia-hid",
"xenia-hid-nop",
"xenia-hid-skylander",
"xenia-kernel",
"xenia-patcher",
"xenia-ui",
"xenia-ui-d3d12",
"xenia-vfs",
})
group("src")
project("xenia-gpu-d3d12-trace-dump")
uuid("686b859c-0046-44c4-a02c-41fc3fb75698")
kind("ConsoleApp")
language("C++")
links({
"xenia-apu",
"xenia-apu-nop",
"xenia-base",
"xenia-core",
"xenia-cpu",
"xenia-gpu",
"xenia-gpu-d3d12",
"xenia-hid",
"xenia-hid-nop",
"xenia-kernel",
"xenia-ui",
"xenia-ui-d3d12",
"xenia-vfs",
"xenia-patcher",
})
links({
"aes_128",
"capstone",
"dxbc",
"fmt",
"imgui",
"libavcodec",
"libavutil",
"mspack",
"snappy",
"xxhash",
})
files({
"d3d12_trace_dump_main.cc",
"../../base/console_app_main_"..platform_suffix..".cc",
})
-- Only create the .user file if it doesn't already exist.
local user_file = project_root.."/build/xenia-gpu-d3d12-trace-dump.vcxproj.user"
if not os.isfile(user_file) then
debugdir(project_root)
debugargs({
"2>&1",
"1>scratch/stdout-trace-dump.txt",
})
end
filter("architecture:x86_64")
links({
"xenia-cpu-backend-x64",
"aes_128",
"capstone",
"dxbc",
"fmt",
"imgui",
"libavcodec",
"libavutil",
"mspack",
"snappy",
"xxhash",
})
files({
"d3d12_trace_viewer_main.cc",
"../../ui/windowed_app_main_"..platform_suffix..".cc",
})
-- Only create the .user file if it doesn't already exist.
local user_file = project_root.."/build/xenia-gpu-d3d12-trace-viewer.vcxproj.user"
if not os.isfile(user_file) then
debugdir(project_root)
debugargs({
"2>&1",
"1>scratch/stdout-trace-viewer.txt",
})
end
filter("architecture:x86_64")
links({
"xenia-cpu-backend-x64",
})
group("src")
project("xenia-gpu-d3d12-trace-dump")
uuid("686b859c-0046-44c4-a02c-41fc3fb75698")
kind("ConsoleApp")
language("C++")
links({
"xenia-apu",
"xenia-apu-nop",
"xenia-base",
"xenia-core",
"xenia-cpu",
"xenia-gpu",
"xenia-gpu-d3d12",
"xenia-hid",
"xenia-hid-nop",
"xenia-hid-skylander",
"xenia-kernel",
"xenia-ui",
"xenia-ui-d3d12",
"xenia-vfs",
"xenia-patcher",
})
links({
"aes_128",
"capstone",
"dxbc",
"fmt",
"imgui",
"libavcodec",
"libavutil",
"mspack",
"snappy",
"xxhash",
})
files({
"d3d12_trace_dump_main.cc",
"../../base/console_app_main_"..platform_suffix..".cc",
})
-- Only create the .user file if it doesn't already exist.
local user_file = project_root.."/build/xenia-gpu-d3d12-trace-dump.vcxproj.user"
if not os.isfile(user_file) then
debugdir(project_root)
debugargs({
"2>&1",
"1>scratch/stdout-trace-dump.txt",
})
end
filter("architecture:x86_64")
links({
"xenia-cpu-backend-x64",
})
end

View File

@ -77,8 +77,8 @@ reg::RB_DEPTHCONTROL GetNormalizedDepthControl(const RegisterFile& regs) {
}
// https://docs.microsoft.com/en-us/windows/win32/api/d3d11/ne-d3d11-d3d11_standard_multisample_quality_levels
const int8_t kD3D10StandardSamplePositions2x[2][2] = {{4, 4}, {-4, -4}};
const int8_t kD3D10StandardSamplePositions4x[4][2] = {
constexpr int8_t kD3D10StandardSamplePositions2x[2][2] = {{4, 4}, {-4, -4}};
constexpr int8_t kD3D10StandardSamplePositions4x[4][2] = {
{-2, -6}, {6, -2}, {-6, 2}, {2, 6}};
void GetPreferredFacePolygonOffset(const RegisterFile& regs,
@ -907,7 +907,7 @@ void GetResolveEdramTileSpan(ResolveEdramInfo edram_info,
rows_out = y1 - y0;
}
const ResolveCopyShaderInfo
constexpr ResolveCopyShaderInfo
resolve_copy_shader_info[size_t(ResolveCopyShaderIndex::kCount)] = {
{"Resolve Copy Fast 32bpp 1x/2xMSAA", false, 4, 4, 6, 3},
{"Resolve Copy Fast 32bpp 4xMSAA", false, 4, 4, 6, 3},

View File

@ -2051,7 +2051,7 @@ void DxbcShaderTranslator::ProcessAllocInstruction(
}
}
const DxbcShaderTranslator::ShaderRdefType
constexpr DxbcShaderTranslator::ShaderRdefType
DxbcShaderTranslator::rdef_types_[size_t(
DxbcShaderTranslator::ShaderRdefTypeIndex::kCount)] = {
// kFloat
@ -2104,7 +2104,7 @@ const DxbcShaderTranslator::ShaderRdefType
dxbc::RdefVariableType::kUInt, 1, 4, 0, ShaderRdefTypeIndex::kUint4},
};
const DxbcShaderTranslator::SystemConstantRdef
constexpr DxbcShaderTranslator::SystemConstantRdef
DxbcShaderTranslator::system_constant_rdef_[size_t(
DxbcShaderTranslator::SystemConstants::Index::kCount)] = {
{"xe_flags", ShaderRdefTypeIndex::kUint, sizeof(uint32_t)},

View File

@ -585,7 +585,7 @@ uint32_t DxbcShaderTranslator::FindOrAddSamplerBinding(
name << "xe_sampler" << fetch_constant;
if (aniso_filter == xenos::AnisoFilter::kDisabled ||
aniso_filter == xenos::AnisoFilter::kUseFetchConst) {
static const char kFilterSuffixes[] = {'p', 'l', 'b', 'f'};
static constexpr char kFilterSuffixes[] = {'p', 'l', 'b', 'f'};
name << '_' << kFilterSuffixes[uint32_t(mag_filter)]
<< kFilterSuffixes[uint32_t(min_filter)]
<< kFilterSuffixes[uint32_t(mip_filter)];
@ -762,7 +762,7 @@ void DxbcShaderTranslator::ProcessTextureFetchInstruction(
// sampling apparently round differently, so `mul` gives a value that would
// be floored as expected, but the left/upper pixel is still sampled
// instead.
const float rounding_offset = 1.5f / 1024.0f;
constexpr float rounding_offset = 1.5f / 1024.0f;
switch (instr.dimension) {
case xenos::FetchOpDimension::k1D:
offsets[0] = instr.attributes.offset_x + rounding_offset;

View File

@ -173,7 +173,7 @@ X_STATUS GraphicsSystem::Setup(cpu::Processor* processor,
: 1.0;
uint64_t last_frame_time = Clock::QueryGuestTickCount();
// Sleep for 90% of the vblank duration, spin for 10%
const double duration_scalar = 0.90;
constexpr double duration_scalar = 0.90;
while (frame_limiter_worker_running_) {
register_file()->values[XE_GPU_REG_D1MODE_V_COUNTER] +=

View File

@ -47,8 +47,8 @@ PacketCategory PacketDisassembler::GetPacketCategory(const uint8_t* base_ptr) {
bool PacketDisassembler::DisasmPacketType0(const uint8_t* base_ptr,
uint32_t packet,
PacketInfo* out_info) {
static const PacketTypeInfo type_0_info = {PacketCategory::kGeneric,
"PM4_TYPE0"};
static constexpr PacketTypeInfo type_0_info = {PacketCategory::kGeneric,
"PM4_TYPE0"};
out_info->type_info = &type_0_info;
uint32_t count = ((packet >> 16) & 0x3FFF) + 1;
@ -72,8 +72,8 @@ bool PacketDisassembler::DisasmPacketType0(const uint8_t* base_ptr,
bool PacketDisassembler::DisasmPacketType1(const uint8_t* base_ptr,
uint32_t packet,
PacketInfo* out_info) {
static const PacketTypeInfo type_1_info = {PacketCategory::kGeneric,
"PM4_TYPE1"};
static constexpr PacketTypeInfo type_1_info = {PacketCategory::kGeneric,
"PM4_TYPE1"};
out_info->type_info = &type_1_info;
out_info->count = 1 + 2;
@ -94,8 +94,8 @@ bool PacketDisassembler::DisasmPacketType1(const uint8_t* base_ptr,
bool PacketDisassembler::DisasmPacketType2(const uint8_t* base_ptr,
uint32_t packet,
PacketInfo* out_info) {
static const PacketTypeInfo type_2_info = {PacketCategory::kGeneric,
"PM4_TYPE2"};
static constexpr PacketTypeInfo type_2_info = {PacketCategory::kGeneric,
"PM4_TYPE2"};
out_info->type_info = &type_2_info;
out_info->count = 1;
@ -106,8 +106,8 @@ bool PacketDisassembler::DisasmPacketType2(const uint8_t* base_ptr,
bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
uint32_t packet,
PacketInfo* out_info) {
static const PacketTypeInfo type_3_unknown_info = {PacketCategory::kGeneric,
"PM4_TYPE3_UNKNOWN"};
static constexpr PacketTypeInfo type_3_unknown_info = {
PacketCategory::kGeneric, "PM4_TYPE3_UNKNOWN"};
out_info->type_info = &type_3_unknown_info;
uint32_t opcode = (packet >> 8) & 0x7F;
@ -127,8 +127,8 @@ bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
switch (opcode) {
case PM4_ME_INIT: {
// initialize CP's micro-engine
static const PacketTypeInfo op_info = {PacketCategory::kGeneric,
"PM4_ME_INIT"};
static constexpr PacketTypeInfo op_info = {PacketCategory::kGeneric,
"PM4_ME_INIT"};
out_actions.emplace_back(PacketAction::MeInit((uint32_t*)ptr, count));
@ -138,15 +138,15 @@ bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
case PM4_NOP: {
// skip N 32-bit words to get to the next packet
// No-op, ignore some data.
static const PacketTypeInfo op_info = {PacketCategory::kGeneric,
"PM4_NOP"};
static constexpr PacketTypeInfo op_info = {PacketCategory::kGeneric,
"PM4_NOP"};
out_info->type_info = &op_info;
break;
}
case PM4_INTERRUPT: {
// generate interrupt from the command stream
static const PacketTypeInfo op_info = {PacketCategory::kGeneric,
"PM4_INTERRUPT"};
static constexpr PacketTypeInfo op_info = {PacketCategory::kGeneric,
"PM4_INTERRUPT"};
out_info->type_info = &op_info;
PacketAction intaction;
@ -160,8 +160,8 @@ bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
// VdSwap will post this to tell us we need to swap the screen/fire an
// interrupt.
// 63 words here, but only the first has any data.
static const PacketTypeInfo op_info = {PacketCategory::kSwap,
"PM4_XE_SWAP"};
static constexpr PacketTypeInfo op_info = {PacketCategory::kSwap,
"PM4_XE_SWAP"};
out_info->type_info = &op_info;
PacketAction xsa;
@ -175,8 +175,8 @@ bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
case PM4_INDIRECT_BUFFER:
case PM4_INDIRECT_BUFFER_PFD: {
// indirect buffer dispatch
static const PacketTypeInfo op_info = {PacketCategory::kGeneric,
"PM4_INDIRECT_BUFFER"};
static constexpr PacketTypeInfo op_info = {PacketCategory::kGeneric,
"PM4_INDIRECT_BUFFER"};
out_info->type_info = &op_info;
PacketAction iba;
@ -189,8 +189,8 @@ bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
}
case PM4_WAIT_REG_MEM: {
// wait until a register or memory location is a specific value
static const PacketTypeInfo op_info = {PacketCategory::kGeneric,
"PM4_WAIT_REG_MEM"};
static constexpr PacketTypeInfo op_info = {PacketCategory::kGeneric,
"PM4_WAIT_REG_MEM"};
out_info->type_info = &op_info;
PacketAction wait_action;
@ -209,8 +209,8 @@ bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
case PM4_REG_RMW: {
// register read/modify/write
// ? (used during shader upload and edram setup)
static const PacketTypeInfo op_info = {PacketCategory::kGeneric,
"PM4_REG_RMW"};
static constexpr PacketTypeInfo op_info = {PacketCategory::kGeneric,
"PM4_REG_RMW"};
out_info->type_info = &op_info;
PacketAction rmw_action;
rmw_action.type = PacketAction::Type::kRegRmw;
@ -227,8 +227,8 @@ bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
}
case PM4_COND_WRITE: {
// conditional write to memory or register
static const PacketTypeInfo op_info = {PacketCategory::kGeneric,
"PM4_COND_WRITE"};
static constexpr PacketTypeInfo op_info = {PacketCategory::kGeneric,
"PM4_COND_WRITE"};
out_info->type_info = &op_info;
PacketAction cwr_action;
cwr_action.type = PacketAction::Type::kCondWrite;
@ -247,8 +247,8 @@ bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
}
case PM4_EVENT_WRITE: {
// generate an event that creates a write to memory when completed
static const PacketTypeInfo op_info = {PacketCategory::kGeneric,
"PM4_EVENT_WRITE"};
static constexpr PacketTypeInfo op_info = {PacketCategory::kGeneric,
"PM4_EVENT_WRITE"};
out_info->type_info = &op_info;
PacketAction evw_action;
evw_action.type = Type::kEventWrite;
@ -260,8 +260,8 @@ bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
}
case PM4_EVENT_WRITE_SHD: {
// generate a VS|PS_done event
static const PacketTypeInfo op_info = {PacketCategory::kGeneric,
"PM4_EVENT_WRITE_SHD"};
static constexpr PacketTypeInfo op_info = {PacketCategory::kGeneric,
"PM4_EVENT_WRITE_SHD"};
out_info->type_info = &op_info;
PacketAction evws_action;
evws_action.type = Type::kEventWriteSHD;
@ -276,8 +276,8 @@ bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
}
case PM4_EVENT_WRITE_EXT: {
// generate a screen extent event
static const PacketTypeInfo op_info = {PacketCategory::kGeneric,
"PM4_EVENT_WRITE_EXT"};
static constexpr PacketTypeInfo op_info = {PacketCategory::kGeneric,
"PM4_EVENT_WRITE_EXT"};
out_info->type_info = &op_info;
PacketAction eve_action;
@ -295,8 +295,8 @@ bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
case PM4_DRAW_INDX: {
// initiate fetch of index buffer and draw
// dword0 = viz query info
static const PacketTypeInfo op_info = {PacketCategory::kDraw,
"PM4_DRAW_INDX"};
static constexpr PacketTypeInfo op_info = {PacketCategory::kDraw,
"PM4_DRAW_INDX"};
out_info->type_info = &op_info;
uint32_t dword0 = xe::load_and_swap<uint32_t>(ptr + 0);
uint32_t dword1 = xe::load_and_swap<uint32_t>(ptr + 4);
@ -337,8 +337,8 @@ bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
}
case PM4_DRAW_INDX_2: {
// draw using supplied indices in packet
static const PacketTypeInfo op_info = {PacketCategory::kDraw,
"PM4_DRAW_INDX_2"};
static constexpr PacketTypeInfo op_info = {PacketCategory::kDraw,
"PM4_DRAW_INDX_2"};
out_info->type_info = &op_info;
uint32_t dword0 = xe::load_and_swap<uint32_t>(ptr + 0);
uint32_t index_count = dword0 >> 16;
@ -372,8 +372,8 @@ bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
// load constant into chip and to memory
// PM4_REG(reg) ((0x4 << 16) | (GSL_HAL_SUBBLOCK_OFFSET(reg)))
// reg - 0x2000
static const PacketTypeInfo op_info = {PacketCategory::kGeneric,
"PM4_SET_CONSTANT"};
static constexpr PacketTypeInfo op_info = {PacketCategory::kGeneric,
"PM4_SET_CONSTANT"};
out_info->type_info = &op_info;
uint32_t offset_type = xe::load_and_swap<uint32_t>(ptr + 0);
uint32_t index = offset_type & 0x7FF;
@ -407,8 +407,8 @@ bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
break;
}
case PM4_SET_CONSTANT2: {
static const PacketTypeInfo op_info = {PacketCategory::kGeneric,
"PM4_SET_CONSTANT2"};
static constexpr PacketTypeInfo op_info = {PacketCategory::kGeneric,
"PM4_SET_CONSTANT2"};
out_info->type_info = &op_info;
uint32_t offset_type = xe::load_and_swap<uint32_t>(ptr + 0);
uint32_t index = offset_type & 0xFFFF;
@ -424,8 +424,8 @@ bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
}
case PM4_LOAD_ALU_CONSTANT: {
// load constants from memory
static const PacketTypeInfo op_info = {PacketCategory::kGeneric,
"PM4_LOAD_ALU_CONSTANT"};
static constexpr PacketTypeInfo op_info = {PacketCategory::kGeneric,
"PM4_LOAD_ALU_CONSTANT"};
out_info->type_info = &op_info;
uint32_t address = xe::load_and_swap<uint32_t>(ptr + 0);
address &= 0x3FFFFFFF;
@ -465,8 +465,8 @@ bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
break;
}
case PM4_SET_SHADER_CONSTANTS: {
static const PacketTypeInfo op_info = {PacketCategory::kGeneric,
"PM4_SET_SHADER_CONSTANTS"};
static constexpr PacketTypeInfo op_info = {PacketCategory::kGeneric,
"PM4_SET_SHADER_CONSTANTS"};
out_info->type_info = &op_info;
uint32_t offset_type = xe::load_and_swap<uint32_t>(ptr + 0);
uint32_t index = offset_type & 0xFFFF;
@ -481,8 +481,8 @@ bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
}
case PM4_IM_LOAD: {
// load sequencer instruction memory (pointer-based)
static const PacketTypeInfo op_info = {PacketCategory::kGeneric,
"PM4_IM_LOAD"};
static constexpr PacketTypeInfo op_info = {PacketCategory::kGeneric,
"PM4_IM_LOAD"};
out_info->type_info = &op_info;
uint32_t addr_type = xe::load_and_swap<uint32_t>(ptr + 0);
auto shader_type = static_cast<xenos::ShaderType>(addr_type & 0x3);
@ -506,8 +506,8 @@ bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
}
case PM4_IM_LOAD_IMMEDIATE: {
// load sequencer instruction memory (code embedded in packet)
static const PacketTypeInfo op_info = {PacketCategory::kGeneric,
"PM4_IM_LOAD_IMMEDIATE"};
static constexpr PacketTypeInfo op_info = {PacketCategory::kGeneric,
"PM4_IM_LOAD_IMMEDIATE"};
out_info->type_info = &op_info;
uint32_t dword0 = xe::load_and_swap<uint32_t>(ptr + 0);
uint32_t dword1 = xe::load_and_swap<uint32_t>(ptr + 4);
@ -534,8 +534,8 @@ bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
}
case PM4_INVALIDATE_STATE: {
// selective invalidation of state pointers
static const PacketTypeInfo op_info = {PacketCategory::kGeneric,
"PM4_INVALIDATE_STATE"};
static constexpr PacketTypeInfo op_info = {PacketCategory::kGeneric,
"PM4_INVALIDATE_STATE"};
out_info->type_info = &op_info;
uint32_t mask = xe::load_and_swap<uint32_t>(ptr + 0);
@ -547,8 +547,8 @@ bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
break;
}
case PM4_SET_BIN_MASK_LO: {
static const PacketTypeInfo op_info = {PacketCategory::kGeneric,
"PM4_SET_BIN_MASK_LO"};
static constexpr PacketTypeInfo op_info = {PacketCategory::kGeneric,
"PM4_SET_BIN_MASK_LO"};
out_info->type_info = &op_info;
uint32_t value = xe::load_and_swap<uint32_t>(ptr);
// bin_mask_ = (bin_mask_ & 0xFFFFFFFF00000000ull) | value;
@ -561,8 +561,8 @@ bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
break;
}
case PM4_SET_BIN_MASK_HI: {
static const PacketTypeInfo op_info = {PacketCategory::kGeneric,
"PM4_SET_BIN_MASK_HI"};
static constexpr PacketTypeInfo op_info = {PacketCategory::kGeneric,
"PM4_SET_BIN_MASK_HI"};
out_info->type_info = &op_info;
uint32_t value = xe::load_and_swap<uint32_t>(ptr);
@ -573,8 +573,8 @@ bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
break;
}
case PM4_SET_BIN_SELECT_LO: {
static const PacketTypeInfo op_info = {PacketCategory::kGeneric,
"PM4_SET_BIN_SELECT_LO"};
static constexpr PacketTypeInfo op_info = {PacketCategory::kGeneric,
"PM4_SET_BIN_SELECT_LO"};
out_info->type_info = &op_info;
uint32_t value = xe::load_and_swap<uint32_t>(ptr);
PacketAction action;
@ -585,8 +585,8 @@ bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
break;
}
case PM4_SET_BIN_SELECT_HI: {
static const PacketTypeInfo op_info = {PacketCategory::kGeneric,
"PM4_SET_BIN_SELECT_HI"};
static constexpr PacketTypeInfo op_info = {PacketCategory::kGeneric,
"PM4_SET_BIN_SELECT_HI"};
out_info->type_info = &op_info;
uint32_t value = xe::load_and_swap<uint32_t>(ptr);
@ -670,14 +670,14 @@ bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
// Ignored packets - useful if breaking on the default handler below.
case 0x50: { // 0xC0015000 usually 2 words, 0xFFFFFFFF / 0x00000000
static const PacketTypeInfo op_info = {PacketCategory::kGeneric,
"PM4_TYPE3_0x50"};
static constexpr PacketTypeInfo op_info = {PacketCategory::kGeneric,
"PM4_TYPE3_0x50"};
out_info->type_info = &op_info;
break;
}
case 0x51: { // 0xC0015100 usually 2 words, 0xFFFFFFFF / 0xFFFFFFFF
static const PacketTypeInfo op_info = {PacketCategory::kGeneric,
"PM4_TYPE3_0x51"};
static constexpr PacketTypeInfo op_info = {PacketCategory::kGeneric,
"PM4_TYPE3_0x51"};
out_info->type_info = &op_info;
break;
}

View File

@ -902,7 +902,8 @@ bool COMMAND_PROCESSOR::ExecutePacketType3_EVENT_WRITE_SHD(
data_value = GpuSwap(data_value, endianness);
uint8_t* write_destination = memory_->TranslatePhysical(address);
if (address > 0x1FFFFFFF) {
uint32_t writeback_base = register_file_->values[XE_GPU_REG_WRITEBACK_BASE];
uint32_t writeback_base =
register_file_->values[XE_GPU_REG_WRITEBACK_START];
uint32_t writeback_size = register_file_->values[XE_GPU_REG_WRITEBACK_SIZE];
uint32_t writeback_offset = address - writeback_base;
// check whether the guest has written writeback base. if they haven't, skip

File diff suppressed because it is too large Load Diff

View File

@ -13,14 +13,14 @@ namespace xe {
namespace gpu {
namespace reg {
const Register RB_COLOR_INFO::rt_register_indices[4] = {
constexpr Register RB_COLOR_INFO::rt_register_indices[4] = {
XE_GPU_REG_RB_COLOR_INFO,
XE_GPU_REG_RB_COLOR1_INFO,
XE_GPU_REG_RB_COLOR2_INFO,
XE_GPU_REG_RB_COLOR3_INFO,
};
const Register RB_BLENDCONTROL::rt_register_indices[4] = {
constexpr Register RB_BLENDCONTROL::rt_register_indices[4] = {
XE_GPU_REG_RB_BLENDCONTROL0,
XE_GPU_REG_RB_BLENDCONTROL1,
XE_GPU_REG_RB_BLENDCONTROL2,

View File

@ -121,11 +121,11 @@ constexpr SwizzleSource GetSwizzledAluSourceComponent(
component_index));
}
inline char GetCharForComponentIndex(uint32_t i) {
const static char kChars[] = {'x', 'y', 'z', 'w'};
constexpr static char kChars[] = {'x', 'y', 'z', 'w'};
return kChars[i];
}
inline char GetCharForSwizzle(SwizzleSource swizzle_source) {
const static char kChars[] = {'x', 'y', 'z', 'w', '0', '1'};
constexpr static char kChars[] = {'x', 'y', 'z', 'w', '0', '1'};
return kChars[static_cast<uint32_t>(swizzle_source)];
}

View File

@ -144,7 +144,7 @@ spv::Id SpirvShaderTranslator::ProcessVectorAluOperation(
EnsureBuildPointAvailable();
// Lookup table for variants of instructions with similar structure.
static const unsigned int kOps[] = {
static constexpr unsigned int kOps[] = {
static_cast<unsigned int>(spv::OpNop), // kAdd
static_cast<unsigned int>(spv::OpNop), // kMul
static_cast<unsigned int>(spv::OpFOrdGreaterThanEqual), // kMax
@ -883,7 +883,7 @@ spv::Id SpirvShaderTranslator::ProcessScalarAluOperation(
EnsureBuildPointAvailable();
// Lookup table for variants of instructions with similar structure.
static const unsigned int kOps[] = {
static constexpr unsigned int kOps[] = {
static_cast<unsigned int>(spv::OpFAdd), // kAdds
static_cast<unsigned int>(spv::OpFAdd), // kAddsPrev
static_cast<unsigned int>(spv::OpNop), // kMuls

View File

@ -763,7 +763,7 @@ void SpirvShaderTranslator::ProcessTextureFetchInstruction(
// multiplication in texture sampling apparently round differently, so
// `mul` gives a value that would be floored as expected, but the
// left/upper pixel is still sampled instead.
const float kRoundingOffset = 1.5f / 1024.0f;
constexpr float kRoundingOffset = 1.5f / 1024.0f;
switch (instr.dimension) {
case xenos::FetchOpDimension::k1D:
offset_values[0] = instr.attributes.offset_x + kRoundingOffset;
@ -2333,7 +2333,7 @@ size_t SpirvShaderTranslator::FindOrAddSamplerBinding(
new_sampler_binding.mip_filter = mip_filter;
new_sampler_binding.aniso_filter = aniso_filter;
std::ostringstream name;
static const char kFilterSuffixes[] = {'p', 'l', 'b', 'f'};
static constexpr char kFilterSuffixes[] = {'p', 'l', 'b', 'f'};
name << "xe_sampler" << fetch_constant << '_'
<< kFilterSuffixes[uint32_t(mag_filter)]
<< kFilterSuffixes[uint32_t(min_filter)]

View File

@ -566,7 +566,7 @@ void SpirvShaderTranslator::CompleteFragmentShaderInMain() {
spv::Id alpha_test_result_non_not_equal;
{
// Function other than "not equal".
static const spv::Op kAlphaTestOps[] = {
static constexpr spv::Op kAlphaTestOps[] = {
spv::OpFOrdLessThan, spv::OpFOrdEqual, spv::OpFOrdGreaterThan};
for (uint32_t i = 0; i < 3; ++i) {
spv::Id alpha_test_comparison_result = builder_->createBinOp(

View File

@ -60,7 +60,7 @@ void ConvertTexelCTX1ToR8G8(xenos::Endian endian, void* output,
} block;
static_assert(sizeof(block) == 8, "CTX1 block mismatch");
const uint32_t bytes_per_block = 8;
constexpr uint32_t bytes_per_block = 8;
CopySwapBlock(endian, block.data, input, bytes_per_block);
uint8_t cr[4] = {
@ -84,7 +84,7 @@ void ConvertTexelCTX1ToR8G8(xenos::Endian endian, void* output,
void ConvertTexelDXT3AToDXT3(xenos::Endian endian, void* output,
const void* input, size_t length) {
const uint32_t bytes_per_block = 16;
constexpr uint32_t bytes_per_block = 16;
auto output_bytes = static_cast<uint8_t*>(output);
CopySwapBlock(endian, &output_bytes[0], input, 8);
std::memset(&output_bytes[8], 0, 8);

View File

@ -100,7 +100,7 @@ void TextureDump(const TextureInfo& src, void* buffer, size_t length) {
FILE* handle = filesystem::OpenFile(path, "wb");
if (handle) {
const char signature[4] = {'D', 'D', 'S', ' '};
constexpr char signature[4] = {'D', 'D', 'S', ' '};
fwrite(&signature, sizeof(signature), 1, handle);
fwrite(&dds_header, sizeof(dds_header), 1, handle);
fwrite(buffer, 1, length, handle);

View File

@ -19,7 +19,7 @@ using namespace xe::gpu::xenos;
#define FORMAT_INFO(texture_format, format, block_width, block_height, bits_per_pixel) \
{xenos::TextureFormat::texture_format, FormatType::format, block_width, block_height, bits_per_pixel}
const FormatInfo* FormatInfo::Get(uint32_t gpu_format) {
static const FormatInfo format_infos[64] = {
static constexpr FormatInfo format_infos[64] = {
#include "texture_info_formats.inl"
};
return &format_infos[gpu_format];

View File

@ -16,7 +16,7 @@ namespace xe {
namespace gpu {
// Trace file extension.
static const char kTraceExtension[] = "xtr";
static constexpr char kTraceExtension[] = "xtr";
// Any byte changes to the files should bump this version.
// Only builds with matching versions will work.

View File

@ -47,11 +47,11 @@ namespace gpu {
using namespace xe::gpu::xenos;
static const ImVec4 kColorError =
static constexpr ImVec4 kColorError =
ImVec4(255 / 255.0f, 0 / 255.0f, 0 / 255.0f, 255 / 255.0f);
static const ImVec4 kColorComment =
static constexpr ImVec4 kColorComment =
ImVec4(42 / 255.0f, 179 / 255.0f, 0 / 255.0f, 255 / 255.0f);
static const ImVec4 kColorIgnored =
static constexpr ImVec4 kColorIgnored =
ImVec4(100 / 255.0f, 100 / 255.0f, 100 / 255.0f, 255 / 255.0f);
TraceViewer::TraceViewer(xe::ui::WindowedAppContext& app_context,
@ -815,10 +815,11 @@ void TraceViewer::DrawVertexFetcher(Shader* shader,
}
ImGui::BeginChild("#indices", ImVec2(0, 300));
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(10, 0));
int display_start, display_end;
ImGui::CalcListClipping(vertex_count, ImGui::GetTextLineHeight(),
&display_start, &display_end);
ImGui::Dummy(ImVec2(0, (display_start)*ImGui::GetTextLineHeight()));
int display_start = 0;
int display_end = 0;
// ImGui::CalcListClipping(vertex_count, ImGui::GetTextLineHeight(),
// &display_start, &display_end);
// ImGui::Dummy(ImVec2(0, (display_start)*ImGui::GetTextLineHeight()));
ImGui::Columns(column_count);
if (display_start <= 1) {
for (size_t el_index = 0; el_index < vertex_binding.attributes.size();
@ -1641,11 +1642,12 @@ void TraceViewer::DrawStateUI() {
ImGui::BeginChild("#vsvertices", ImVec2(0, 300));
int display_start, display_end;
ImGui::CalcListClipping(int(vertices.size() / 4),
ImGui::GetTextLineHeight(), &display_start,
&display_end);
ImGui::Dummy(ImVec2(0, (display_start)*ImGui::GetTextLineHeight()));
int display_start = 0;
int display_end = 0;
// ImGui::CalcListClipping(int(vertices.size() / 4),
// ImGui::GetTextLineHeight(), &display_start,
// &display_end);
// ImGui::Dummy(ImVec2(0, (display_start)*ImGui::GetTextLineHeight()));
ImGui::Columns(int(el_size), "#vsvertices", true);
for (size_t i = display_start; i < display_end; i++) {
@ -1706,11 +1708,12 @@ void TraceViewer::DrawStateUI() {
}
ImGui::BeginChild("#indices", ImVec2(0, 300));
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
int display_start, display_end;
ImGui::CalcListClipping(1 + draw_info.index_count,
ImGui::GetTextLineHeight(), &display_start,
&display_end);
ImGui::Dummy(ImVec2(0, (display_start)*ImGui::GetTextLineHeight()));
int display_start = 0;
int display_end = 0;
// ImGui::CalcListClipping(1 + draw_info.index_count,
// ImGui::GetTextLineHeight(), &display_start,
// &display_end);
// ImGui::Dummy(ImVec2(0, (display_start)*ImGui::GetTextLineHeight()));
ImGui::Columns(2, "#indices", true);
ImGui::SetColumnOffset(1, 60);
if (display_start <= 1) {

View File

@ -13,7 +13,7 @@ namespace xe {
namespace gpu {
namespace ucode {
const AluScalarOpcodeInfo kAluScalarOpcodeInfos[64] = {
constexpr AluScalarOpcodeInfo kAluScalarOpcodeInfos[64] = {
{"adds", 1, true, kAluOpChangedStateNone},
{"adds_prev", 1, false, kAluOpChangedStateNone},
{"muls", 1, true, kAluOpChangedStateNone},
@ -80,7 +80,7 @@ const AluScalarOpcodeInfo kAluScalarOpcodeInfos[64] = {
{"opcode_63", 0, false, kAluOpChangedStateNone},
};
const AluVectorOpcodeInfo kAluVectorOpcodeInfos[32] = {
constexpr AluVectorOpcodeInfo kAluVectorOpcodeInfos[32] = {
{"add", {0b1111, 0b1111}, kAluOpChangedStateNone},
{"mul", {0b1111, 0b1111}, kAluOpChangedStateNone},
{"max", {0b1111, 0b1111}, kAluOpChangedStateNone},

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