Compare commits
201 Commits
0dc0f18
...
canary_exp
Author | SHA1 | Date |
---|---|---|
![]() |
e9b2464254 | |
![]() |
10f2b5ebfc | |
![]() |
833f938a64 | |
![]() |
37e3fe9eb6 | |
![]() |
ada971aefc | |
![]() |
e7e3cfc7fb | |
![]() |
2969a04145 | |
![]() |
70364e73ae | |
![]() |
4e8e789876 | |
![]() |
43d206d2e9 | |
![]() |
3b3c41ab2a | |
![]() |
7f7e4fd381 | |
![]() |
ff29ceabb4 | |
![]() |
4a5f63650d | |
![]() |
03c0e70f8b | |
![]() |
6b384dfe52 | |
![]() |
a10ca517a6 | |
![]() |
0b81604633 | |
![]() |
fe0e18466f | |
![]() |
4702bfb94c | |
![]() |
a717c0cd9f | |
![]() |
c3e4a93c0a | |
![]() |
f36dbd2b33 | |
![]() |
4b9509391a | |
![]() |
25d6f8269a | |
![]() |
7fec549552 | |
![]() |
8a1188090f | |
![]() |
39621ddec8 | |
![]() |
31173107bc | |
![]() |
4182852a4b | |
![]() |
c4e86cfd2b | |
![]() |
f66ab091c1 | |
![]() |
d9092fb232 | |
![]() |
c83522060e | |
![]() |
01d46c20ff | |
![]() |
5e4a04f383 | |
![]() |
3eef564ff8 | |
![]() |
45ca1c352d | |
![]() |
4cb783bf22 | |
![]() |
d01c35f506 | |
![]() |
d8137a23ea | |
![]() |
5e820b09c3 | |
![]() |
032dc8437b | |
![]() |
108fa002f9 | |
![]() |
6314388c51 | |
![]() |
fd82727be6 | |
![]() |
235978018c | |
![]() |
3b49edc3c6 | |
![]() |
f2a2812c67 | |
![]() |
12a7e4c9c2 | |
![]() |
3ab5ba5d81 | |
![]() |
7835f92d8c | |
![]() |
0f804c3690 | |
![]() |
0aeac841b8 | |
![]() |
79509828f0 | |
![]() |
3be371a4a3 | |
![]() |
20106f8cd5 | |
![]() |
f3de3ad3f6 | |
![]() |
54055a2271 | |
![]() |
b6884ba10b | |
![]() |
f819f23854 | |
![]() |
c5d6db2840 | |
![]() |
f6323beb20 | |
![]() |
20d3ac4ca9 | |
![]() |
fd1abfe6aa | |
![]() |
f91be22742 | |
![]() |
f65f044ee5 | |
![]() |
1d7973aea5 | |
![]() |
422517c673 | |
![]() |
15008ccecc | |
![]() |
b864149575 | |
![]() |
50492a951e | |
![]() |
31ce3e0c71 | |
![]() |
96c2fb13f7 | |
![]() |
97be6ebf51 | |
![]() |
6173cedde7 | |
![]() |
e601b5ab87 | |
![]() |
270e88a7a7 | |
![]() |
bb20633c52 | |
![]() |
9308a35624 | |
![]() |
de10b9ef91 | |
![]() |
f4b854e484 | |
![]() |
97a45315e3 | |
![]() |
a79c00f67a | |
![]() |
63c2d94a98 | |
![]() |
b43cb2ed8e | |
![]() |
d211130c6c | |
![]() |
5e9019309e | |
![]() |
b447699a5b | |
![]() |
fb3c12d362 | |
![]() |
fe739208b6 | |
![]() |
e85c2392ba | |
![]() |
2c8acf7b96 | |
![]() |
de3b49e356 | |
![]() |
f6d9e76fca | |
![]() |
dd112ed462 | |
![]() |
d18f80457d | |
![]() |
c15dde52d6 | |
![]() |
9434cc89c9 | |
![]() |
6b055f1f74 | |
![]() |
8cf15a8d54 | |
![]() |
3ba31d9f9a | |
![]() |
bc6bce780a | |
![]() |
2a4ca1a1b7 | |
![]() |
9f8fad7551 | |
![]() |
8273e8928a | |
![]() |
674870d881 | |
![]() |
900a02efff | |
![]() |
be715f76fa | |
![]() |
03571ac4c1 | |
![]() |
b8296a9bc9 | |
![]() |
418de9b7f2 | |
![]() |
7797adf5f2 | |
![]() |
be44b9ba33 | |
![]() |
afe74e3d72 | |
![]() |
8f647c548d | |
![]() |
2941b672d6 | |
![]() |
7566871220 | |
![]() |
179591c8bc | |
![]() |
8197881803 | |
![]() |
5ba6c2b840 | |
![]() |
56703e52e2 | |
![]() |
5d5eb03127 | |
![]() |
066391fb59 | |
![]() |
bde7d5579a | |
![]() |
31d715d100 | |
![]() |
7298536d46 | |
![]() |
7667958556 | |
![]() |
d2b265e251 | |
![]() |
02c95bee06 | |
![]() |
1a356f7344 | |
![]() |
47f327e848 | |
![]() |
c4f1bf27ef | |
![]() |
0771938db6 | |
![]() |
4b24f128f6 | |
![]() |
86a25791d0 | |
![]() |
30dcc09714 | |
![]() |
a0d199cd35 | |
![]() |
7a2f53bf20 | |
![]() |
7479ccc292 | |
![]() |
5f918ef28d | |
![]() |
d20620eb5e | |
![]() |
0ee39400fe | |
![]() |
a45a9d8704 | |
![]() |
f61d52dc46 | |
![]() |
40bd0080f1 | |
![]() |
b7066c7a15 | |
![]() |
1e2f903a4a | |
![]() |
6ae45effd0 | |
![]() |
8926bdcdd6 | |
![]() |
9132035a51 | |
![]() |
ae1c1e017d | |
![]() |
d801e047dc | |
![]() |
23d1f7a308 | |
![]() |
c4867250e4 | |
![]() |
25b3540480 | |
![]() |
570d30f06d | |
![]() |
763a3da6ea | |
![]() |
27d9cb8cfc | |
![]() |
f833effd07 | |
![]() |
b9ecfd5d78 | |
![]() |
0d06cdd649 | |
![]() |
1544349499 | |
![]() |
01fc219fc2 | |
![]() |
34b7085ed3 | |
![]() |
5979274998 | |
![]() |
5af7e1540b | |
![]() |
d2f350d0d3 | |
![]() |
da89b6a0c3 | |
![]() |
6666b803fd | |
![]() |
523a2dc6e3 | |
![]() |
1110cdd372 | |
![]() |
ccf7adf015 | |
![]() |
60318a5db6 | |
![]() |
9555e7bde4 | |
![]() |
ac6692fc65 | |
![]() |
c373208c97 | |
![]() |
78f97f8ff3 | |
![]() |
b3d345610a | |
![]() |
75d49df2c5 | |
![]() |
d0e6f3638e | |
![]() |
fbacd3c12d | |
![]() |
180be3664e | |
![]() |
b7b707ddd2 | |
![]() |
4cc074df63 | |
![]() |
54610b939f | |
![]() |
787c8d0edc | |
![]() |
9a0ed48168 | |
![]() |
b7b6b860a9 | |
![]() |
dbe645e16e | |
![]() |
6f0a736c6c | |
![]() |
a4412ad40d | |
![]() |
403c9500bb | |
![]() |
00202f938d | |
![]() |
08537f0a80 | |
![]() |
de1ad7aaf5 | |
![]() |
d90c320dda | |
![]() |
753698ea20 | |
![]() |
3f196f4b62 | |
![]() |
00c94f28a1 | |
![]() |
f58fab1d2c |
|
@ -3,6 +3,9 @@ BasedOnStyle: Google
|
|||
DerivePointerAlignment: false
|
||||
PointerAlignment: Left
|
||||
SortIncludes: true
|
||||
KeepEmptyLines:
|
||||
AtStartOfFile: false
|
||||
InsertNewlineAtEOF: true
|
||||
|
||||
# Regroup causes unnecessary noise due to clang-format bug.
|
||||
IncludeBlocks: Preserve
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
name: Create release
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
os:
|
||||
required: true
|
||||
type: string
|
||||
secrets:
|
||||
RELEASE_TOKEN:
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
release:
|
||||
name: Release
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/download-artifact@main
|
||||
- name: Release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
GH_REPO: ${{ github.repository_owner }}/xenia-canary-releases
|
||||
notes: ${{ github.event.head_commit.message }}
|
||||
run: |
|
||||
rm -rf **/*.pdb
|
||||
case ${{ inputs.os }} in
|
||||
windows)
|
||||
assets=xenia_canary_windows.zip
|
||||
7z a $assets './xenia_canary_windows/*'
|
||||
;;
|
||||
linux)
|
||||
for dir in xenia_canary_${{ inputs.os }}*; do
|
||||
cd $dir
|
||||
chmod +x xenia_canary
|
||||
asset=${dir}.tar.gz
|
||||
assets+=($asset)
|
||||
tar -czvpf ../${asset} *
|
||||
cd -
|
||||
done
|
||||
;;
|
||||
esac
|
||||
for asset in ${assets[@]}; do
|
||||
if [ ! -f $asset ]; then
|
||||
echo "::error::$asset doesn't exist!"
|
||||
exit 1
|
||||
fi
|
||||
if [ $(stat -c%s $asset) -lt 100000 ]; then
|
||||
echo "::error::$asset is too small!"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
create_or_edit_release() {
|
||||
local tag=$1
|
||||
local title=$2
|
||||
if gh release view $tag; then
|
||||
gh release edit $tag -t $title -n "$notes"
|
||||
gh release upload $tag ${assets[@]} --clobber
|
||||
else
|
||||
gh release create $tag ${assets[@]} --target 925ed98d5dce604b651027c36fb522dc1ff0fa55 -t $title -n "$notes"
|
||||
fi
|
||||
}
|
||||
tag=${GITHUB_SHA::7}
|
||||
create_or_edit_release $tag ${tag}_$GITHUB_REF_NAME
|
||||
create_or_edit_release $GITHUB_REF_NAME $tag
|
|
@ -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,117 @@ on:
|
|||
jobs:
|
||||
lint:
|
||||
name: Lint
|
||||
runs-on: windows-latest
|
||||
runs-on: ubuntu-24.04
|
||||
outputs:
|
||||
#LLVM_VERSION: ${{ steps.setup.outputs.LLVM_VERSION }}
|
||||
UBUNTU_BASE: ${{ steps.setup.outputs.UBUNTU_BASE }}
|
||||
steps:
|
||||
- uses: actions/checkout@main
|
||||
- name: Check Clang-Format Version
|
||||
run: clang-format --version
|
||||
- name: Setup
|
||||
id: setup
|
||||
env:
|
||||
LLVM_VERSION: 19 # Same as Windows
|
||||
run: |
|
||||
UBUNTU_BASE=$(lsb_release -cs)
|
||||
#echo "LLVM_VERSION=$LLVM_VERSION" >> "$GITHUB_OUTPUT"
|
||||
echo "UBUNTU_BASE=$UBUNTU_BASE" >> "$GITHUB_OUTPUT"
|
||||
wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc
|
||||
sudo apt-add-repository "deb http://apt.llvm.org/${UBUNTU_BASE}/ llvm-toolchain-${UBUNTU_BASE}-$LLVM_VERSION main"
|
||||
sudo apt-get -y update
|
||||
sudo apt-get -y install clang-format-$LLVM_VERSION
|
||||
- name: Lint
|
||||
run: ./xb lint --all
|
||||
run: ./xenia-build.py lint --all
|
||||
|
||||
build-linux:
|
||||
name: Build (Linux) # runner.os can't be used here
|
||||
build-clang:
|
||||
name: Build (Clang ${{ matrix.LLVM_VERSION }})
|
||||
needs: lint
|
||||
runs-on: ubuntu-24.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
LLVM_VERSION: [20] # '${{ needs.lint.outputs.LLVM_VERSION }}'
|
||||
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
|
||||
env:
|
||||
UBUNTU_BASE: ${{ needs.lint.outputs.UBUNTU_BASE }}
|
||||
run: |
|
||||
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
|
||||
./xb setup
|
||||
sudo apt-get -y install mesa-vulkan-drivers valgrind libc++-dev libc++abi-dev libgtk-3-dev libsdl2-dev libvulkan-dev libx11-xcb-dev clang-${{ matrix.LLVM_VERSION }} ninja-build
|
||||
./xenia-build.py setup
|
||||
- name: Build
|
||||
run: ./xb build --config=Release
|
||||
env:
|
||||
CC: clang-${{ matrix.LLVM_VERSION }}
|
||||
CXX: clang++-${{ matrix.LLVM_VERSION }}
|
||||
run: ./xenia-build.py build --config=Release
|
||||
- name: Prepare artifacts
|
||||
id: prepare_artifacts
|
||||
run: |
|
||||
if [ $(stat -c %s build/bin/Linux/Release/xenia_canary) -le 100000 ]; then
|
||||
echo "::error::Binary is too small."
|
||||
fi
|
||||
mkdir -p artifacts
|
||||
cp -r build/bin/Linux/Release/xenia_canary LICENSE artifacts
|
||||
- name: Upload xenia canary artifacts
|
||||
if: steps.prepare_artifacts.outcome == 'success'
|
||||
uses: actions/upload-artifact@main
|
||||
with:
|
||||
name: xenia_canary_linux
|
||||
path: artifacts
|
||||
if-no-files-found: error
|
||||
|
||||
# build-gcc:
|
||||
# name: Build (GCC ${{ matrix.GCC_VERSION }})
|
||||
# needs: lint
|
||||
# runs-on: ubuntu-24.04
|
||||
# strategy:
|
||||
# fail-fast: false
|
||||
# matrix:
|
||||
# GCC_VERSION: [14]
|
||||
# steps:
|
||||
# - uses: actions/checkout@main
|
||||
# with:
|
||||
# fetch-depth: 0
|
||||
# - name: Setup
|
||||
# run: |
|
||||
# sudo apt-get -y update
|
||||
# sudo apt-get -y install mesa-vulkan-drivers valgrind libc++-dev libc++abi-dev libgtk-3-dev libsdl2-dev libvulkan-dev libx11-xcb-dev g++-${{ matrix.GCC_VERSION }}
|
||||
# ./xenia-build.py setup
|
||||
# - name: Build
|
||||
# env:
|
||||
# CC: gcc-${{ matrix.GCC_VERSION }}
|
||||
# CXX: g++-${{ matrix.GCC_VERSION }}
|
||||
# # AR: ar
|
||||
# run: ./xenia-build.py build --config=Release
|
||||
# - name: Prepare artifacts
|
||||
# id: prepare_artifacts
|
||||
# run: |
|
||||
# if [ $(stat -c %s build/bin/Linux/Release/xenia_canary) -le 100000 ]; then
|
||||
# echo "::error::Binary is too small."
|
||||
# fi
|
||||
# mkdir -p artifacts
|
||||
# cp -r build/bin/Linux/Release/xenia_canary LICENSE artifacts
|
||||
# - name: Upload xenia canary artifacts
|
||||
# if: steps.prepare_artifacts.outcome == 'success'
|
||||
# uses: actions/upload-artifact@main
|
||||
# with:
|
||||
# name: xenia_canary_linux_gcc
|
||||
# path: artifacts
|
||||
# if-no-files-found: error
|
||||
|
||||
create-release:
|
||||
name: Create release
|
||||
needs: [lint, build-clang] #build-gcc
|
||||
if: |
|
||||
github.repository == 'xenia-canary/xenia-canary' &&
|
||||
github.event.action != 'pull_request' &&
|
||||
github.ref == 'refs/heads/canary_experimental'
|
||||
uses: ./.github/workflows/Create_release.yml
|
||||
with:
|
||||
os: linux
|
||||
secrets:
|
||||
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
|
|
|
@ -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
|
||||
run: python xenia-build.py 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:
|
||||
|
@ -73,45 +69,37 @@ jobs:
|
|||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup
|
||||
run: .\xb setup
|
||||
run: python xenia-build.py setup
|
||||
- name: Build
|
||||
run: .\xb build --config=Release --target=src\xenia-app
|
||||
run: python xenia-build.py build --no_premake --config=Release --target=src\xenia-app
|
||||
- name: Prepare artifacts
|
||||
id: prepare_artifacts
|
||||
run: |
|
||||
foreach ($file in 'build\bin\Windows\Release\xenia_canary.exe','build\bin\Windows\Release\xenia_canary.pdb') {
|
||||
if ((get-item $file).Length -le 100000) {
|
||||
echo "::error::$file is too small."
|
||||
}
|
||||
}
|
||||
robocopy . build\bin\Windows\Release LICENSE /r:0 /w:0
|
||||
robocopy build\bin\Windows\Release artifacts\xenia_canary xenia_canary.exe xenia_canary.pdb LICENSE /r:0 /w:0
|
||||
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
|
||||
|
||||
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' &&
|
||||
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
|
||||
github.ref == 'refs/heads/canary_experimental'
|
||||
uses: ./.github/workflows/Create_release.yml
|
||||
with:
|
||||
os: windows
|
||||
secrets:
|
||||
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
|
|
|
@ -15,7 +15,8 @@
|
|||
url = https://github.com/premake/premake-core.git
|
||||
[submodule "third_party/snappy"]
|
||||
path = third_party/snappy
|
||||
url = https://github.com/xenia-project/snappy.git
|
||||
url = https://github.com/google/snappy.git
|
||||
ignore = dirty
|
||||
[submodule "third_party/premake-export-compile-commands"]
|
||||
path = third_party/premake-export-compile-commands
|
||||
url = https://github.com/xenia-project/premake-export-compile-commands.git
|
||||
|
@ -42,7 +43,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
|
||||
|
@ -97,9 +98,16 @@
|
|||
[submodule "third_party/rapidcsv"]
|
||||
path = third_party/rapidcsv
|
||||
url = https://github.com/d99kris/rapidcsv.git
|
||||
[submodule "third_party/zlib"]
|
||||
path = third_party/zlib
|
||||
url = https://github.com/madler/zlib.git
|
||||
[submodule "third_party/zlib-ng"]
|
||||
path = third_party/zlib-ng
|
||||
url = https://github.com/zlib-ng/zlib-ng.git
|
||||
ignore = dirty
|
||||
[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
|
||||
[submodule "third_party/cpplint"]
|
||||
path = third_party/cpplint
|
||||
url = https://github.com/cpplint/cpplint.git
|
||||
|
|
|
@ -20,7 +20,7 @@ Discussing illegal activities will get you banned.
|
|||
|
||||
Buildbot | Status | Releases
|
||||
-------- | ------ | --------
|
||||
Windows | [](https://github.com/xenia-canary/xenia-canary/actions/workflows/Windows_build.yml) [](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 | [](https://github.com/xenia-canary/xenia-canary/actions/workflows/Windows_build.yml) [](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 | [](https://github.com/xenia-canary/xenia-canary/actions/workflows/Linux_build.yml)
|
||||
Netplay Build | | [Latest](https://github.com/AdrianCassar/xenia-canary/releases/latest)
|
||||
|
||||
|
|
|
@ -9,10 +9,11 @@ drivers.
|
|||
### Windows
|
||||
|
||||
* Windows 10 or later
|
||||
* [Visual Studio 2022, Visual Studio 2019](https://www.visualstudio.com/downloads/)
|
||||
* [Python 3.9+](https://www.python.org/downloads/)
|
||||
* [Visual Studio 2022](https://www.visualstudio.com/downloads/)
|
||||
* CMake 3.10+ (or C++ CMake tools for Windows)
|
||||
* Windows 11 SDK version 10.0.22000.0 (for Visual Studio 2022, this or any newer version)
|
||||
* [Python 3.9+ 64-bit](https://www.python.org/downloads/)
|
||||
* Ensure Python is in PATH.
|
||||
* Windows 11 SDK version 10.0.22000.0 (for Visual Studio 2019, this or any newer version)
|
||||
|
||||
```
|
||||
git clone https://github.com/xenia-canary/xenia-canary.git
|
||||
|
@ -88,18 +89,24 @@ get helpful spacers/movs in the disassembly.
|
|||
|
||||
Linux support is extremely experimental and presently incomplete.
|
||||
|
||||
The build script uses LLVM/Clang 9. GCC while it should work in theory, is not easily
|
||||
The build script uses Clang 19. GCC while it should work in theory, is not easily
|
||||
interchangeable right now.
|
||||
|
||||
* Normal building via `xb build` uses Make.
|
||||
* [CodeLite](https://codelite.org) is supported. `xb devenv` will generate a workspace and attempt to open it. Your distribution's version may be out of date so check their website.
|
||||
* Experimental CMake generation is available to facilitate use of other IDEs such as [CLion](https://www.jetbrains.com/clion/). If `clion` is available inside `$PATH`, `xb devenv` will start it. Otherwise `build/CMakeLists.txt` needs to be generated by invoking `xb premake --devenv=cmake` manually.
|
||||
* Normal building via `xb build` uses CMake+Ninja.
|
||||
* Environment variables:
|
||||
Name | Default Value
|
||||
----- | -------------
|
||||
`CC` | `clang`
|
||||
`CXX` | `clang++`
|
||||
|
||||
Clang-9 or newer should be available from system repositories on all up to date distributions.
|
||||
<!--* [CodeLite](https://codelite.org) is supported. `xb devenv` will generate a workspace and attempt to open it. Your distribution's version may be out of date so check their website.
|
||||
* Experimental CMake generation is available to facilitate use of other IDEs such as [CLion](https://www.jetbrains.com/clion/). If `clion` is available inside `$PATH`, `xb devenv` will start it. Otherwise `build/CMakeLists.txt` needs to be generated by invoking `xb premake --devenv=cmake` manually.-->
|
||||
|
||||
Clang-19 or newer should be available from system repositories on all up to date distributions.
|
||||
You will also need some development libraries. To get them on an Ubuntu system:
|
||||
|
||||
```bash
|
||||
sudo apt-get install libgtk-3-dev libpthread-stubs0-dev liblz4-dev libx11-dev libx11-xcb-dev libvulkan-dev libsdl2-dev libiberty-dev libunwind-dev libc++-dev libc++abi-dev
|
||||
```sh
|
||||
sudo apt-get install build-essential mesa-vulkan-drivers valgrind libc++-dev libc++abi-dev libgtk-3-dev liblz4-dev libsdl2-dev libvulkan-dev libx11-xcb-dev clang-19 llvm-19 ninja-build
|
||||
```
|
||||
|
||||
In addition, you will need up to date Vulkan libraries and drivers for your hardware, which most distributions have in their standard repositories nowadays.
|
||||
|
|
140
premake5.lua
140
premake5.lua
|
@ -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
|
||||
|
@ -22,14 +27,18 @@ includedirs({
|
|||
})
|
||||
|
||||
defines({
|
||||
"_UNICODE",
|
||||
"UNICODE",
|
||||
"IMGUI_DISABLE_OBSOLETE_FUNCTIONS",
|
||||
"IMGUI_DISABLE_DEFAULT_FONT",
|
||||
--"IMGUI_USE_WCHAR32",
|
||||
"IMGUI_USE_STB_SPRINTF",
|
||||
--"IMGUI_ENABLE_FREETYPE",
|
||||
"USE_CPP17", -- Tabulate
|
||||
})
|
||||
|
||||
cdialect("C17")
|
||||
cppdialect("C++20")
|
||||
exceptionhandling("On")
|
||||
rtti("On")
|
||||
symbols("On")
|
||||
fatalwarnings("All")
|
||||
|
||||
-- TODO(DrChat): Find a way to disable this on other architectures.
|
||||
if ARCH ~= "ppc64" then
|
||||
|
@ -38,11 +47,6 @@ if ARCH ~= "ppc64" then
|
|||
filter({})
|
||||
end
|
||||
|
||||
characterset("Unicode")
|
||||
flags({
|
||||
"FatalWarnings", -- Treat warnings as errors.
|
||||
})
|
||||
|
||||
filter("kind:StaticLib")
|
||||
defines({
|
||||
"_LIB",
|
||||
|
@ -50,23 +54,27 @@ 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"})
|
||||
|
||||
filter({"configurations:Checked", "platforms:Windows"}) -- "toolset:msc"
|
||||
buildoptions({
|
||||
"/RTCsu", -- Full Run-Time Checks.
|
||||
})
|
||||
filter({"configurations:Checked", "platforms:Linux"})
|
||||
|
||||
filter({"configurations:Checked or Debug", "platforms:Linux"})
|
||||
defines({
|
||||
"_GLIBCXX_DEBUG", -- libstdc++ debug mode
|
||||
})
|
||||
filter({"configurations:Release", "platforms:Windows"})
|
||||
buildoptions({
|
||||
"/Gw",
|
||||
"/Ob3",
|
||||
})
|
||||
|
||||
filter({"configurations:Checked or Debug", "platforms:Windows"}) -- "toolset:msc"
|
||||
symbols("Full")
|
||||
|
||||
filter("configurations:Debug")
|
||||
runtime("Release")
|
||||
|
@ -75,10 +83,6 @@ filter("configurations:Debug")
|
|||
"DEBUG",
|
||||
"_NO_DEBUG_HEAP=1",
|
||||
})
|
||||
filter({"configurations:Debug", "platforms:Linux"})
|
||||
defines({
|
||||
"_GLIBCXX_DEBUG", -- make dbg symbols work on some distros
|
||||
})
|
||||
|
||||
filter("configurations:Release")
|
||||
runtime("Release")
|
||||
|
@ -87,23 +91,36 @@ filter("configurations:Release")
|
|||
"_NO_DEBUG_HEAP=1",
|
||||
})
|
||||
optimize("Speed")
|
||||
inlining("Auto")
|
||||
flags({
|
||||
"LinkTimeOptimization",
|
||||
"NoBufferSecurityCheck",
|
||||
"NoBufferSecurityCheck"
|
||||
})
|
||||
inlining("Auto")
|
||||
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:not Windows"})
|
||||
symbols("Off")
|
||||
|
||||
filter({"configurations:Release", "platforms:Windows"}) -- "toolset:msc"
|
||||
linktimeoptimization("On")
|
||||
buildoptions({
|
||||
"/Gw",
|
||||
"/Ob3",
|
||||
-- "/Qpar", -- TODO: Test this.
|
||||
})
|
||||
|
||||
filter("platforms:Linux")
|
||||
system("linux")
|
||||
toolset("clang")
|
||||
buildoptions({
|
||||
vectorextensions("AVX2")
|
||||
--buildoptions({
|
||||
-- "-mlzcnt", -- (don't) Assume lzcnt is supported.
|
||||
})
|
||||
--})
|
||||
pkg_config.all("gtk+-x11-3.0")
|
||||
links({
|
||||
"stdc++fs",
|
||||
|
@ -113,21 +130,26 @@ filter("platforms:Linux")
|
|||
"rt",
|
||||
})
|
||||
|
||||
filter({"platforms:Linux"})
|
||||
vectorextensions("AVX2")
|
||||
|
||||
filter({"platforms:Linux", "kind:*App"})
|
||||
linkgroups("On")
|
||||
|
||||
filter({"platforms:Linux", "language:C++", "toolset:gcc"})
|
||||
filter({"language:C++", "toolset:clang or gcc"}) -- "platforms:Linux"
|
||||
disablewarnings({
|
||||
"unused-result",
|
||||
"deprecated-volatile",
|
||||
"switch",
|
||||
"deprecated-enum-enum-conversion",
|
||||
"attributes",
|
||||
})
|
||||
|
||||
filter({"platforms:Linux", "toolset:gcc"})
|
||||
filter({"language:C++", "toolset:gcc"}) -- "platforms:Linux"
|
||||
disablewarnings({
|
||||
"unused-result",
|
||||
"volatile",
|
||||
"template-id-cdtor",
|
||||
"return-type",
|
||||
"deprecated",
|
||||
})
|
||||
|
||||
filter("toolset:gcc") -- "platforms:Linux"
|
||||
removefatalwarnings("All") -- HACK
|
||||
if ARCH == "ppc64" then
|
||||
buildoptions({
|
||||
"-m32",
|
||||
|
@ -137,19 +159,35 @@ filter({"platforms:Linux", "toolset:gcc"})
|
|||
"-m32",
|
||||
"-mpowerpc64"
|
||||
})
|
||||
else
|
||||
buildoptions({
|
||||
"-fpermissive", -- HACK
|
||||
})
|
||||
linkoptions({
|
||||
"-fpermissive", -- HACK
|
||||
})
|
||||
end
|
||||
|
||||
filter({"platforms:Linux", "language:C++", "toolset:clang"})
|
||||
filter({"language:C++", "toolset:clang"}) -- "platforms:Linux"
|
||||
disablewarnings({
|
||||
"deprecated-register",
|
||||
"deprecated-volatile",
|
||||
"switch",
|
||||
"deprecated-enum-enum-conversion",
|
||||
})
|
||||
filter({"platforms:Linux", "language:C++", "toolset:clang", "files:*.cc or *.cpp"})
|
||||
buildoptions({
|
||||
"-stdlib=libstdc++",
|
||||
"-std=c++20", -- clang doesn't respect cppdialect(?)
|
||||
CLANG_BIN = os.getenv("CC") or _OPTIONS["cc"] or "clang"
|
||||
if os.istarget("linux") and string.contains(CLANG_BIN, "clang") then
|
||||
if tonumber(string.match(os.outputof(CLANG_BIN.." --version"), "version (%d%d)")) >= 20 then
|
||||
filter({"language:C++", "toolset:clang"}) -- "platforms:Linux"
|
||||
disablewarnings({
|
||||
"deprecated-literal-operator", -- Needed only for tabulate
|
||||
"nontrivial-memcall",
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
filter({"language:C", "toolset:clang or gcc"}) -- "platforms:Linux"
|
||||
disablewarnings({
|
||||
"implicit-function-declaration",
|
||||
})
|
||||
|
||||
filter("platforms:Android-*")
|
||||
|
@ -174,16 +212,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.
|
||||
|
@ -248,10 +278,7 @@ workspace("xenia")
|
|||
-- 10.0.15063.0: ID3D12GraphicsCommandList1::SetSamplePositions.
|
||||
-- 10.0.19041.0: D3D12_HEAP_FLAG_CREATE_NOT_ZEROED.
|
||||
-- 10.0.22000.0: DWMWA_WINDOW_CORNER_PREFERENCE.
|
||||
filter("action:vs2017")
|
||||
systemversion("10.0.22000.0")
|
||||
filter("action:vs2019")
|
||||
systemversion("10.0")
|
||||
systemversion("latest")
|
||||
filter({})
|
||||
end
|
||||
end
|
||||
|
@ -272,9 +299,13 @@ workspace("xenia")
|
|||
include("third_party/xxhash.lua")
|
||||
include("third_party/zarchive.lua")
|
||||
include("third_party/zstd.lua")
|
||||
include("third_party/zlib.lua")
|
||||
include("third_party/zlib-ng.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 +323,7 @@ workspace("xenia")
|
|||
removefiles({
|
||||
"src/xenia/base/app_win32.manifest"
|
||||
})
|
||||
removeflags({
|
||||
"FatalWarnings",
|
||||
})
|
||||
removefatalwarnings("All")
|
||||
end
|
||||
|
||||
include("src/xenia")
|
||||
|
@ -311,6 +340,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")
|
||||
|
|
|
@ -9,8 +9,6 @@ project("xenia-app-discord")
|
|||
links({
|
||||
"discord-rpc"
|
||||
})
|
||||
defines({
|
||||
})
|
||||
includedirs({
|
||||
project_root.."/third_party/discord-rpc/src"
|
||||
})
|
||||
|
|
|
@ -9,13 +9,6 @@
|
|||
|
||||
#include "xenia/app/emulator_window.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "third_party/imgui/imgui.h"
|
||||
#include "third_party/stb/stb_image_write.h"
|
||||
#include "third_party/tomlplusplus/toml.hpp"
|
||||
|
@ -167,8 +160,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 +174,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 +562,96 @@ void EmulatorWindow::DisplayConfigDialog::OnDraw(ImGuiIO& io) {
|
|||
}
|
||||
}
|
||||
|
||||
void EmulatorWindow::ContentInstallDialog::OnDraw(ImGuiIO& io) {
|
||||
ImGui::SetNextWindowPos(ImVec2(20, 20), ImGuiCond_FirstUseEver);
|
||||
ImGui::SetNextWindowSize(ImVec2(20, 20), ImGuiCond_FirstUseEver);
|
||||
|
||||
bool dialog_open = true;
|
||||
if (!ImGui::Begin(
|
||||
fmt::format("Installation Progress###{}", window_id_).c_str(),
|
||||
&dialog_open,
|
||||
ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_AlwaysAutoResize |
|
||||
ImGuiWindowFlags_HorizontalScrollbar)) {
|
||||
Close();
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
|
||||
bool is_everything_installed = true;
|
||||
for (const auto& entry : *installation_entries_) {
|
||||
ImGui::BeginTable(fmt::format("table_{}", entry.name_).c_str(), 2);
|
||||
ImGui::TableNextRow(0);
|
||||
ImGui::TableSetColumnIndex(0);
|
||||
if (entry.icon_) {
|
||||
ImGui::Image(reinterpret_cast<ImTextureID>(entry.icon_.get()),
|
||||
ui::default_image_icon_size);
|
||||
} else {
|
||||
ImGui::Dummy(ui::default_image_icon_size);
|
||||
}
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
ImGui::Text("Name: %s", entry.name_.c_str());
|
||||
ImGui::Text("Installation Path:");
|
||||
ImGui::SameLine();
|
||||
if (ImGui::TextLink(
|
||||
xe::path_to_utf8(entry.data_installation_path_).c_str())) {
|
||||
LaunchFileExplorer(emulator_window_.emulator_->content_root() /
|
||||
entry.data_installation_path_);
|
||||
}
|
||||
|
||||
if (entry.content_type_ != xe::XContentType::kInvalid) {
|
||||
ImGui::Text("Content Type: %s",
|
||||
XContentTypeMap.at(entry.content_type_).c_str());
|
||||
}
|
||||
|
||||
std::string result = fmt::format(
|
||||
"Status: {}", xe::Emulator::installStateStringName[static_cast<uint8_t>(
|
||||
entry.installation_state_)]);
|
||||
|
||||
if (entry.installation_state_ == xe::Emulator::InstallState::failed) {
|
||||
result += fmt::format(" - {} ({:08X})",
|
||||
entry.installation_error_message_.c_str(),
|
||||
entry.installation_result_);
|
||||
}
|
||||
|
||||
ImGui::Text("%s", result.c_str());
|
||||
ImGui::EndTable();
|
||||
|
||||
if (entry.content_size_ > 0) {
|
||||
ImGui::ProgressBar(static_cast<float>(entry.currently_installed_size_) /
|
||||
entry.content_size_);
|
||||
|
||||
if (entry.currently_installed_size_ != entry.content_size_ &&
|
||||
entry.installation_result_ == X_ERROR_SUCCESS) {
|
||||
is_everything_installed = false;
|
||||
}
|
||||
} else {
|
||||
ImGui::ProgressBar(0.0f);
|
||||
}
|
||||
|
||||
if (installation_entries_->size() > 1) {
|
||||
ImGui::Separator();
|
||||
}
|
||||
}
|
||||
ImGui::Spacing();
|
||||
|
||||
ImGui::BeginDisabled(!is_everything_installed);
|
||||
if (ImGui::Button("Close")) {
|
||||
ImGui::EndDisabled();
|
||||
Close();
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
|
||||
if (!dialog_open && is_everything_installed) {
|
||||
Close();
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
bool EmulatorWindow::Initialize() {
|
||||
window_->AddListener(&window_listener_);
|
||||
window_->AddInputListener(&window_listener_, kZOrderEmulatorWindowInput);
|
||||
|
@ -935,11 +1018,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 +1094,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 +1171,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 (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";
|
||||
for (auto& entry : *content_installation_status) {
|
||||
emulator_->ProcessContentPackageHeader(entry.path_, entry);
|
||||
}
|
||||
|
||||
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));
|
||||
auto installationThread = std::thread([this, content_installation_status] {
|
||||
for (auto& entry : *content_installation_status) {
|
||||
emulator_->InstallContentPackage(entry.path_, entry);
|
||||
}
|
||||
});
|
||||
installationThread.detach();
|
||||
|
||||
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 +1477,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 +1683,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,8 +1853,9 @@ EmulatorWindow::ControllerHotKey EmulatorWindow::ProcessControllerHotkey(
|
|||
}
|
||||
|
||||
if (!notificationTitle.empty()) {
|
||||
app_context_.CallInUIThread([&]() {
|
||||
new xe::ui::HostNotificationWindow(imgui_drawer(), notificationTitle,
|
||||
app_context_.CallInUIThread(
|
||||
[imgui_drawer = imgui_drawer(), notificationTitle, notificationDesc]() {
|
||||
new xe::ui::HostNotificationWindow(imgui_drawer, notificationTitle,
|
||||
notificationDesc, 0);
|
||||
});
|
||||
}
|
||||
|
@ -1808,7 +1868,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 +1890,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 +1949,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");
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -54,11 +54,13 @@ project("xenia-app")
|
|||
-- Unified library containing all apps as StaticLibs, not just the main
|
||||
-- emulator windowed app.
|
||||
kind("SharedLib")
|
||||
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,21 +116,17 @@ project("xenia-app")
|
|||
"xenia-ui-d3d12",
|
||||
})
|
||||
|
||||
if enableMiscSubprojects then
|
||||
filter({"platforms:Windows", SINGLE_LIBRARY_FILTER})
|
||||
links({
|
||||
"xenia-gpu-d3d12-trace-viewer",
|
||||
"xenia-ui-window-d3d12-demo",
|
||||
})
|
||||
-- filter({"configurations:Release", "platforms:Windows"})
|
||||
-- buildoptions({
|
||||
-- "/O1",
|
||||
-- })
|
||||
end
|
||||
|
||||
filter("platforms:Windows")
|
||||
-- Only create the .user file if it doesn't already exist.
|
||||
local user_file = project_root.."/build/xenia-app.vcxproj.user"
|
||||
if not os.isfile(user_file) then
|
||||
debugdir(project_root)
|
||||
debugargs({
|
||||
})
|
||||
end
|
||||
|
|
|
@ -6,83 +6,22 @@
|
|||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/app/profile_dialogs.h"
|
||||
#include <algorithm>
|
||||
#include "xenia/app/emulator_window.h"
|
||||
#include "xenia/base/png_utils.h"
|
||||
#include "xenia/base/system.h"
|
||||
#include "xenia/kernel/util/shim_utils.h"
|
||||
#include "xenia/kernel/xam/xam_ui.h"
|
||||
#include "xenia/ui/file_picker.h"
|
||||
|
||||
#include "xenia/kernel/xam/ui/create_profile_ui.h"
|
||||
#include "xenia/kernel/xam/ui/gamercard_ui.h"
|
||||
#include "xenia/kernel/xam/ui/signin_ui.h"
|
||||
#include "xenia/kernel/xam/ui/title_info_ui.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace xam {
|
||||
extern bool xeDrawProfileContent(ui::ImGuiDrawer* imgui_drawer,
|
||||
const uint64_t xuid, const uint8_t user_index,
|
||||
const X_XAMACCOUNTINFO* account,
|
||||
uint64_t* selected_xuid);
|
||||
}
|
||||
} // namespace kernel
|
||||
namespace app {
|
||||
|
||||
void CreateProfileDialog::OnDraw(ImGuiIO& io) {
|
||||
if (!has_opened_) {
|
||||
ImGui::OpenPopup("Create Profile");
|
||||
has_opened_ = true;
|
||||
}
|
||||
|
||||
auto profile_manager = emulator_window_->emulator()
|
||||
->kernel_state()
|
||||
->xam_state()
|
||||
->profile_manager();
|
||||
|
||||
bool dialog_open = true;
|
||||
if (!ImGui::BeginPopupModal("Create Profile", &dialog_open,
|
||||
ImGuiWindowFlags_NoCollapse |
|
||||
ImGuiWindowFlags_AlwaysAutoResize |
|
||||
ImGuiWindowFlags_HorizontalScrollbar)) {
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
|
||||
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows) &&
|
||||
!ImGui::IsAnyItemActive() && !ImGui::IsMouseClicked(0)) {
|
||||
ImGui::SetKeyboardFocusHere(0);
|
||||
}
|
||||
|
||||
ImGui::TextUnformatted("Gamertag:");
|
||||
ImGui::InputText("##Gamertag", gamertag_, sizeof(gamertag_));
|
||||
|
||||
const std::string gamertag_string = std::string(gamertag_);
|
||||
bool valid = profile_manager->IsGamertagValid(gamertag_string);
|
||||
|
||||
ImGui::BeginDisabled(!valid);
|
||||
if (ImGui::Button("Create")) {
|
||||
bool autologin = (profile_manager->GetAccountCount() == 0);
|
||||
if (profile_manager->CreateProfile(gamertag_string, autologin,
|
||||
migration_) &&
|
||||
migration_) {
|
||||
emulator_window_->emulator()->DataMigration(0xB13EBABEBABEBABE);
|
||||
}
|
||||
std::fill(std::begin(gamertag_), std::end(gamertag_), '\0');
|
||||
dialog_open = false;
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button("Cancel")) {
|
||||
std::fill(std::begin(gamertag_), std::end(gamertag_), '\0');
|
||||
dialog_open = false;
|
||||
}
|
||||
|
||||
if (!dialog_open) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
Close();
|
||||
ImGui::EndPopup();
|
||||
return;
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
void NoProfileDialog::OnDraw(ImGuiIO& io) {
|
||||
auto profile_manager = emulator_window_->emulator()
|
||||
->kernel_state()
|
||||
|
@ -124,13 +63,13 @@ void NoProfileDialog::OnDraw(ImGuiIO& io) {
|
|||
|
||||
if (content_files.empty()) {
|
||||
if (ImGui::Button("Create Profile")) {
|
||||
new CreateProfileDialog(emulator_window_->imgui_drawer(),
|
||||
emulator_window_);
|
||||
new kernel::xam::ui::CreateProfileUI(emulator_window_->imgui_drawer(),
|
||||
emulator_window_->emulator());
|
||||
}
|
||||
} else {
|
||||
if (ImGui::Button("Create profile & migrate data")) {
|
||||
new CreateProfileDialog(emulator_window_->imgui_drawer(),
|
||||
emulator_window_, true);
|
||||
new kernel::xam::ui::CreateProfileUI(emulator_window_->imgui_drawer(),
|
||||
emulator_window_->emulator(), true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -149,6 +88,57 @@ void NoProfileDialog::OnDraw(ImGuiIO& io) {
|
|||
ImGui::End();
|
||||
}
|
||||
|
||||
void ProfileConfigDialog::LoadProfileIcon() {
|
||||
if (!emulator_window_) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint8_t user_index = 0; user_index < XUserMaxUserCount; user_index++) {
|
||||
const auto profile = emulator_window_->emulator()
|
||||
->kernel_state()
|
||||
->xam_state()
|
||||
->profile_manager()
|
||||
->GetProfile(user_index);
|
||||
|
||||
if (!profile) {
|
||||
continue;
|
||||
}
|
||||
LoadProfileIcon(profile->xuid());
|
||||
}
|
||||
}
|
||||
|
||||
void ProfileConfigDialog::LoadProfileIcon(const uint64_t xuid) {
|
||||
if (!emulator_window_) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto profile_manager = emulator_window_->emulator()
|
||||
->kernel_state()
|
||||
->xam_state()
|
||||
->profile_manager();
|
||||
if (!profile_manager) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto profile = profile_manager->GetProfile(xuid);
|
||||
|
||||
if (!profile) {
|
||||
if (profile_icon_.contains(xuid)) {
|
||||
profile_icon_[xuid].release();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const auto profile_icon =
|
||||
profile->GetProfileIcon(kernel::xam::XTileType::kGamerTile);
|
||||
if (profile_icon.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
profile_icon_[xuid].release();
|
||||
profile_icon_[xuid] = imgui_drawer()->LoadImGuiIcon(profile_icon);
|
||||
}
|
||||
|
||||
void ProfileConfigDialog::OnDraw(ImGuiIO& io) {
|
||||
if (!emulator_window_->emulator() ||
|
||||
!emulator_window_->emulator()->kernel_state() ||
|
||||
|
@ -184,28 +174,120 @@ void ProfileConfigDialog::OnDraw(ImGuiIO& io) {
|
|||
ImGui::Separator();
|
||||
}
|
||||
|
||||
const ImVec2 next_window_position =
|
||||
ImVec2(ImGui::GetWindowPos().x + ImGui::GetWindowSize().x + 20.f,
|
||||
ImGui::GetWindowPos().y);
|
||||
|
||||
for (auto& [xuid, account] : *profiles) {
|
||||
ImGui::PushID(static_cast<int>(xuid));
|
||||
|
||||
const uint8_t user_index =
|
||||
profile_manager->GetUserIndexAssignedToProfile(xuid);
|
||||
|
||||
if (!kernel::xam::xeDrawProfileContent(imgui_drawer(), xuid, user_index,
|
||||
&account, &selected_xuid_)) {
|
||||
const auto profile_icon = profile_icon_.find(xuid) != profile_icon_.cend()
|
||||
? profile_icon_[xuid].get()
|
||||
: nullptr;
|
||||
|
||||
auto context_menu_fun = [=, this]() -> bool {
|
||||
if (ImGui::BeginPopupContextItem("Profile Menu")) {
|
||||
//*selected_xuid = xuid;
|
||||
if (user_index == XUserIndexAny) {
|
||||
if (ImGui::MenuItem("Login")) {
|
||||
profile_manager->Login(xuid);
|
||||
if (!profile_manager->GetProfile(xuid)
|
||||
->GetProfileIcon(kernel::xam::XTileType::kGamerTile)
|
||||
.empty()) {
|
||||
LoadProfileIcon(xuid);
|
||||
}
|
||||
}
|
||||
if (ImGui::BeginMenu("Login to slot:")) {
|
||||
for (uint8_t i = 1; i <= XUserMaxUserCount; i++) {
|
||||
if (ImGui::MenuItem(fmt::format("slot {}", i).c_str())) {
|
||||
profile_manager->Login(xuid, i - 1);
|
||||
}
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
} else {
|
||||
if (ImGui::MenuItem("Logout")) {
|
||||
profile_manager->Logout(user_index);
|
||||
LoadProfileIcon(xuid);
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::MenuItem("Modify")) {
|
||||
new kernel::xam::ui::GamercardUI(
|
||||
emulator_window_->window(), emulator_window_->imgui_drawer(),
|
||||
emulator_window_->emulator()->kernel_state(), xuid);
|
||||
}
|
||||
|
||||
const bool is_signedin = profile_manager->GetProfile(xuid) != nullptr;
|
||||
ImGui::BeginDisabled(!is_signedin);
|
||||
if (ImGui::MenuItem("Show Played Titles")) {
|
||||
new kernel::xam::ui::TitleListUI(
|
||||
emulator_window_->imgui_drawer(), next_window_position,
|
||||
profile_manager->GetProfile(user_index));
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
|
||||
if (ImGui::MenuItem("Show Content Directory")) {
|
||||
const auto path = profile_manager->GetProfileContentPath(
|
||||
xuid, emulator_window_->emulator()->kernel_state()->title_id());
|
||||
|
||||
if (!std::filesystem::exists(path)) {
|
||||
std::filesystem::create_directories(path);
|
||||
}
|
||||
|
||||
std::thread path_open(LaunchFileExplorer, path);
|
||||
path_open.detach();
|
||||
}
|
||||
|
||||
if (!emulator_window_->emulator()->is_title_open()) {
|
||||
ImGui::Separator();
|
||||
if (ImGui::BeginMenu("Delete Profile")) {
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::TextUnformatted(
|
||||
fmt::format(
|
||||
"You're about to delete profile: {} (XUID: {:016X}). "
|
||||
"This will remove all data assigned to this profile "
|
||||
"including savefiles. Are you sure?",
|
||||
account.GetGamertagString(), xuid)
|
||||
.c_str());
|
||||
ImGui::EndTooltip();
|
||||
|
||||
if (ImGui::MenuItem("Yes, delete it!")) {
|
||||
profile_manager->DeleteProfile(xuid);
|
||||
ImGui::EndMenu();
|
||||
ImGui::EndPopup();
|
||||
return false;
|
||||
}
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
if (!kernel::xam::xeDrawProfileContent(
|
||||
imgui_drawer(), xuid, user_index, &account, profile_icon,
|
||||
context_menu_fun, [=, this]() { LoadProfileIcon(xuid); },
|
||||
&selected_xuid_)) {
|
||||
ImGui::PopID();
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
ImGui::Spacing();
|
||||
ImGui::Separator();
|
||||
}
|
||||
|
||||
ImGui::Spacing();
|
||||
|
||||
if (ImGui::Button("Create Profile")) {
|
||||
new CreateProfileDialog(emulator_window_->imgui_drawer(), emulator_window_);
|
||||
new kernel::xam::ui::CreateProfileUI(emulator_window_->imgui_drawer(),
|
||||
emulator_window_->emulator());
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
|
|
|
@ -19,26 +19,6 @@ namespace app {
|
|||
|
||||
class EmulatorWindow;
|
||||
|
||||
class CreateProfileDialog final : public ui::ImGuiDialog {
|
||||
public:
|
||||
CreateProfileDialog(ui::ImGuiDrawer* imgui_drawer,
|
||||
EmulatorWindow* emulator_window,
|
||||
bool with_migration = false)
|
||||
: ui::ImGuiDialog(imgui_drawer),
|
||||
emulator_window_(emulator_window),
|
||||
migration_(with_migration) {
|
||||
memset(gamertag_, 0, sizeof(gamertag_));
|
||||
}
|
||||
|
||||
protected:
|
||||
void OnDraw(ImGuiIO& io) override;
|
||||
|
||||
bool has_opened_ = false;
|
||||
bool migration_ = false;
|
||||
char gamertag_[16] = "";
|
||||
EmulatorWindow* emulator_window_;
|
||||
};
|
||||
|
||||
class NoProfileDialog final : public ui::ImGuiDialog {
|
||||
public:
|
||||
NoProfileDialog(ui::ImGuiDrawer* imgui_drawer,
|
||||
|
@ -55,12 +35,19 @@ class ProfileConfigDialog final : public ui::ImGuiDialog {
|
|||
public:
|
||||
ProfileConfigDialog(ui::ImGuiDrawer* imgui_drawer,
|
||||
EmulatorWindow* emulator_window)
|
||||
: ui::ImGuiDialog(imgui_drawer), emulator_window_(emulator_window) {}
|
||||
: ui::ImGuiDialog(imgui_drawer), emulator_window_(emulator_window) {
|
||||
LoadProfileIcon();
|
||||
}
|
||||
|
||||
protected:
|
||||
void OnDraw(ImGuiIO& io) override;
|
||||
|
||||
private:
|
||||
void LoadProfileIcon();
|
||||
void LoadProfileIcon(const uint64_t xuid);
|
||||
|
||||
std::map<uint64_t, std::unique_ptr<ui::ImmediateTexture>> profile_icon_;
|
||||
|
||||
uint64_t selected_xuid_ = 0;
|
||||
EmulatorWindow* emulator_window_;
|
||||
};
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include <memory>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include "xenia/app/discord/discord_presence.h"
|
||||
#include "xenia/app/emulator_window.h"
|
||||
|
@ -95,9 +94,15 @@ UPDATE_from_bool(mount_cache, 2024, 8, 31, 20, false);
|
|||
DEFINE_transient_path(target, "",
|
||||
"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 +426,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
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -412,7 +412,8 @@ bool AudioMediaPlayer::LoadSongToMemory(std::vector<uint8_t>* buffer) {
|
|||
|
||||
buffer->resize(vfs_file->entry()->size());
|
||||
size_t bytes_read = 0;
|
||||
result = vfs_file->ReadSync(buffer->data(), vfs_file->entry()->size(), 0,
|
||||
result = vfs_file->ReadSync(
|
||||
std::span<uint8_t>(buffer->data(), vfs_file->entry()->size()), 0,
|
||||
&bytes_read);
|
||||
|
||||
return !result;
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -10,6 +10,4 @@ project("xenia-apu-nop")
|
|||
"xenia-base",
|
||||
"xenia-apu",
|
||||
})
|
||||
defines({
|
||||
})
|
||||
local_platform_files()
|
||||
|
|
|
@ -12,8 +12,6 @@ project("xenia-apu")
|
|||
"libavformat",
|
||||
"xenia-base",
|
||||
})
|
||||
defines({
|
||||
})
|
||||
includedirs({
|
||||
project_root.."/third_party/FFmpeg/",
|
||||
})
|
||||
|
|
|
@ -12,7 +12,5 @@ project("xenia-apu-sdl")
|
|||
"xenia-helper-sdl",
|
||||
"SDL2",
|
||||
})
|
||||
defines({
|
||||
})
|
||||
local_platform_files()
|
||||
sdl2_include()
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
#include "xenia/apu/sdl/sdl_audio_driver.h"
|
||||
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
|
||||
#include "xenia/apu/apu_flags.h"
|
||||
|
|
|
@ -10,6 +10,4 @@ project("xenia-apu-xaudio2")
|
|||
"xenia-base",
|
||||
"xenia-apu",
|
||||
})
|
||||
defines({
|
||||
})
|
||||
local_platform_files()
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
#include "xenia/apu/xma_context.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
#include "xenia/apu/xma_decoder.h"
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
// #include <vector>
|
||||
|
||||
#include "xenia/memory.h"
|
||||
#include "xenia/xbox.h"
|
||||
|
@ -160,23 +159,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;
|
||||
|
|
|
@ -10,8 +10,6 @@
|
|||
#include "xenia/apu/xma_context_new.h"
|
||||
#include "xenia/apu/xma_helpers.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "xenia/base/logging.h"
|
||||
#include "xenia/base/platform.h"
|
||||
#include "xenia/base/profiling.h"
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
#include "xenia/apu/xma_context_old.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
#include "xenia/apu/xma_decoder.h"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]; }
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#include "xenia/base/arena.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/base/math.h"
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -9,8 +9,6 @@
|
|||
|
||||
#include "xenia/base/clock.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <mutex>
|
||||
|
||||
#include "xenia/base/assert.h"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -7,14 +7,11 @@
|
|||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "xenia/base/console_app_main.h"
|
||||
#include "xenia/base/cvar.h"
|
||||
#include "xenia/base/logging.h"
|
||||
|
||||
extern "C" int main(int argc, char** argv) {
|
||||
int main(int argc, char** argv) {
|
||||
xe::ConsoleAppEntryInfo entry_info = xe::GetConsoleAppEntryInfo();
|
||||
|
||||
if (!entry_info.transparent_options) {
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
*/
|
||||
|
||||
#include <cstdlib>
|
||||
#include <vector>
|
||||
|
||||
#include "xenia/base/console_app_main.h"
|
||||
#include "xenia/base/main_win.h"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#include "xenia/base/exception_handler.h"
|
||||
|
||||
#include <signal.h>
|
||||
#include <ucontext.h>
|
||||
#include <cstdint>
|
||||
|
||||
#include "xenia/base/assert.h"
|
||||
|
@ -168,7 +167,7 @@ static void ExceptionHandlerCallback(int signal_number, siginfo_t* signal_info,
|
|||
mcontext.gregs[REG_EFL] = greg_t(thread_context.eflags);
|
||||
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,
|
||||
|
|
|
@ -9,8 +9,6 @@
|
|||
|
||||
#include "xenia/base/filesystem.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace xe {
|
||||
namespace filesystem {
|
||||
|
||||
|
@ -24,5 +22,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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -16,14 +16,12 @@
|
|||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <ftw.h>
|
||||
#include <libgen.h>
|
||||
#include <pwd.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <iostream>
|
||||
|
||||
namespace xe {
|
||||
|
||||
|
@ -192,20 +190,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 +244,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) {
|
||||
|
|
|
@ -9,8 +9,6 @@
|
|||
|
||||
#include "xenia/base/filesystem_wildcard.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/base/string.h"
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
|
||||
#include <cctype>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
// TODO(gibbed): UTF8 support.
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,11 +10,8 @@
|
|||
#include "xenia/base/logging.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
#include "third_party/disruptorplus/include/disruptorplus/multi_threaded_claim_strategy.hpp"
|
||||
#include "third_party/disruptorplus/include/disruptorplus/ring_buffer.hpp"
|
||||
|
@ -244,12 +241,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 +350,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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
|
@ -7,7 +7,6 @@
|
|||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include <malloc.h>
|
||||
#include <cstring>
|
||||
|
||||
#include "xenia/base/cvar.h"
|
||||
|
@ -60,7 +59,7 @@ static void RequestWin32HighResolutionTimer() {
|
|||
ULONG minimum_resolution, maximum_resolution, current_resolution;
|
||||
nt_query_timer_resolution(&minimum_resolution, &maximum_resolution,
|
||||
¤t_resolution);
|
||||
nt_set_timer_resolution(maximum_resolution, TRUE, ¤t_resolution);
|
||||
nt_set_timer_resolution(maximum_resolution, true, ¤t_resolution);
|
||||
}
|
||||
|
||||
static void RequestWin32MMCSS() {
|
||||
|
@ -74,7 +73,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);
|
||||
}
|
||||
|
|
|
@ -7,9 +7,7 @@
|
|||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
#include "third_party/fmt/include/fmt/format.h"
|
||||
#include "xenia/base/logging.h"
|
||||
|
@ -29,7 +27,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;
|
||||
|
||||
|
|
|
@ -16,8 +16,6 @@
|
|||
#include <arm_neon.h>
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
DEFINE_bool(
|
||||
writable_executable_memory, true,
|
||||
"Allow mapping memory with both write and execute access, for simulating "
|
||||
|
@ -473,7 +471,7 @@ void copy_and_swap_16_unaligned(void* dst_ptr, const void* src_ptr,
|
|||
auto dst = reinterpret_cast<uint8_t*>(dst_ptr);
|
||||
auto 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 +505,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 +537,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)));
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,193 @@
|
|||
/* Xenia: minor tweaks to bring up to date with winnt.h */
|
||||
#include <cstdint>
|
||||
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* NT image format (to be used when the Win32 SDK version of WINNT.H cannot) */
|
||||
|
||||
#define XIMAGE_DOS_SIGNATURE 0x5A4D /* MZ */
|
||||
#define XIMAGE_OS2_SIGNATURE 0x454E /* NE */
|
||||
#define XIMAGE_OS2_SIGNATURE_LE 0x454C /* LE */
|
||||
#define XIMAGE_NT_SIGNATURE 0x00004550 /* PE00 */
|
||||
|
||||
typedef struct _XIMAGE_DOS_HEADER { /* DOS .EXE header */
|
||||
uint16_t e_magic; /* Magic number */
|
||||
uint16_t e_cblp; /* Bytes on last page of file */
|
||||
uint16_t e_cp; /* Pages in file */
|
||||
uint16_t e_crlc; /* Relocations */
|
||||
uint16_t e_cparhdr; /* Size of header in paragraphs */
|
||||
uint16_t e_minalloc; /* Minimum extra paragraphs needed */
|
||||
uint16_t e_maxalloc; /* Maximum extra paragraphs needed */
|
||||
uint16_t e_ss; /* Initial (relative) SS value */
|
||||
uint16_t e_sp; /* Initial SP value */
|
||||
uint16_t e_csum; /* Checksum */
|
||||
uint16_t e_ip; /* Initial IP value */
|
||||
uint16_t e_cs; /* Initial (relative) CS value */
|
||||
uint16_t e_lfarlc; /* File address of relocation table */
|
||||
uint16_t e_ovno; /* Overlay number */
|
||||
uint16_t e_res[4]; /* Reserved words */
|
||||
uint16_t e_oemid; /* OEM identifier (for e_oeminfo) */
|
||||
uint16_t e_oeminfo; /* OEM information; e_oemid specific */
|
||||
uint16_t e_res2[10]; /* Reserved words */
|
||||
int32_t e_lfanew; /* File address of new exe header */
|
||||
} XIMAGE_DOS_HEADER, *PXIMAGE_DOS_HEADER;
|
||||
|
||||
typedef struct _XIMAGE_OS2_HEADER { /* OS/2 .EXE header */
|
||||
uint16_t ne_magic; /* Magic number */
|
||||
int8_t ne_ver; /* Version number */
|
||||
int8_t ne_rev; /* Revision number */
|
||||
uint16_t ne_enttab; /* Offset of Entry Table */
|
||||
uint16_t ne_cbenttab; /* Number of bytes in Entry Table */
|
||||
int32_t ne_crc; /* Checksum of whole file */
|
||||
uint16_t ne_flags; /* Flag word */
|
||||
uint16_t ne_autodata; /* Automatic data segment number */
|
||||
uint16_t ne_heap; /* Initial heap allocation */
|
||||
uint16_t ne_stack; /* Initial stack allocation */
|
||||
int32_t ne_csip; /* Initial CS:IP setting */
|
||||
int32_t ne_sssp; /* Initial SS:SP setting */
|
||||
uint16_t ne_cseg; /* Count of file segments */
|
||||
uint16_t ne_cmod; /* Entries in Module Reference Table */
|
||||
uint16_t ne_cbnrestab; /* Size of non-resident name table */
|
||||
uint16_t ne_segtab; /* Offset of Segment Table */
|
||||
uint16_t ne_rsrctab; /* Offset of Resource Table */
|
||||
uint16_t ne_restab; /* Offset of resident name table */
|
||||
uint16_t ne_modtab; /* Offset of Module Reference Table */
|
||||
uint16_t ne_imptab; /* Offset of Imported Names Table */
|
||||
int32_t ne_nrestab; /* Offset of Non-resident Names Table */
|
||||
uint16_t ne_cmovent; /* Count of movable entries */
|
||||
uint16_t ne_align; /* Segment alignment shift count */
|
||||
uint16_t ne_cres; /* Count of resource segments */
|
||||
uint8_t ne_exetyp; /* Target Operating system */
|
||||
uint8_t ne_flagsothers; /* Other .EXE flags */
|
||||
uint16_t ne_pretthunks; /* offset to return thunks */
|
||||
uint16_t ne_psegrefbytes; /* offset to segment ref. bytes */
|
||||
uint16_t ne_swaparea; /* Minimum code swap area size */
|
||||
uint16_t ne_expver; /* Expected Windows version number */
|
||||
} XIMAGE_OS2_HEADER, *PXIMAGE_OS2_HEADER;
|
||||
|
||||
typedef struct _XIMAGE_FILE_HEADER {
|
||||
uint16_t Machine;
|
||||
uint16_t NumberOfSections;
|
||||
uint32_t TimeDateStamp;
|
||||
uint32_t PointerToSymbolTable;
|
||||
uint32_t NumberOfSymbols;
|
||||
uint16_t SizeOfOptionalHeader;
|
||||
uint16_t Characteristics;
|
||||
} XIMAGE_FILE_HEADER, *PXIMAGE_FILE_HEADER;
|
||||
|
||||
#define XIMAGE_FILE_32BIT_MACHINE 0x0100 /* 32 bit word machine. */
|
||||
|
||||
#define XIMAGE_FILE_MACHINE_POWERPCBE 0x01F2 // IBM PowerPC Big-Endian
|
||||
|
||||
typedef struct _XIMAGE_DATA_DIRECTORY {
|
||||
uint32_t VirtualAddress;
|
||||
uint32_t Size;
|
||||
} XIMAGE_DATA_DIRECTORY, *PXIMAGE_DATA_DIRECTORY;
|
||||
|
||||
#define XIMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
|
||||
|
||||
/*
|
||||
* Optional header format.
|
||||
*/
|
||||
|
||||
typedef struct _XIMAGE_OPTIONAL_HEADER {
|
||||
/*
|
||||
* Standard fields.
|
||||
*/
|
||||
|
||||
uint16_t Magic;
|
||||
uint8_t MajorLinkerVersion;
|
||||
uint8_t MinorLinkerVersion;
|
||||
uint32_t SizeOfCode;
|
||||
uint32_t SizeOfInitializedData;
|
||||
uint32_t SizeOfUninitializedData;
|
||||
uint32_t AddressOfEntryPoint;
|
||||
uint32_t BaseOfCode;
|
||||
uint32_t BaseOfData;
|
||||
|
||||
/*
|
||||
* NT additional fields.
|
||||
*/
|
||||
|
||||
uint32_t ImageBase;
|
||||
uint32_t SectionAlignment;
|
||||
uint32_t FileAlignment;
|
||||
uint16_t MajorOperatingSystemVersion;
|
||||
uint16_t MinorOperatingSystemVersion;
|
||||
uint16_t MajorImageVersion;
|
||||
uint16_t MinorImageVersion;
|
||||
uint16_t MajorSubsystemVersion;
|
||||
uint16_t MinorSubsystemVersion;
|
||||
uint32_t Reserved1;
|
||||
uint32_t SizeOfImage;
|
||||
uint32_t SizeOfHeaders;
|
||||
uint32_t CheckSum;
|
||||
uint16_t Subsystem;
|
||||
uint16_t DllCharacteristics;
|
||||
uint32_t SizeOfStackReserve;
|
||||
uint32_t SizeOfStackCommit;
|
||||
uint32_t SizeOfHeapReserve;
|
||||
uint32_t SizeOfHeapCommit;
|
||||
uint32_t LoaderFlags;
|
||||
uint32_t NumberOfRvaAndSizes;
|
||||
XIMAGE_DATA_DIRECTORY DataDirectory[XIMAGE_NUMBEROF_DIRECTORY_ENTRIES];
|
||||
} XIMAGE_OPTIONAL_HEADER, *PXIMAGE_OPTIONAL_HEADER;
|
||||
|
||||
typedef XIMAGE_OPTIONAL_HEADER XIMAGE_OPTIONAL_HEADER32;
|
||||
|
||||
#define XIMAGE_SIZEOF_NT_OPTIONAL_HEADER 224
|
||||
|
||||
#define XIMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b
|
||||
|
||||
typedef struct _XIMAGE_NT_HEADERS {
|
||||
uint32_t Signature;
|
||||
XIMAGE_FILE_HEADER FileHeader;
|
||||
XIMAGE_OPTIONAL_HEADER OptionalHeader;
|
||||
} XIMAGE_NT_HEADERS, *PXIMAGE_NT_HEADERS;
|
||||
|
||||
typedef XIMAGE_NT_HEADERS XIMAGE_NT_HEADERS32;
|
||||
|
||||
#define XIMAGE_FIRST_SECTION(ntheader) \
|
||||
((PXIMAGE_SECTION_HEADER)((uint8_t*)ntheader + \
|
||||
offsetof(XIMAGE_NT_HEADERS, OptionalHeader) + \
|
||||
((PXIMAGE_NT_HEADERS)(ntheader)) \
|
||||
->FileHeader.SizeOfOptionalHeader))
|
||||
|
||||
#define XIMAGE_SUBSYSTEM_XBOX 14
|
||||
|
||||
/*
|
||||
* Section header format.
|
||||
*/
|
||||
|
||||
#define XIMAGE_SIZEOF_SHORT_NAME 8
|
||||
|
||||
typedef struct _XIMAGE_SECTION_HEADER {
|
||||
uint8_t Name[XIMAGE_SIZEOF_SHORT_NAME];
|
||||
union {
|
||||
uint32_t PhysicalAddress;
|
||||
uint32_t VirtualSize;
|
||||
} Misc;
|
||||
uint32_t VirtualAddress;
|
||||
uint32_t SizeOfRawData;
|
||||
uint32_t PointerToRawData;
|
||||
uint32_t PointerToRelocations;
|
||||
uint32_t PointerToLinenumbers;
|
||||
uint16_t NumberOfRelocations;
|
||||
uint16_t NumberOfLinenumbers;
|
||||
uint32_t Characteristics;
|
||||
} XIMAGE_SECTION_HEADER, *PXIMAGE_SECTION_HEADER;
|
||||
|
||||
#define XIMAGE_SIZEOF_SECTION_HEADER 40
|
||||
|
||||
typedef struct _XIMAGE_EXPORT_DIRECTORY {
|
||||
uint32_t Characteristics;
|
||||
uint32_t TimeDateStamp;
|
||||
uint16_t MajorVersion;
|
||||
uint16_t MinorVersion;
|
||||
uint32_t Name;
|
||||
uint32_t Base;
|
||||
uint32_t NumberOfFunctions;
|
||||
uint32_t NumberOfNames;
|
||||
uint32_t** AddressOfFunctions;
|
||||
uint32_t** AddressOfNames;
|
||||
uint16_t** AddressOfNameOrdinals;
|
||||
} XIMAGE_EXPORT_DIRECTORY, *PXIMAGE_EXPORT_DIRECTORY;
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2025 Xenia Canary. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/base/png_utils.h"
|
||||
#include "xenia/base/filesystem.h"
|
||||
|
||||
#include "third_party/stb/stb_image.h"
|
||||
|
||||
namespace xe {
|
||||
|
||||
bool IsFilePngImage(const std::filesystem::path& file_path) {
|
||||
FILE* file = xe::filesystem::OpenFile(file_path, "rb");
|
||||
if (!file) {
|
||||
return false;
|
||||
}
|
||||
|
||||
constexpr uint8_t magic_size = 4;
|
||||
char magic[magic_size];
|
||||
if (fread(&magic, 1, magic_size, file) != magic_size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
|
||||
if (magic[1] != 'P' || magic[2] != 'N' || magic[3] != 'G') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::pair<uint16_t, uint16_t> GetImageResolution(
|
||||
const std::filesystem::path& file_path) {
|
||||
FILE* file = xe::filesystem::OpenFile(file_path, "rb");
|
||||
if (!file) {
|
||||
return {};
|
||||
}
|
||||
|
||||
int width, height, channels;
|
||||
if (!stbi_info_from_file(file, &width, &height, &channels)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
return {width, height};
|
||||
}
|
||||
|
||||
std::vector<uint8_t> ReadPngFromFile(const std::filesystem::path& file_path) {
|
||||
FILE* file = xe::filesystem::OpenFile(file_path, "rb");
|
||||
if (!file) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto file_size = std::filesystem::file_size(file_path);
|
||||
std::vector<uint8_t> data(file_size);
|
||||
fread(data.data(), 1, file_size, file);
|
||||
fclose(file);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
} // namespace xe
|
|
@ -0,0 +1,27 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2025 Xenia Canary. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_BASE_PNG_UTILS_H_
|
||||
#define XENIA_BASE_PNG_UTILS_H_
|
||||
|
||||
#include <filesystem>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace xe {
|
||||
|
||||
bool IsFilePngImage(const std::filesystem::path& file_path);
|
||||
std::pair<uint16_t, uint16_t> GetImageResolution(
|
||||
const std::filesystem::path& file_path);
|
||||
|
||||
std::vector<uint8_t> ReadPngFromFile(const std::filesystem::path& file_path);
|
||||
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_BASE_PNG_UTILS_H_
|
|
@ -8,8 +8,6 @@ project("xenia-base")
|
|||
links({
|
||||
"fmt",
|
||||
})
|
||||
defines({
|
||||
})
|
||||
local_platform_files()
|
||||
removefiles({"console_app_main_*.cc"})
|
||||
removefiles({"main_init_*.cc"})
|
||||
|
@ -17,4 +15,6 @@ project("xenia-base")
|
|||
"debug_visualizers.natvis",
|
||||
})
|
||||
|
||||
if enableTests then
|
||||
include("testing")
|
||||
end
|
||||
|
|
|
@ -7,9 +7,6 @@
|
|||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
// NOTE: this must be included before microprofile as macro expansion needs
|
||||
// XELOGI.
|
||||
#include "xenia/base/logging.h"
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
*/
|
||||
|
||||
#include "xenia/base/ring_buffer.h"
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
namespace xe {
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#include "xenia/base/socket.h"
|
||||
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
#include "xenia/base/logging.h"
|
||||
#include "xenia/base/platform_win.h"
|
||||
|
@ -96,7 +95,7 @@ class Win32Socket : public Socket {
|
|||
|
||||
// Keepalive for a looong time, as we may be paused by the debugger/etc.
|
||||
struct tcp_keepalive alive;
|
||||
alive.onoff = TRUE;
|
||||
alive.onoff = true;
|
||||
alive.keepalivetime = 7200000;
|
||||
alive.keepaliveinterval = 6000;
|
||||
DWORD bytes_returned;
|
||||
|
@ -209,7 +208,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 +230,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;
|
||||
|
|
|
@ -10,8 +10,6 @@
|
|||
#include "xenia/base/string.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <algorithm>
|
||||
#include <locale>
|
||||
|
||||
#include "xenia/base/platform.h"
|
||||
#if XE_PLATFORM_WIN32
|
||||
|
@ -22,7 +20,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;
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
#include "xenia/base/string_buffer.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdarg>
|
||||
|
||||
#include "xenia/base/assert.h"
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#ifndef XENIA_BASE_STRING_KEY_H_
|
||||
#define XENIA_BASE_STRING_KEY_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
|
||||
|
@ -58,6 +59,41 @@ struct string_key : internal::string_key_base {
|
|||
};
|
||||
};
|
||||
|
||||
struct string_key_insensitive : internal::string_key_base {
|
||||
public:
|
||||
explicit string_key_insensitive(const std::string_view value)
|
||||
: string_key_base(value) {}
|
||||
explicit string_key_insensitive(std::string value) : string_key_base(value) {}
|
||||
|
||||
static string_key_insensitive create(const std::string_view value) {
|
||||
return string_key_insensitive(std::string(value));
|
||||
}
|
||||
|
||||
static string_key_insensitive create(std::string value) {
|
||||
return string_key_insensitive(value);
|
||||
}
|
||||
|
||||
bool operator==(const string_key_insensitive& other) const {
|
||||
return other.view().size() == view().size() &&
|
||||
std::ranges::equal(
|
||||
other.view(), view(), {},
|
||||
[](char ch) {
|
||||
return std::tolower(static_cast<unsigned char>(ch));
|
||||
},
|
||||
[](char ch) {
|
||||
return std::tolower(static_cast<unsigned char>(ch));
|
||||
});
|
||||
}
|
||||
|
||||
size_t hash() const { return utf8::hash_fnv1a(view()); }
|
||||
|
||||
struct Hash {
|
||||
size_t operator()(const string_key_insensitive& t) const {
|
||||
return t.hash();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
struct string_key_case : internal::string_key_base {
|
||||
public:
|
||||
explicit string_key_case(const std::string_view value)
|
||||
|
@ -91,6 +127,13 @@ struct hash<xe::string_key> {
|
|||
std::size_t operator()(const xe::string_key& t) const { return t.hash(); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<xe::string_key_insensitive> {
|
||||
std::size_t operator()(const xe::string_key_insensitive& t) const {
|
||||
return t.hash();
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<xe::string_key_case> {
|
||||
std::size_t operator()(const xe::string_key_case& t) const {
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -29,7 +29,11 @@ void LaunchWebBrowser(const std::string_view url) {
|
|||
system(cmd.c_str());
|
||||
}
|
||||
|
||||
void LaunchFileExplorer(const std::filesystem::path& path) { assert_always(); }
|
||||
void LaunchFileExplorer(const std::filesystem::path& path) {
|
||||
auto cmd = std::string("xdg-open ");
|
||||
cmd.append(path);
|
||||
system(cmd.c_str());
|
||||
}
|
||||
|
||||
void ShowSimpleMessageBox(SimpleMessageBoxType type, std::string_view message) {
|
||||
void* libsdl2 = dlopen("libSDL2.so", RTLD_LAZY | RTLD_LOCAL);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -17,15 +17,11 @@
|
|||
#include <pthread.h>
|
||||
#include <sched.h>
|
||||
#include <signal.h>
|
||||
#include <sys/eventfd.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <ctime>
|
||||
#include <memory>
|
||||
|
||||
#include "logging.h"
|
||||
|
||||
|
@ -82,8 +78,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 +156,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 +175,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 +207,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 +232,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 +256,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);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual void* native_handle() const {
|
||||
return cond_.native_handle();
|
||||
}
|
||||
|
||||
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 +286,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 +312,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 +321,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 +331,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 +341,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 +354,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 +365,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 +382,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 +400,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 +412,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 +420,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 +434,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 +447,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 +466,7 @@ struct ThreadStartData {
|
|||
};
|
||||
|
||||
template <>
|
||||
class PosixCondition<Thread> : public PosixConditionBase {
|
||||
class PosixCondition<Thread> final : public PosixConditionBase {
|
||||
enum class State {
|
||||
kUninitialized,
|
||||
kRunning,
|
||||
|
@ -526,13 +520,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 +547,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
|
|||
assert_always();
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
bool Signal() override { return true; }
|
||||
|
@ -555,7 +555,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 +579,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 +603,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 +625,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 +646,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
|
|||
#endif
|
||||
}
|
||||
|
||||
int priority() {
|
||||
int priority() const {
|
||||
WaitStarted();
|
||||
int policy;
|
||||
sched_param param{};
|
||||
|
@ -658,7 +658,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 +678,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 +691,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 +701,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 +731,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 +747,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,10 +755,10 @@ 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) {
|
||||
if (pthread_kill(thread_, GetSystemSignal(SignalType::kThreadTerminate)) !=
|
||||
0) {
|
||||
assert_always();
|
||||
}
|
||||
#else
|
||||
|
@ -767,17 +767,16 @@ class PosixCondition<Thread> : public PosixConditionBase {
|
|||
}
|
||||
#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 +787,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 +812,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
|
|||
|
||||
class PosixWaitHandle {
|
||||
public:
|
||||
virtual ~PosixWaitHandle() = default;
|
||||
virtual PosixConditionBase& condition() = 0;
|
||||
};
|
||||
|
||||
|
@ -829,7 +829,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 +912,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 +941,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 +965,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 +977,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 +1032,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 +1104,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 +1120,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();
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <forward_list>
|
||||
|
||||
#include "third_party/disruptorplus/include/disruptorplus/blocking_wait_strategy.hpp"
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -11,11 +11,8 @@
|
|||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <locale>
|
||||
#include <numeric>
|
||||
#include <tuple>
|
||||
|
||||
#define UTF_CPP_CPLUSPLUS 201703L
|
||||
#define UTF_CPP_CPLUSPLUS 202002L
|
||||
#include "third_party/utfcpp/source/utf8.h"
|
||||
|
||||
namespace utfcpp = utf8;
|
||||
|
@ -82,10 +79,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;
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include <cstddef>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -14,8 +14,6 @@ project("xenia-cpu-backend-x64")
|
|||
})
|
||||
defines({
|
||||
"CAPSTONE_X86_ATT_DISABLE",
|
||||
"CAPSTONE_DIET_NO",
|
||||
"CAPSTONE_X86_REDUCE_NO",
|
||||
"CAPSTONE_HAS_X86",
|
||||
"CAPSTONE_USE_SYS_DYN_MEM",
|
||||
"XBYAK_NO_OP_NAMES",
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
#include "xenia/cpu/backend/x64/x64_backend.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include "third_party/capstone/include/capstone/capstone.h"
|
||||
#include "third_party/capstone/include/capstone/x86.h"
|
||||
|
@ -636,7 +635,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 +680,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 +703,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 +734,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 +780,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 +837,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 +877,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 +1736,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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
#include "xenia/cpu/backend/x64/x64_sequences.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
#include "xenia/base/cvar.h"
|
||||
|
|
|
@ -24,9 +24,7 @@
|
|||
|
||||
#include "xenia/cpu/backend/x64/x64_sequences.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/base/clock.h"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -9,8 +9,6 @@
|
|||
|
||||
#include "xenia/cpu/backend/x64/x64_tracers.h"
|
||||
|
||||
#include <cinttypes>
|
||||
|
||||
#include "xenia/base/logging.h"
|
||||
#include "xenia/base/vec128.h"
|
||||
#include "xenia/cpu/backend/x64/x64_emitter.h"
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
#include "xenia/cpu/compiler/passes/register_allocation_pass.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
#include "xenia/base/assert.h"
|
||||
|
|
|
@ -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.",
|
||||
|
|
|
@ -9,9 +9,6 @@
|
|||
|
||||
#include "xenia/cpu/elf_module.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
|
||||
#include "xenia/base/byte_order.h"
|
||||
#include "xenia/base/logging.h"
|
||||
#include "xenia/cpu/processor.h"
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
#include "xenia/cpu/hir/hir_builder.h"
|
||||
|
||||
#include <cinttypes>
|
||||
#include <cstdarg>
|
||||
#include <cstring>
|
||||
|
||||
|
@ -2100,7 +2099,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,
|
||||
|
|
|
@ -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, \
|
||||
|
|
|
@ -9,9 +9,7 @@
|
|||
|
||||
#include "xenia/cpu/mmio_handler.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <utility>
|
||||
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/base/byte_order.h"
|
||||
|
|
|
@ -9,11 +9,6 @@
|
|||
|
||||
#include "xenia/cpu/module.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <sstream> // NOLINT(readability/streams): should be replaced.
|
||||
#include <string>
|
||||
|
||||
#include "xenia/base/profiling.h"
|
||||
#include "xenia/base/threading.h"
|
||||
#include "xenia/cpu/processor.h"
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
#include "xenia/cpu/ppc/ppc_context.h"
|
||||
|
||||
#include <cinttypes>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "xenia/base/assert.h"
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue