Compare commits
82 Commits
0dc0f18
...
canary_exp
Author | SHA1 | Date |
---|---|---|
![]() |
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 |
|
@ -0,0 +1,59 @@
|
|||
name: Create release
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
os:
|
||||
required: true
|
||||
type: string
|
||||
secrets:
|
||||
RELEASE_TOKEN:
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
release:
|
||||
name: Release
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/download-artifact@main
|
||||
- name: Release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
GH_REPO: ${{ github.repository_owner }}/xenia-canary-releases
|
||||
notes: ${{ github.event.head_commit.message }}
|
||||
run: |
|
||||
rm -rf **/*.pdb
|
||||
case ${{ inputs.os }} in
|
||||
windows)
|
||||
asset=xenia_canary_windows.zip
|
||||
7z a $asset './xenia_canary_windows/*'
|
||||
;;
|
||||
linux)
|
||||
asset=xenia_canary_linux.tar.gz
|
||||
cd xenia_canary_linux
|
||||
chmod +x xenia_canary
|
||||
tar -cvpf ../$asset *
|
||||
cd -
|
||||
;;
|
||||
esac
|
||||
if [ ! -f $asset ]; then
|
||||
echo "::error::$asset doesn't exist!"
|
||||
exit 1
|
||||
fi
|
||||
if [ $(stat -c%s $asset) -lt 100000 ]; then
|
||||
echo "::error::$asset is too small!"
|
||||
exit 1
|
||||
fi
|
||||
create_or_edit_release() {
|
||||
local tag=$1
|
||||
local title=$2
|
||||
if gh release view $tag; then
|
||||
gh release edit $tag -t $title -n "$notes"
|
||||
gh release upload $tag $asset --clobber
|
||||
else
|
||||
gh release create $tag $asset --target 925ed98d5dce604b651027c36fb522dc1ff0fa55 -t $title -n "$notes"
|
||||
fi
|
||||
}
|
||||
tag=${GITHUB_SHA::7}
|
||||
create_or_edit_release $tag ${tag}_$GITHUB_REF_NAME
|
||||
create_or_edit_release $GITHUB_REF_NAME $tag
|
|
@ -7,13 +7,14 @@ on:
|
|||
- '.drone.star'
|
||||
- '.gitattributes'
|
||||
- '.gitignore'
|
||||
- '.gdbinit'
|
||||
- '.github/*'
|
||||
- '.github/workflows/Windows_build.yml'
|
||||
- '.github/*_TEMPLATE/**'
|
||||
- '*.bat'
|
||||
- '*.md'
|
||||
- '*.yml'
|
||||
- '*.ps1'
|
||||
- '*.txt'
|
||||
- '*.yml'
|
||||
- 'docs/**'
|
||||
- 'src/**/*_windows.*'
|
||||
- 'src/**/*_android.*'
|
||||
|
@ -25,13 +26,14 @@ on:
|
|||
- '.drone.star'
|
||||
- '.gitattributes'
|
||||
- '.gitignore'
|
||||
- '.gdbinit'
|
||||
- '.github/*'
|
||||
- '.github/workflows/Windows_build.yml'
|
||||
- '.github/*_TEMPLATE/**'
|
||||
- '*.bat'
|
||||
- '*.md'
|
||||
- '*.yml'
|
||||
- '*.ps1'
|
||||
- '*.txt'
|
||||
- '*.yml'
|
||||
- 'docs/**'
|
||||
- 'src/**/*_windows.*'
|
||||
- 'src/**/*_android.*'
|
||||
|
@ -42,36 +44,68 @@ on:
|
|||
jobs:
|
||||
lint:
|
||||
name: Lint
|
||||
runs-on: windows-latest
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@main
|
||||
- name: Check Clang-Format Version
|
||||
run: clang-format --version
|
||||
- name: Setup
|
||||
run: |
|
||||
LLVM_VERSION=18 # Same as Windows
|
||||
UBUNTU_BASE=jammy
|
||||
wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc
|
||||
sudo apt-add-repository "deb http://apt.llvm.org/${UBUNTU_BASE}/ llvm-toolchain-${UBUNTU_BASE}-$LLVM_VERSION main"
|
||||
sudo apt-get -y update
|
||||
sudo apt-get -y install clang-format-$LLVM_VERSION
|
||||
- name: Lint
|
||||
run: ./xb lint --all
|
||||
|
||||
build-linux:
|
||||
name: Build (Linux) # runner.os can't be used here
|
||||
build:
|
||||
name: Build (LLVM ${{ matrix.LLVM_VERSION }})
|
||||
needs: lint
|
||||
runs-on: ubuntu-24.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
LLVM_VERSION: [19]
|
||||
steps:
|
||||
- uses: actions/checkout@main
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Set environment variables
|
||||
run: |
|
||||
LLVM_VERSION=19
|
||||
echo "LLVM_VERSION=$LLVM_VERSION" >> $GITHUB_ENV
|
||||
echo "UBUNTU_BASE=jammy" >> $GITHUB_ENV
|
||||
echo "CC=clang-${LLVM_VERSION}" >> $GITHUB_ENV
|
||||
echo "CXX=clang++-${LLVM_VERSION}" >> $GITHUB_ENV
|
||||
echo "AR=llvm-ar-${LLVM_VERSION}" >> $GITHUB_ENV
|
||||
- name: Setup
|
||||
run: |
|
||||
UBUNTU_BASE=jammy
|
||||
wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc
|
||||
sudo apt-add-repository "deb http://apt.llvm.org/${UBUNTU_BASE}/ llvm-toolchain-${UBUNTU_BASE}-$LLVM_VERSION main"
|
||||
sudo apt-add-repository "deb http://apt.llvm.org/${UBUNTU_BASE}/ llvm-toolchain-${UBUNTU_BASE}-${{ matrix.LLVM_VERSION }} main"
|
||||
sudo apt-get -y update
|
||||
sudo apt-get -y install mesa-vulkan-drivers valgrind libc++-dev libc++abi-dev libgtk-3-dev libsdl2-dev libvulkan-dev libx11-dev libx11-xcb-dev clang-$LLVM_VERSION clang-format-$LLVM_VERSION llvm-$LLVM_VERSION
|
||||
sudo apt-get -y install mesa-vulkan-drivers valgrind libc++-dev libc++abi-dev libgtk-3-dev libsdl2-dev libvulkan-dev libx11-xcb-dev clang-${{ matrix.LLVM_VERSION }} llvm-${{ matrix.LLVM_VERSION }} ninja-build
|
||||
./xb setup
|
||||
- name: Build
|
||||
env:
|
||||
CC: clang-${{ matrix.LLVM_VERSION }}
|
||||
CXX: clang++-${{ matrix.LLVM_VERSION }}
|
||||
AR: llvm-ar-${{ matrix.LLVM_VERSION }}
|
||||
run: ./xb build --config=Release
|
||||
- name: Prepare artifacts
|
||||
id: prepare_artifacts
|
||||
run: |
|
||||
mkdir -p artifacts
|
||||
cp -r build/bin/Linux/Release/xenia_canary LICENSE artifacts
|
||||
- name: Upload xenia canary artifacts
|
||||
if: steps.prepare_artifacts.outcome == 'success'
|
||||
uses: actions/upload-artifact@main
|
||||
with:
|
||||
name: xenia_canary_linux
|
||||
path: artifacts
|
||||
if-no-files-found: error
|
||||
|
||||
create-release:
|
||||
name: Create release
|
||||
needs: [lint, build]
|
||||
if: |
|
||||
github.repository == 'xenia-canary/xenia-canary' &&
|
||||
github.event.action != 'pull_request' &&
|
||||
github.ref == 'refs/heads/canary_experimental'
|
||||
uses: ./.github/workflows/Create_release.yml
|
||||
with:
|
||||
os: linux
|
||||
secrets:
|
||||
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
|
|
|
@ -51,21 +51,17 @@ jobs:
|
|||
lint:
|
||||
name: Lint
|
||||
runs-on: windows-latest
|
||||
env:
|
||||
POWERSHELL_TELEMETRY_OPTOUT: 1
|
||||
steps:
|
||||
- uses: actions/checkout@main
|
||||
- name: Check Clang-Format Version
|
||||
run: clang-format --version
|
||||
- name: Lint
|
||||
run: .\xb lint --all
|
||||
|
||||
build-windows:
|
||||
name: Build (Windows, VS${{ matrix.vsver }}) # runner.os can't be used here
|
||||
build:
|
||||
name: Build
|
||||
needs: lint
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
vsver: [2022]
|
||||
runs-on: windows-${{ matrix.vsver }}
|
||||
runs-on: windows-2025
|
||||
env:
|
||||
POWERSHELL_TELEMETRY_OPTOUT: 1
|
||||
steps:
|
||||
|
@ -84,34 +80,21 @@ jobs:
|
|||
If ($LastExitCode -le 7) { echo "LastExitCode = $LastExitCode";$LastExitCode = 0 }
|
||||
- name: Upload xenia canary artifacts
|
||||
if: steps.prepare_artifacts.outcome == 'success'
|
||||
id: upload_artifacts
|
||||
uses: actions/upload-artifact@main
|
||||
with:
|
||||
name: xenia_canary_vs${{ matrix.vsver }}
|
||||
name: xenia_canary_windows
|
||||
path: artifacts\xenia_canary
|
||||
if-no-files-found: error
|
||||
- name: Create release
|
||||
if: |
|
||||
github.repository == 'xenia-canary/xenia-canary' &&
|
||||
github.event.action != 'pull_request' &&
|
||||
github.ref == 'refs/heads/canary_experimental' &&
|
||||
steps.upload_artifacts.outcome == 'success'
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
$asset="xenia_canary.zip"
|
||||
rm -recurse -force artifacts\xenia_canary\*.pdb # Ideally this would use xr, but I can't get it to work
|
||||
7z a $asset .\artifacts\xenia_canary\*
|
||||
If ($(Get-Item $asset).length -le 100000) {
|
||||
Throw "Error: Archive $asset too small!"
|
||||
}
|
||||
$tag=$env:GITHUB_SHA.SubString(0,7)
|
||||
$branch=$($env:GITHUB_REF -replace 'refs/heads/')
|
||||
$title="${tag}_$branch"
|
||||
gh release create $tag $asset --target $env:GITHUB_SHA -t $title
|
||||
# Remove canary_ to prevent conflicts from tag
|
||||
$tag=$($branch -replace 'canary_')
|
||||
gh release delete $tag -y
|
||||
git push --delete origin $tag
|
||||
git tag -d $tag
|
||||
gh release create $tag $asset --target $env:GITHUB_SHA -t $branch
|
||||
|
||||
create-release:
|
||||
name: Create release
|
||||
needs: [lint, build]
|
||||
if: |
|
||||
github.repository == 'xenia-canary/xenia-canary' &&
|
||||
github.event.action != 'pull_request' &&
|
||||
github.ref == 'refs/heads/canary_experimental'
|
||||
uses: ./.github/workflows/Create_release.yml
|
||||
with:
|
||||
os: windows
|
||||
secrets:
|
||||
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
url = https://github.com/libsdl-org/SDL.git
|
||||
[submodule "third_party/utfcpp"]
|
||||
path = third_party/utfcpp
|
||||
url = https://github.com/xenia-project/utfcpp.git
|
||||
url = https://github.com/nemtrif/utfcpp.git
|
||||
[submodule "third_party/fmt"]
|
||||
path = third_party/fmt
|
||||
url = https://github.com/fmtlib/fmt.git
|
||||
|
@ -103,3 +103,6 @@
|
|||
[submodule "third_party/pugixml"]
|
||||
path = third_party/pugixml
|
||||
url = https://github.com/zeux/pugixml.git
|
||||
[submodule "third_party/libusb"]
|
||||
path = third_party/libusb
|
||||
url = https://github.com/libusb/libusb.git
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
62
premake5.lua
62
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
|
||||
|
@ -30,6 +35,8 @@ cppdialect("C++20")
|
|||
exceptionhandling("On")
|
||||
rtti("On")
|
||||
symbols("On")
|
||||
characterset("Unicode")
|
||||
fatalwarnings("All")
|
||||
|
||||
-- TODO(DrChat): Find a way to disable this on other architectures.
|
||||
if ARCH ~= "ppc64" then
|
||||
|
@ -38,11 +45,6 @@ if ARCH ~= "ppc64" then
|
|||
filter({})
|
||||
end
|
||||
|
||||
characterset("Unicode")
|
||||
flags({
|
||||
"FatalWarnings", -- Treat warnings as errors.
|
||||
})
|
||||
|
||||
filter("kind:StaticLib")
|
||||
defines({
|
||||
"_LIB",
|
||||
|
@ -50,23 +52,24 @@ filter("kind:StaticLib")
|
|||
|
||||
filter("configurations:Checked")
|
||||
runtime("Debug")
|
||||
sanitize("Address")
|
||||
flags("NoIncrementalLink")
|
||||
editandcontinue("Off")
|
||||
staticruntime("Off")
|
||||
optimize("Off")
|
||||
defines({
|
||||
"DEBUG",
|
||||
})
|
||||
|
||||
filter({"configurations:Checked", "platforms:Windows"})
|
||||
buildoptions({
|
||||
"/RTCsu", -- Full Run-Time Checks.
|
||||
})
|
||||
|
||||
filter({"configurations:Checked", "platforms:Linux"})
|
||||
defines({
|
||||
"_GLIBCXX_DEBUG", -- libstdc++ debug mode
|
||||
})
|
||||
filter({"configurations:Release", "platforms:Windows"})
|
||||
buildoptions({
|
||||
"/Gw",
|
||||
"/Ob3",
|
||||
})
|
||||
|
||||
filter("configurations:Debug")
|
||||
runtime("Release")
|
||||
|
@ -75,6 +78,7 @@ filter("configurations:Debug")
|
|||
"DEBUG",
|
||||
"_NO_DEBUG_HEAP=1",
|
||||
})
|
||||
|
||||
filter({"configurations:Debug", "platforms:Linux"})
|
||||
defines({
|
||||
"_GLIBCXX_DEBUG", -- make dbg symbols work on some distros
|
||||
|
@ -88,19 +92,28 @@ filter("configurations:Release")
|
|||
})
|
||||
optimize("Speed")
|
||||
inlining("Auto")
|
||||
flags({
|
||||
"LinkTimeOptimization",
|
||||
"NoBufferSecurityCheck",
|
||||
})
|
||||
editandcontinue("Off")
|
||||
-- Not using floatingpoint("Fast") - NaN checks are used in some places
|
||||
-- (though rarely), overall preferable to avoid any functional differences
|
||||
-- between debug and release builds, and to have calculations involved in GPU
|
||||
-- (especially anything that may affect vertex position invariance) and CPU
|
||||
-- (such as constant propagation) emulation as predictable as possible,
|
||||
-- including handling of specials since games make assumptions about them.
|
||||
|
||||
filter({"configurations:Release", "platforms:Windows"})
|
||||
linktimeoptimization("On")
|
||||
flags({
|
||||
"NoBufferSecurityCheck"
|
||||
})
|
||||
buildoptions({
|
||||
"/Gw",
|
||||
"/Ob3",
|
||||
})
|
||||
|
||||
filter("platforms:Linux")
|
||||
system("linux")
|
||||
toolset("clang")
|
||||
vectorextensions("AVX2")
|
||||
buildoptions({
|
||||
-- "-mlzcnt", -- (don't) Assume lzcnt is supported.
|
||||
})
|
||||
|
@ -113,9 +126,6 @@ filter("platforms:Linux")
|
|||
"rt",
|
||||
})
|
||||
|
||||
filter({"platforms:Linux"})
|
||||
vectorextensions("AVX2")
|
||||
|
||||
filter({"platforms:Linux", "kind:*App"})
|
||||
linkgroups("On")
|
||||
|
||||
|
@ -145,6 +155,7 @@ filter({"platforms:Linux", "language:C++", "toolset:clang"})
|
|||
"deprecated-volatile",
|
||||
"switch",
|
||||
"deprecated-enum-enum-conversion",
|
||||
"attributes",
|
||||
})
|
||||
filter({"platforms:Linux", "language:C++", "toolset:clang", "files:*.cc or *.cpp"})
|
||||
buildoptions({
|
||||
|
@ -174,16 +185,8 @@ filter("platforms:Windows")
|
|||
toolset("msc")
|
||||
buildoptions({
|
||||
"/utf-8", -- 'build correctly on systems with non-Latin codepages'.
|
||||
-- Mark warnings as severe
|
||||
"/w14839", -- non-standard use of class 'type' as an argument to a variadic function
|
||||
"/w14840", -- non-portable use of class 'type' as an argument to a variadic function
|
||||
-- Disable warnings
|
||||
"/wd4100", -- Unreferenced parameters are ok.
|
||||
"/wd4201", -- Nameless struct/unions are ok.
|
||||
"/wd4512", -- 'assignment operator was implicitly defined as deleted'.
|
||||
"/wd4127", -- 'conditional expression is constant'.
|
||||
"/wd4324", -- 'structure was padded due to alignment specifier'.
|
||||
"/wd4189", -- 'local variable is initialized but not referenced'.
|
||||
})
|
||||
flags({
|
||||
"MultiProcessorCompile", -- Multiprocessor compilation.
|
||||
|
@ -275,6 +278,10 @@ workspace("xenia")
|
|||
include("third_party/zlib.lua")
|
||||
include("third_party/pugixml.lua")
|
||||
|
||||
if os.istarget("windows") then
|
||||
include("third_party/libusb.lua")
|
||||
end
|
||||
|
||||
if not os.istarget("android") then
|
||||
-- SDL2 requires sdl2-config, and as of November 2020 isn't high-quality on
|
||||
-- Android yet, most importantly in game controllers - the keycode and axis
|
||||
|
@ -292,9 +299,7 @@ workspace("xenia")
|
|||
removefiles({
|
||||
"src/xenia/base/app_win32.manifest"
|
||||
})
|
||||
removeflags({
|
||||
"FatalWarnings",
|
||||
})
|
||||
removefatalwarnings("All")
|
||||
end
|
||||
|
||||
include("src/xenia")
|
||||
|
@ -311,6 +316,7 @@ workspace("xenia")
|
|||
include("src/xenia/gpu/vulkan")
|
||||
include("src/xenia/hid")
|
||||
include("src/xenia/hid/nop")
|
||||
include("src/xenia/hid/skylander")
|
||||
include("src/xenia/kernel")
|
||||
include("src/xenia/patcher")
|
||||
include("src/xenia/ui")
|
||||
|
|
|
@ -167,8 +167,8 @@ using xe::ui::UIEvent;
|
|||
using namespace xe::hid;
|
||||
using namespace xe::gpu;
|
||||
|
||||
const std::string kRecentlyPlayedTitlesFilename = "recent.toml";
|
||||
const std::string kBaseTitle = "Xenia-canary";
|
||||
constexpr std::string_view kRecentlyPlayedTitlesFilename = "recent.toml";
|
||||
constexpr std::string_view kBaseTitle = "Xenia-canary";
|
||||
|
||||
EmulatorWindow::EmulatorWindow(Emulator* emulator,
|
||||
ui::WindowedAppContext& app_context,
|
||||
|
@ -181,7 +181,7 @@ EmulatorWindow::EmulatorWindow(Emulator* emulator,
|
|||
std::make_unique<ui::ImGuiDrawer>(window_.get(), kZOrderImGui)),
|
||||
display_config_game_config_load_callback_(
|
||||
new DisplayConfigGameConfigLoadCallback(*emulator, *this)) {
|
||||
base_title_ = kBaseTitle +
|
||||
base_title_ = std::string(kBaseTitle) +
|
||||
#ifdef DEBUG
|
||||
#if _NO_DEBUG_HEAP == 1
|
||||
" DEBUG"
|
||||
|
@ -569,6 +569,96 @@ void EmulatorWindow::DisplayConfigDialog::OnDraw(ImGuiIO& io) {
|
|||
}
|
||||
}
|
||||
|
||||
void EmulatorWindow::ContentInstallDialog::OnDraw(ImGuiIO& io) {
|
||||
ImGui::SetNextWindowPos(ImVec2(20, 20), ImGuiCond_FirstUseEver);
|
||||
ImGui::SetNextWindowSize(ImVec2(20, 20), ImGuiCond_FirstUseEver);
|
||||
|
||||
bool dialog_open = true;
|
||||
if (!ImGui::Begin(
|
||||
fmt::format("Installation Progress###{}", window_id_).c_str(),
|
||||
&dialog_open,
|
||||
ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_AlwaysAutoResize |
|
||||
ImGuiWindowFlags_HorizontalScrollbar)) {
|
||||
Close();
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
|
||||
bool is_everything_installed = true;
|
||||
for (const auto& entry : *installation_entries_) {
|
||||
ImGui::BeginTable(fmt::format("table_{}", entry.name_).c_str(), 2);
|
||||
ImGui::TableNextRow(0);
|
||||
ImGui::TableSetColumnIndex(0);
|
||||
if (entry.icon_) {
|
||||
ImGui::Image(reinterpret_cast<ImTextureID>(entry.icon_.get()),
|
||||
ui::default_image_icon_size);
|
||||
} else {
|
||||
ImGui::Dummy(ui::default_image_icon_size);
|
||||
}
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
ImGui::Text("Name: %s", entry.name_.c_str());
|
||||
ImGui::Text("Installation Path:");
|
||||
ImGui::SameLine();
|
||||
if (ImGui::TextLink(
|
||||
xe::path_to_utf8(entry.data_installation_path_).c_str())) {
|
||||
LaunchFileExplorer(emulator_window_.emulator_->content_root() /
|
||||
entry.data_installation_path_);
|
||||
}
|
||||
|
||||
if (entry.content_type_ != xe::XContentType::kInvalid) {
|
||||
ImGui::Text("Content Type: %s",
|
||||
XContentTypeMap.at(entry.content_type_).c_str());
|
||||
}
|
||||
|
||||
std::string result = fmt::format(
|
||||
"Status: {}", xe::Emulator::installStateStringName[static_cast<uint8_t>(
|
||||
entry.installation_state_)]);
|
||||
|
||||
if (entry.installation_state_ == xe::Emulator::InstallState::failed) {
|
||||
result += fmt::format(" - {} ({:08X})",
|
||||
entry.installation_error_message_.c_str(),
|
||||
entry.installation_result_);
|
||||
}
|
||||
|
||||
ImGui::Text("%s", result.c_str());
|
||||
ImGui::EndTable();
|
||||
|
||||
if (entry.content_size_ > 0) {
|
||||
ImGui::ProgressBar(static_cast<float>(entry.currently_installed_size_) /
|
||||
entry.content_size_);
|
||||
|
||||
if (entry.currently_installed_size_ != entry.content_size_ &&
|
||||
entry.installation_result_ == X_ERROR_SUCCESS) {
|
||||
is_everything_installed = false;
|
||||
}
|
||||
} else {
|
||||
ImGui::ProgressBar(0.0f);
|
||||
}
|
||||
|
||||
if (installation_entries_->size() > 1) {
|
||||
ImGui::Separator();
|
||||
}
|
||||
}
|
||||
ImGui::Spacing();
|
||||
|
||||
ImGui::BeginDisabled(!is_everything_installed);
|
||||
if (ImGui::Button("Close")) {
|
||||
ImGui::EndDisabled();
|
||||
Close();
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
|
||||
if (!dialog_open && is_everything_installed) {
|
||||
Close();
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
bool EmulatorWindow::Initialize() {
|
||||
window_->AddListener(&window_listener_);
|
||||
window_->AddInputListener(&window_listener_, kZOrderEmulatorWindowInput);
|
||||
|
@ -935,11 +1025,16 @@ void EmulatorWindow::OnMouseUp(const ui::MouseEvent& e) {
|
|||
|
||||
void EmulatorWindow::TakeScreenshot() {
|
||||
xe::ui::RawImage image;
|
||||
|
||||
imgui_drawer_->EnableNotifications(false);
|
||||
|
||||
if (!GetGraphicsSystemPresenter()->CaptureGuestOutput(image) ||
|
||||
GetGraphicsSystemPresenter() == nullptr) {
|
||||
XELOGE("Failed to capture guest output for screenshot");
|
||||
return;
|
||||
}
|
||||
|
||||
imgui_drawer_->EnableNotifications(true);
|
||||
ExportScreenshot(image);
|
||||
}
|
||||
|
||||
|
@ -1006,9 +1101,9 @@ void EmulatorWindow::ToggleFullscreenOnDoubleClick() {
|
|||
// this function tests if user has double clicked.
|
||||
// if double click was achieved the fullscreen gets toggled
|
||||
const auto now = steady_clock::now(); // current mouse event time
|
||||
const int16_t mouse_down_max_threshold = 250;
|
||||
const int16_t mouse_up_max_threshold = 250;
|
||||
const int16_t mouse_up_down_max_delta = 100;
|
||||
constexpr int16_t mouse_down_max_threshold = 250;
|
||||
constexpr int16_t mouse_up_max_threshold = 250;
|
||||
constexpr int16_t mouse_up_down_max_delta = 100;
|
||||
// max delta to prevent 'chaining' of double clicks with next mouse events
|
||||
|
||||
const auto last_mouse_down_delta = diff_in_ms(now, last_mouse_down);
|
||||
|
@ -1083,62 +1178,27 @@ void EmulatorWindow::InstallContent() {
|
|||
return;
|
||||
}
|
||||
|
||||
using content_installation_data =
|
||||
std::tuple<X_STATUS, std::string, std::string>;
|
||||
std::map<XContentType, std::vector<content_installation_data>>
|
||||
content_installation_details;
|
||||
std::shared_ptr<std::vector<Emulator::ContentInstallEntry>>
|
||||
content_installation_status =
|
||||
std::make_shared<std::vector<Emulator::ContentInstallEntry>>();
|
||||
|
||||
for (const auto& path : paths) {
|
||||
// Normalize the path and make absolute.
|
||||
auto abs_path = std::filesystem::absolute(path);
|
||||
|
||||
Emulator::ContentInstallationInfo installation_info;
|
||||
auto result = emulator_->InstallContentPackage(abs_path, installation_info);
|
||||
|
||||
auto entry =
|
||||
content_installation_details.find(installation_info.content_type);
|
||||
|
||||
// There is no entry with that specific type of XContent, so we must add it.
|
||||
if (entry == content_installation_details.end()) {
|
||||
content_installation_details.insert({installation_info.content_type, {}});
|
||||
entry = content_installation_details.find(installation_info.content_type);
|
||||
};
|
||||
|
||||
entry->second.push_back({result, installation_info.content_name,
|
||||
installation_info.installation_path});
|
||||
content_installation_status->push_back({path});
|
||||
}
|
||||
|
||||
// Prepare installation process summary message
|
||||
std::string summary = "Installation result: \n";
|
||||
for (auto& entry : *content_installation_status) {
|
||||
emulator_->ProcessContentPackageHeader(entry.path_, entry);
|
||||
}
|
||||
|
||||
for (const auto& content_type : content_installation_details) {
|
||||
if (XContentTypeMap.find(content_type.first) != XContentTypeMap.cend()) {
|
||||
summary += XContentTypeMap.at(content_type.first) + ":\n";
|
||||
} else {
|
||||
summary += "Unknown:\n";
|
||||
auto installationThread = std::thread([this, content_installation_status] {
|
||||
for (auto& entry : *content_installation_status) {
|
||||
emulator_->InstallContentPackage(entry.path_, entry);
|
||||
}
|
||||
});
|
||||
installationThread.detach();
|
||||
|
||||
for (const auto& content_installation_entry : content_type.second) {
|
||||
const std::string status =
|
||||
std::get<0>(content_installation_entry) == X_STATUS_SUCCESS
|
||||
? "Success"
|
||||
: fmt::format("Failed (0x{:08X})",
|
||||
std::get<0>(content_installation_entry));
|
||||
|
||||
summary += fmt::format("\t{} - {} => {}\n", status,
|
||||
std::get<1>(content_installation_entry),
|
||||
std::get<2>(content_installation_entry));
|
||||
}
|
||||
|
||||
summary += "\n";
|
||||
}
|
||||
|
||||
if (content_installation_details.count(XContentType::kProfile)) {
|
||||
emulator_->kernel_state()->xam_state()->profile_manager()->ReloadProfiles();
|
||||
}
|
||||
|
||||
xe::ui::ImGuiDialog::ShowMessageBox(imgui_drawer_.get(),
|
||||
"Content Installation Summary", summary);
|
||||
new ContentInstallDialog(imgui_drawer_.get(), *this,
|
||||
content_installation_status);
|
||||
}
|
||||
|
||||
void EmulatorWindow::ExtractZarchive() {
|
||||
|
@ -1424,6 +1484,12 @@ void EmulatorWindow::ToggleControllerVibration() {
|
|||
auto input_lock = input_sys->lock();
|
||||
|
||||
input_sys->ToggleVibration();
|
||||
|
||||
if (emulator_->kernel_state()) {
|
||||
emulator_->kernel_state()->BroadcastNotification(
|
||||
kXNotificationSystemProfileSettingChanged,
|
||||
static_cast<uint32_t>(input_sys->GetConnectedSlots().count()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1624,7 +1690,7 @@ EmulatorWindow::ControllerHotKey EmulatorWindow::ProcessControllerHotkey(
|
|||
}
|
||||
|
||||
// Hotkey cool-down to prevent toggling too fast
|
||||
const std::chrono::milliseconds delay(75);
|
||||
constexpr std::chrono::milliseconds delay(75);
|
||||
|
||||
// If the Xbox Gamebar is enabled or the Guide button is disabled then
|
||||
// replace the Guide button with the Back button without redeclaring the key
|
||||
|
@ -1794,10 +1860,11 @@ EmulatorWindow::ControllerHotKey EmulatorWindow::ProcessControllerHotkey(
|
|||
}
|
||||
|
||||
if (!notificationTitle.empty()) {
|
||||
app_context_.CallInUIThread([&]() {
|
||||
new xe::ui::HostNotificationWindow(imgui_drawer(), notificationTitle,
|
||||
notificationDesc, 0);
|
||||
});
|
||||
app_context_.CallInUIThread(
|
||||
[imgui_drawer = imgui_drawer(), notificationTitle, notificationDesc]() {
|
||||
new xe::ui::HostNotificationWindow(imgui_drawer, notificationTitle,
|
||||
notificationDesc, 0);
|
||||
});
|
||||
}
|
||||
|
||||
xe::threading::Sleep(delay);
|
||||
|
@ -1808,7 +1875,7 @@ EmulatorWindow::ControllerHotKey EmulatorWindow::ProcessControllerHotkey(
|
|||
void EmulatorWindow::VibrateController(xe::hid::InputSystem* input_sys,
|
||||
uint32_t user_index,
|
||||
bool toggle_rumble) {
|
||||
const std::chrono::milliseconds rumble_duration(100);
|
||||
constexpr std::chrono::milliseconds rumble_duration(100);
|
||||
|
||||
// Hold lock while sleeping this thread for the duration of the rumble,
|
||||
// otherwise the rumble may fail.
|
||||
|
@ -1830,7 +1897,7 @@ void EmulatorWindow::VibrateController(xe::hid::InputSystem* input_sys,
|
|||
void EmulatorWindow::GamepadHotKeys() {
|
||||
X_INPUT_STATE state;
|
||||
|
||||
const std::chrono::milliseconds thread_delay(75);
|
||||
constexpr std::chrono::milliseconds thread_delay(75);
|
||||
|
||||
auto input_sys = emulator_->input_system();
|
||||
|
||||
|
@ -1889,8 +1956,7 @@ void EmulatorWindow::DisplayHotKeysConfig() {
|
|||
|
||||
if (!guide_enabled) {
|
||||
pretty_text = std::regex_replace(
|
||||
pretty_text,
|
||||
std::regex("Guide", std::regex_constants::syntax_option_type::icase),
|
||||
pretty_text, std::regex("Guide", std::regex_constants::icase),
|
||||
"Back");
|
||||
}
|
||||
|
||||
|
|
|
@ -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")
|
||||
links({
|
||||
"xenia-gpu-vulkan-trace-viewer",
|
||||
"xenia-hid-demo",
|
||||
"xenia-ui-window-vulkan-demo",
|
||||
})
|
||||
if enableMiscSubprojects then
|
||||
links({
|
||||
"xenia-gpu-vulkan-trace-viewer",
|
||||
"xenia-hid-demo",
|
||||
"xenia-ui-window-vulkan-demo",
|
||||
})
|
||||
end
|
||||
filter(NOT_SINGLE_LIBRARY_FILTER)
|
||||
kind("WindowedApp")
|
||||
|
||||
|
@ -114,15 +116,13 @@ project("xenia-app")
|
|||
"xenia-ui-d3d12",
|
||||
})
|
||||
|
||||
filter({"platforms:Windows", SINGLE_LIBRARY_FILTER})
|
||||
links({
|
||||
"xenia-gpu-d3d12-trace-viewer",
|
||||
"xenia-ui-window-d3d12-demo",
|
||||
})
|
||||
-- filter({"configurations:Release", "platforms:Windows"})
|
||||
-- buildoptions({
|
||||
-- "/O1",
|
||||
-- })
|
||||
if enableMiscSubprojects then
|
||||
filter({"platforms:Windows", SINGLE_LIBRARY_FILTER})
|
||||
links({
|
||||
"xenia-gpu-d3d12-trace-viewer",
|
||||
"xenia-ui-window-d3d12-demo",
|
||||
})
|
||||
end
|
||||
|
||||
filter("platforms:Windows")
|
||||
-- Only create the .user file if it doesn't already exist.
|
||||
|
|
|
@ -95,9 +95,15 @@ UPDATE_from_bool(mount_cache, 2024, 8, 31, 20, false);
|
|||
DEFINE_transient_path(target, "",
|
||||
"Specifies the target .xex or .iso to execute.",
|
||||
"General");
|
||||
#ifndef XE_PLATFORM_WIN32
|
||||
DEFINE_transient_bool(portable, false,
|
||||
"Specifies if Xenia should run in portable mode.",
|
||||
"General");
|
||||
#else
|
||||
DEFINE_transient_bool(portable, true,
|
||||
"Specifies if Xenia should run in portable mode.",
|
||||
"General");
|
||||
#endif
|
||||
|
||||
DECLARE_bool(debug);
|
||||
|
||||
|
@ -421,7 +427,7 @@ bool EmulatorApp::OnInitialize() {
|
|||
if (!cvars::portable &&
|
||||
!std::filesystem::exists(storage_root / "portable.txt")) {
|
||||
storage_root = xe::filesystem::GetUserFolder();
|
||||
#if defined(XE_PLATFORM_WIN32) || defined(XE_PLATFORM_GNU_LINUX)
|
||||
#if defined(XE_PLATFORM_WIN32) || defined(XE_PLATFORM_LINUX)
|
||||
storage_root = storage_root / "Xenia";
|
||||
#else
|
||||
// TODO(Triang3l): Point to the app's external storage "files" directory
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -160,23 +160,23 @@ static_assert_size(Xma2ExtraData, 34);
|
|||
|
||||
class XmaContext {
|
||||
public:
|
||||
static const uint32_t kBytesPerPacket = 2048;
|
||||
static const uint32_t kBitsPerPacket = kBytesPerPacket * 8;
|
||||
static const uint32_t kBitsPerHeader = 32;
|
||||
static constexpr uint32_t kBytesPerPacket = 2048;
|
||||
static constexpr uint32_t kBitsPerPacket = kBytesPerPacket * 8;
|
||||
static constexpr uint32_t kBitsPerHeader = 32;
|
||||
|
||||
static const uint32_t kBytesPerSample = 2;
|
||||
static const uint32_t kSamplesPerFrame = 512;
|
||||
static const uint32_t kSamplesPerSubframe = 128;
|
||||
static const uint32_t kBytesPerFrameChannel =
|
||||
static constexpr uint32_t kBytesPerSample = 2;
|
||||
static constexpr uint32_t kSamplesPerFrame = 512;
|
||||
static constexpr uint32_t kSamplesPerSubframe = 128;
|
||||
static constexpr uint32_t kBytesPerFrameChannel =
|
||||
kSamplesPerFrame * kBytesPerSample;
|
||||
static const uint32_t kBytesPerSubframeChannel =
|
||||
static constexpr uint32_t kBytesPerSubframeChannel =
|
||||
kSamplesPerSubframe * kBytesPerSample;
|
||||
|
||||
// static const uint32_t kOutputBytesPerBlock = 256;
|
||||
// static const uint32_t kOutputMaxSizeBytes = 31 * kOutputBytesPerBlock;
|
||||
|
||||
explicit XmaContext();
|
||||
~XmaContext();
|
||||
virtual ~XmaContext();
|
||||
|
||||
virtual int Setup(uint32_t id, Memory* memory, uint32_t guest_ptr) {
|
||||
return 0;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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]; }
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -168,7 +168,7 @@ static void ExceptionHandlerCallback(int signal_number, siginfo_t* signal_info,
|
|||
mcontext.gregs[REG_EFL] = greg_t(thread_context.eflags);
|
||||
uint32_t modified_register_index;
|
||||
// The order must match the order in X64Register.
|
||||
static const size_t kIntRegisterMap[] = {
|
||||
static constexpr size_t kIntRegisterMap[] = {
|
||||
REG_RAX, REG_RCX, REG_RDX, REG_RBX, REG_RSP, REG_RBP,
|
||||
REG_RSI, REG_RDI, REG_R8, REG_R9, REG_R10, REG_R11,
|
||||
REG_R12, REG_R13, REG_R14, REG_R15,
|
||||
|
|
|
@ -24,5 +24,42 @@ bool CreateParentFolder(const std::filesystem::path& path) {
|
|||
return true;
|
||||
}
|
||||
|
||||
std::error_code CreateFolder(const std::filesystem::path& path) {
|
||||
if (std::filesystem::exists(path)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::error_code ec;
|
||||
if (std::filesystem::create_directories(path, ec)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return ec;
|
||||
}
|
||||
|
||||
std::vector<FileInfo> ListDirectories(const std::filesystem::path& path) {
|
||||
std::vector<FileInfo> files = ListFiles(path);
|
||||
std::vector<FileInfo> directories = {};
|
||||
|
||||
std::copy_if(files.cbegin(), files.cend(), std::back_inserter(directories),
|
||||
[](const FileInfo& file) {
|
||||
return file.type == FileInfo::Type::kDirectory;
|
||||
});
|
||||
|
||||
return std::move(directories);
|
||||
}
|
||||
|
||||
std::vector<FileInfo> FilterByName(const std::vector<FileInfo>& files,
|
||||
const std::regex pattern) {
|
||||
std::vector<FileInfo> filtered_entries = {};
|
||||
|
||||
std::copy_if(
|
||||
files.cbegin(), files.cend(), std::back_inserter(filtered_entries),
|
||||
[pattern](const FileInfo& file) {
|
||||
return std::regex_match(file.name.filename().string(), pattern);
|
||||
});
|
||||
return std::move(filtered_entries);
|
||||
}
|
||||
|
||||
} // namespace filesystem
|
||||
} // namespace xe
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -192,20 +192,26 @@ std::unique_ptr<FileHandle> FileHandle::OpenExisting(
|
|||
return std::make_unique<PosixFileHandle>(path, handle);
|
||||
}
|
||||
|
||||
bool GetInfo(const std::filesystem::path& path, FileInfo* out_info) {
|
||||
std::optional<FileInfo> GetInfo(const std::filesystem::path& path) {
|
||||
FileInfo info{};
|
||||
struct stat st;
|
||||
if (stat(path.c_str(), &st) == 0) {
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
out_info->type = FileInfo::Type::kDirectory;
|
||||
info.type = FileInfo::Type::kDirectory;
|
||||
// On Linux st.st_size can have non-zero size (generally 4096) so make 0
|
||||
info.total_size = 0;
|
||||
} else {
|
||||
out_info->type = FileInfo::Type::kFile;
|
||||
info.type = FileInfo::Type::kFile;
|
||||
info.total_size = st.st_size;
|
||||
}
|
||||
out_info->create_timestamp = convertUnixtimeToWinFiletime(st.st_ctime);
|
||||
out_info->access_timestamp = convertUnixtimeToWinFiletime(st.st_atime);
|
||||
out_info->write_timestamp = convertUnixtimeToWinFiletime(st.st_mtime);
|
||||
return true;
|
||||
info.path = path.parent_path();
|
||||
info.name = path.filename();
|
||||
info.create_timestamp = convertUnixtimeToWinFiletime(st.st_ctime);
|
||||
info.access_timestamp = convertUnixtimeToWinFiletime(st.st_atime);
|
||||
info.write_timestamp = convertUnixtimeToWinFiletime(st.st_mtime);
|
||||
return std::move(info);
|
||||
}
|
||||
return false;
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<FileInfo> ListFiles(const std::filesystem::path& path) {
|
||||
|
@ -240,7 +246,7 @@ std::vector<FileInfo> ListFiles(const std::filesystem::path& path) {
|
|||
result.push_back(info);
|
||||
}
|
||||
closedir(dir);
|
||||
return result;
|
||||
return std::move(result);
|
||||
}
|
||||
|
||||
bool SetAttributes(const std::filesystem::path& path, uint64_t attributes) {
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -244,12 +244,12 @@ class Logger {
|
|||
}
|
||||
|
||||
private:
|
||||
static const size_t kBufferSize = 8_MiB;
|
||||
static constexpr size_t kBufferSize = 8_MiB;
|
||||
uint8_t buffer_[kBufferSize];
|
||||
|
||||
static const size_t kBlockSize = 256;
|
||||
static const size_t kBlockCount = kBufferSize / kBlockSize;
|
||||
static const size_t kBlockIndexMask = kBlockCount - 1;
|
||||
static constexpr size_t kBlockSize = 256;
|
||||
static constexpr size_t kBlockCount = kBufferSize / kBlockSize;
|
||||
static constexpr size_t kBlockIndexMask = kBlockCount - 1;
|
||||
|
||||
static const size_t kClaimStrategyFootprint =
|
||||
sizeof(std::atomic<dp::sequence_t>[kBlockCount]);
|
||||
|
@ -353,14 +353,14 @@ class Logger {
|
|||
? line_range.second[line_range.second_length - 1]
|
||||
: line_range.first[line_range.first_length - 1];
|
||||
if (last_char != '\n') {
|
||||
const char suffix[1] = {'\n'};
|
||||
constexpr char suffix[1] = {'\n'};
|
||||
Write(suffix, 1);
|
||||
}
|
||||
|
||||
rb.EndRead(std::move(line_range));
|
||||
} else {
|
||||
// Always ensure there is a newline.
|
||||
const char suffix[1] = {'\n'};
|
||||
constexpr char suffix[1] = {'\n'};
|
||||
Write(suffix, 1);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
|
@ -60,7 +60,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 +74,7 @@ static void RequestWin32MMCSS() {
|
|||
dwm_enable_mmcss = reinterpret_cast<decltype(dwm_enable_mmcss)>(
|
||||
GetProcAddress(dwmapi_module, "DwmEnableMMCSS"));
|
||||
if (dwm_enable_mmcss) {
|
||||
dwm_enable_mmcss(TRUE);
|
||||
dwm_enable_mmcss(true);
|
||||
}
|
||||
FreeLibrary(dwmapi_module);
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ class Win32MappedMemory : public MappedMemory {
|
|||
public:
|
||||
// CreateFile returns INVALID_HANDLE_VALUE in case of failure.
|
||||
// chrispy: made inline const to get around clang error
|
||||
static inline const HANDLE kFileHandleInvalid = INVALID_HANDLE_VALUE;
|
||||
static inline constexpr HANDLE kFileHandleInvalid = INVALID_HANDLE_VALUE;
|
||||
// CreateFileMapping returns nullptr in case of failure.
|
||||
static constexpr HANDLE kMappingHandleInvalid = nullptr;
|
||||
|
||||
|
|
|
@ -473,7 +473,7 @@ void copy_and_swap_16_unaligned(void* dst_ptr, const void* src_ptr,
|
|||
auto dst = reinterpret_cast<uint8_t*>(dst_ptr);
|
||||
auto src = reinterpret_cast<const uint8_t*>(src_ptr);
|
||||
|
||||
const uint8x16_t tbl_idx =
|
||||
constexpr uint8x16_t tbl_idx =
|
||||
vcombine_u8(vcreate_u8(UINT64_C(0x0607040502030001)),
|
||||
vcreate_u8(UINT64_C(0x0E0F0C0D0A0B0809)));
|
||||
|
||||
|
@ -507,7 +507,7 @@ void copy_and_swap_32_unaligned(void* dst_ptr, const void* src_ptr,
|
|||
auto dst = reinterpret_cast<uint8_t*>(dst_ptr);
|
||||
auto src = reinterpret_cast<const uint8_t*>(src_ptr);
|
||||
|
||||
const uint8x16_t tbl_idx =
|
||||
constexpr uint8x16_t tbl_idx =
|
||||
vcombine_u8(vcreate_u8(UINT64_C(0x405060700010203)),
|
||||
vcreate_u8(UINT64_C(0x0C0D0E0F08090A0B)));
|
||||
|
||||
|
@ -539,7 +539,7 @@ void copy_and_swap_64_unaligned(void* dst_ptr, const void* src_ptr,
|
|||
auto dst = reinterpret_cast<uint8_t*>(dst_ptr);
|
||||
auto src = reinterpret_cast<const uint8_t*>(src_ptr);
|
||||
|
||||
const uint8x16_t tbl_idx =
|
||||
constexpr uint8x16_t tbl_idx =
|
||||
vcombine_u8(vcreate_u8(UINT64_C(0x0001020304050607)),
|
||||
vcreate_u8(UINT64_C(0x08090A0B0C0D0E0F)));
|
||||
|
||||
|
|
|
@ -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) {
|
||||
return munmap(base_address, length) == 0;
|
||||
const auto region_begin = reinterpret_cast<uintptr_t>(base_address);
|
||||
const uintptr_t region_end =
|
||||
reinterpret_cast<uintptr_t>(base_address) + length;
|
||||
|
||||
std::lock_guard guard(g_mapped_file_ranges_mutex);
|
||||
for (const auto& mapped_range : mapped_file_ranges) {
|
||||
if (region_begin >= mapped_range.region_begin &&
|
||||
region_end <= mapped_range.region_end) {
|
||||
switch (deallocation_type) {
|
||||
case DeallocationType::kDecommit:
|
||||
return Protect(base_address, length, PageAccess::kNoAccess);
|
||||
case DeallocationType::kRelease:
|
||||
assert_always("Error: Tried to release mapped memory!");
|
||||
default:
|
||||
assert_unhandled_case(deallocation_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (deallocation_type) {
|
||||
case DeallocationType::kDecommit:
|
||||
return Protect(base_address, length, PageAccess::kNoAccess);
|
||||
case DeallocationType::kRelease:
|
||||
return munmap(base_address, length) == 0;
|
||||
default:
|
||||
assert_unhandled_case(deallocation_type);
|
||||
}
|
||||
}
|
||||
|
||||
bool Protect(void* base_address, size_t length, PageAccess access,
|
||||
PageAccess* out_old_access) {
|
||||
// Linux does not have a syscall to query memory permissions.
|
||||
assert_null(out_old_access);
|
||||
if (out_old_access) {
|
||||
size_t length_copy = length;
|
||||
QueryProtect(base_address, length_copy, *out_old_access);
|
||||
}
|
||||
|
||||
uint32_t prot = ToPosixProtectFlags(access);
|
||||
return mprotect(base_address, length, prot) == 0;
|
||||
}
|
||||
|
||||
bool QueryProtect(void* base_address, size_t& length, PageAccess& access_out) {
|
||||
// No generic POSIX solution exists. The Linux solution should work on all
|
||||
// Linux kernel based OS, including Android.
|
||||
std::ifstream memory_maps;
|
||||
memory_maps.open("/proc/self/maps", std::ios_base::in);
|
||||
std::string maps_entry_string;
|
||||
|
||||
while (std::getline(memory_maps, maps_entry_string)) {
|
||||
std::stringstream entry_stream(maps_entry_string);
|
||||
uintptr_t map_region_begin, map_region_end;
|
||||
char separator, protection[4];
|
||||
|
||||
entry_stream >> std::hex >> map_region_begin >> separator >>
|
||||
map_region_end >> protection;
|
||||
|
||||
if (map_region_begin <= reinterpret_cast<uintptr_t>(base_address) &&
|
||||
map_region_end > reinterpret_cast<uintptr_t>(base_address)) {
|
||||
length = map_region_end - reinterpret_cast<uintptr_t>(base_address);
|
||||
|
||||
access_out = ToXeniaProtectFlags(protection);
|
||||
|
||||
// Look at the next consecutive mappings
|
||||
while (std::getline(memory_maps, maps_entry_string)) {
|
||||
std::stringstream next_entry_stream(maps_entry_string);
|
||||
uintptr_t next_map_region_begin, next_map_region_end;
|
||||
char next_protection[4];
|
||||
|
||||
next_entry_stream >> std::hex >> next_map_region_begin >> separator >>
|
||||
next_map_region_end >> next_protection;
|
||||
if (map_region_end == next_map_region_begin &&
|
||||
access_out == ToXeniaProtectFlags(next_protection)) {
|
||||
length =
|
||||
next_map_region_end - reinterpret_cast<uintptr_t>(base_address);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
memory_maps.close();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
memory_maps.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -182,12 +287,41 @@ void CloseFileMappingHandle(FileMappingHandle handle,
|
|||
void* MapFileView(FileMappingHandle handle, void* base_address, size_t length,
|
||||
PageAccess access, size_t file_offset) {
|
||||
uint32_t prot = ToPosixProtectFlags(access);
|
||||
return mmap64(base_address, length, prot, MAP_PRIVATE | MAP_ANONYMOUS, handle,
|
||||
file_offset);
|
||||
|
||||
int flags = MAP_SHARED;
|
||||
if (base_address != nullptr) {
|
||||
flags |= MAP_FIXED_NOREPLACE;
|
||||
}
|
||||
|
||||
void* result = mmap(base_address, length, prot, flags, handle, file_offset);
|
||||
|
||||
if (result != MAP_FAILED) {
|
||||
std::lock_guard guard(g_mapped_file_ranges_mutex);
|
||||
mapped_file_ranges.push_back(
|
||||
{reinterpret_cast<uintptr_t>(result),
|
||||
reinterpret_cast<uintptr_t>(result) + length});
|
||||
return result;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool UnmapFileView(FileMappingHandle handle, void* base_address,
|
||||
size_t length) {
|
||||
std::lock_guard guard(g_mapped_file_ranges_mutex);
|
||||
for (auto mapped_range = mapped_file_ranges.begin();
|
||||
mapped_range != mapped_file_ranges.end();) {
|
||||
if (mapped_range->region_begin ==
|
||||
reinterpret_cast<uintptr_t>(base_address) &&
|
||||
mapped_range->region_end ==
|
||||
reinterpret_cast<uintptr_t>(base_address) + length) {
|
||||
mapped_file_ranges.erase(mapped_range);
|
||||
return munmap(base_address, length) == 0;
|
||||
}
|
||||
++mapped_range;
|
||||
}
|
||||
// TODO: Implement partial file unmapping.
|
||||
assert_always("Error: Partial unmapping of files not yet supported.");
|
||||
return munmap(base_address, length) == 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -17,4 +17,6 @@ project("xenia-base")
|
|||
"debug_visualizers.natvis",
|
||||
})
|
||||
|
||||
include("testing")
|
||||
if enableTests then
|
||||
include("testing")
|
||||
end
|
|
@ -96,7 +96,7 @@ class Win32Socket : public Socket {
|
|||
|
||||
// Keepalive for a looong time, as we may be paused by the debugger/etc.
|
||||
struct tcp_keepalive alive;
|
||||
alive.onoff = TRUE;
|
||||
alive.onoff = true;
|
||||
alive.keepalivetime = 7200000;
|
||||
alive.keepaliveinterval = 6000;
|
||||
DWORD bytes_returned;
|
||||
|
@ -209,7 +209,7 @@ class Win32SocketServer : public SocketServer {
|
|||
SOCKET socket = socket_;
|
||||
socket_ = INVALID_SOCKET;
|
||||
linger so_linger;
|
||||
so_linger.l_onoff = TRUE;
|
||||
so_linger.l_onoff = true;
|
||||
so_linger.l_linger = 30;
|
||||
setsockopt(socket, SOL_SOCKET, SO_LINGER,
|
||||
reinterpret_cast<const char*>(&so_linger), sizeof(so_linger));
|
||||
|
@ -231,7 +231,7 @@ class Win32SocketServer : public SocketServer {
|
|||
return false;
|
||||
}
|
||||
struct tcp_keepalive alive;
|
||||
alive.onoff = TRUE;
|
||||
alive.onoff = true;
|
||||
alive.keepalivetime = 7200000;
|
||||
alive.keepaliveinterval = 6000;
|
||||
DWORD bytes_returned;
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include <strings.h>
|
||||
#endif // !XE_PLATFORM_WIN32
|
||||
|
||||
#define UTF_CPP_CPLUSPLUS 201703L
|
||||
#define UTF_CPP_CPLUSPLUS 202002L
|
||||
#include "third_party/utfcpp/source/utf8.h"
|
||||
|
||||
namespace utfcpp = utf8;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -82,8 +82,7 @@ void AndroidShutdown() {
|
|||
#endif
|
||||
|
||||
template <typename _Rep, typename _Period>
|
||||
inline timespec DurationToTimeSpec(
|
||||
std::chrono::duration<_Rep, _Period> duration) {
|
||||
timespec DurationToTimeSpec(std::chrono::duration<_Rep, _Period> duration) {
|
||||
auto nanoseconds =
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(duration);
|
||||
auto div = ldiv(nanoseconds.count(), 1000000000L);
|
||||
|
@ -161,6 +160,8 @@ void Sleep(std::chrono::microseconds duration) {
|
|||
} while (ret == -1 && errno == EINTR);
|
||||
}
|
||||
|
||||
void NanoSleep(int64_t duration) { Sleep(std::chrono::nanoseconds(duration)); }
|
||||
|
||||
// TODO(bwrsandman) Implement by allowing alert interrupts from IO operations
|
||||
thread_local bool alertable_state_ = false;
|
||||
SleepResult AlertableSleep(std::chrono::microseconds duration) {
|
||||
|
@ -178,28 +179,25 @@ TlsHandle AllocateTlsHandle() {
|
|||
return static_cast<TlsHandle>(key);
|
||||
}
|
||||
|
||||
bool FreeTlsHandle(TlsHandle handle) {
|
||||
return pthread_key_delete(static_cast<pthread_key_t>(handle)) == 0;
|
||||
}
|
||||
bool FreeTlsHandle(TlsHandle handle) { return pthread_key_delete(handle) == 0; }
|
||||
|
||||
uintptr_t GetTlsValue(TlsHandle handle) {
|
||||
return reinterpret_cast<uintptr_t>(
|
||||
pthread_getspecific(static_cast<pthread_key_t>(handle)));
|
||||
return reinterpret_cast<uintptr_t>(pthread_getspecific(handle));
|
||||
}
|
||||
|
||||
bool SetTlsValue(TlsHandle handle, uintptr_t value) {
|
||||
return pthread_setspecific(static_cast<pthread_key_t>(handle),
|
||||
reinterpret_cast<void*>(value)) == 0;
|
||||
return pthread_setspecific(handle, reinterpret_cast<void*>(value)) == 0;
|
||||
}
|
||||
|
||||
class PosixConditionBase {
|
||||
public:
|
||||
virtual ~PosixConditionBase() = default;
|
||||
virtual bool Signal() = 0;
|
||||
|
||||
WaitResult Wait(std::chrono::milliseconds timeout) {
|
||||
bool executed;
|
||||
auto predicate = [this] { return this->signaled(); };
|
||||
auto lock = std::unique_lock<std::mutex>(mutex_);
|
||||
auto lock = std::unique_lock(mutex_);
|
||||
if (predicate()) {
|
||||
executed = true;
|
||||
} else {
|
||||
|
@ -213,15 +211,14 @@ class PosixConditionBase {
|
|||
if (executed) {
|
||||
post_execution();
|
||||
return WaitResult::kSuccess;
|
||||
} else {
|
||||
return WaitResult::kTimeout;
|
||||
}
|
||||
return WaitResult::kTimeout;
|
||||
}
|
||||
|
||||
static std::pair<WaitResult, size_t> WaitMultiple(
|
||||
std::vector<PosixConditionBase*>&& handles, bool wait_all,
|
||||
std::chrono::milliseconds timeout) {
|
||||
assert_true(handles.size() > 0);
|
||||
assert_true(!handles.empty());
|
||||
|
||||
// Construct a condition for all or any depending on wait_all
|
||||
std::function<bool()> predicate;
|
||||
|
@ -239,17 +236,16 @@ class PosixConditionBase {
|
|||
// TODO(bwrsandman, Triang3l) This is controversial, see issue #1677
|
||||
// This will probably cause a deadlock on the next thread doing any waiting
|
||||
// if the thread is suspended between locking and waiting
|
||||
std::unique_lock<std::mutex> lock(PosixConditionBase::mutex_);
|
||||
std::unique_lock lock(mutex_);
|
||||
|
||||
bool wait_success = true;
|
||||
// If the timeout is infinite, wait without timeout.
|
||||
// The predicate will be checked before beginning the wait
|
||||
if (timeout == std::chrono::milliseconds::max()) {
|
||||
PosixConditionBase::cond_.wait(lock, predicate);
|
||||
cond_.wait(lock, predicate);
|
||||
} else {
|
||||
// Wait with timeout.
|
||||
wait_success =
|
||||
PosixConditionBase::cond_.wait_for(lock, timeout, predicate);
|
||||
wait_success = cond_.wait_for(lock, timeout, predicate);
|
||||
}
|
||||
if (wait_success) {
|
||||
auto first_signaled = std::numeric_limits<size_t>::max();
|
||||
|
@ -264,15 +260,16 @@ class PosixConditionBase {
|
|||
}
|
||||
assert_true(std::numeric_limits<size_t>::max() != first_signaled);
|
||||
return std::make_pair(WaitResult::kSuccess, first_signaled);
|
||||
} else {
|
||||
return std::make_pair<WaitResult, size_t>(WaitResult::kTimeout, 0);
|
||||
}
|
||||
return std::make_pair<WaitResult, size_t>(WaitResult::kTimeout, 0);
|
||||
}
|
||||
|
||||
virtual void* native_handle() const { return cond_.native_handle(); }
|
||||
[[nodiscard]] virtual void* native_handle() const {
|
||||
return cond_.native_handle();
|
||||
}
|
||||
|
||||
protected:
|
||||
inline virtual bool signaled() const = 0;
|
||||
[[nodiscard]] inline virtual bool signaled() const = 0;
|
||||
inline virtual void post_execution() = 0;
|
||||
static std::condition_variable cond_;
|
||||
static std::mutex mutex_;
|
||||
|
@ -293,23 +290,23 @@ class PosixCondition<Event> : public PosixConditionBase {
|
|||
public:
|
||||
PosixCondition(bool manual_reset, bool initial_state)
|
||||
: signal_(initial_state), manual_reset_(manual_reset) {}
|
||||
virtual ~PosixCondition() = default;
|
||||
~PosixCondition() override = default;
|
||||
|
||||
bool Signal() override {
|
||||
auto lock = std::unique_lock<std::mutex>(mutex_);
|
||||
auto lock = std::unique_lock(mutex_);
|
||||
signal_ = true;
|
||||
cond_.notify_all();
|
||||
return true;
|
||||
}
|
||||
|
||||
void Reset() {
|
||||
auto lock = std::unique_lock<std::mutex>(mutex_);
|
||||
auto lock = std::unique_lock(mutex_);
|
||||
signal_ = false;
|
||||
}
|
||||
|
||||
private:
|
||||
inline bool signaled() const override { return signal_; }
|
||||
inline void post_execution() override {
|
||||
[[nodiscard]] bool signaled() const override { return signal_; }
|
||||
void post_execution() override {
|
||||
if (!manual_reset_) {
|
||||
signal_ = false;
|
||||
}
|
||||
|
@ -319,7 +316,7 @@ class PosixCondition<Event> : public PosixConditionBase {
|
|||
};
|
||||
|
||||
template <>
|
||||
class PosixCondition<Semaphore> : public PosixConditionBase {
|
||||
class PosixCondition<Semaphore> final : public PosixConditionBase {
|
||||
public:
|
||||
PosixCondition(uint32_t initial_count, uint32_t maximum_count)
|
||||
: count_(initial_count), maximum_count_(maximum_count) {}
|
||||
|
@ -328,7 +325,7 @@ class PosixCondition<Semaphore> : public PosixConditionBase {
|
|||
|
||||
bool Release(uint32_t release_count, int* out_previous_count) {
|
||||
if (maximum_count_ - count_ >= release_count) {
|
||||
auto lock = std::unique_lock<std::mutex>(mutex_);
|
||||
auto lock = std::unique_lock(mutex_);
|
||||
if (out_previous_count) *out_previous_count = count_;
|
||||
count_ += release_count;
|
||||
cond_.notify_all();
|
||||
|
@ -338,8 +335,8 @@ class PosixCondition<Semaphore> : public PosixConditionBase {
|
|||
}
|
||||
|
||||
private:
|
||||
inline bool signaled() const override { return count_ > 0; }
|
||||
inline void post_execution() override {
|
||||
[[nodiscard]] bool signaled() const override { return count_ > 0; }
|
||||
void post_execution() override {
|
||||
count_--;
|
||||
cond_.notify_all();
|
||||
}
|
||||
|
@ -348,7 +345,7 @@ class PosixCondition<Semaphore> : public PosixConditionBase {
|
|||
};
|
||||
|
||||
template <>
|
||||
class PosixCondition<Mutant> : public PosixConditionBase {
|
||||
class PosixCondition<Mutant> final : public PosixConditionBase {
|
||||
public:
|
||||
explicit PosixCondition(bool initial_owner) : count_(0) {
|
||||
if (initial_owner) {
|
||||
|
@ -361,7 +358,7 @@ class PosixCondition<Mutant> : public PosixConditionBase {
|
|||
|
||||
bool Release() {
|
||||
if (owner_ == std::this_thread::get_id() && count_ > 0) {
|
||||
auto lock = std::unique_lock<std::mutex>(mutex_);
|
||||
auto lock = std::unique_lock(mutex_);
|
||||
--count_;
|
||||
// Free to be acquired by another thread
|
||||
if (count_ == 0) {
|
||||
|
@ -372,13 +369,15 @@ class PosixCondition<Mutant> : public PosixConditionBase {
|
|||
return false;
|
||||
}
|
||||
|
||||
void* native_handle() const override { return mutex_.native_handle(); }
|
||||
[[nodiscard]] void* native_handle() const override {
|
||||
return mutex_.native_handle();
|
||||
}
|
||||
|
||||
private:
|
||||
inline bool signaled() const override {
|
||||
[[nodiscard]] bool signaled() const override {
|
||||
return count_ == 0 || owner_ == std::this_thread::get_id();
|
||||
}
|
||||
inline void post_execution() override {
|
||||
void post_execution() override {
|
||||
count_++;
|
||||
owner_ = std::this_thread::get_id();
|
||||
}
|
||||
|
@ -387,15 +386,15 @@ class PosixCondition<Mutant> : public PosixConditionBase {
|
|||
};
|
||||
|
||||
template <>
|
||||
class PosixCondition<Timer> : public PosixConditionBase {
|
||||
class PosixCondition<Timer> final : public PosixConditionBase {
|
||||
public:
|
||||
explicit PosixCondition(bool manual_reset)
|
||||
: callback_(nullptr), signal_(false), manual_reset_(manual_reset) {}
|
||||
|
||||
virtual ~PosixCondition() { Cancel(); }
|
||||
~PosixCondition() override { Cancel(); }
|
||||
|
||||
bool Signal() override {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
std::lock_guard lock(mutex_);
|
||||
signal_ = true;
|
||||
cond_.notify_all();
|
||||
return true;
|
||||
|
@ -405,7 +404,7 @@ class PosixCondition<Timer> : public PosixConditionBase {
|
|||
std::function<void()> opt_callback) {
|
||||
Cancel();
|
||||
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
std::lock_guard lock(mutex_);
|
||||
|
||||
callback_ = std::move(opt_callback);
|
||||
signal_ = false;
|
||||
|
@ -417,7 +416,7 @@ class PosixCondition<Timer> : public PosixConditionBase {
|
|||
std::function<void()> opt_callback) {
|
||||
Cancel();
|
||||
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
std::lock_guard lock(mutex_);
|
||||
|
||||
callback_ = std::move(opt_callback);
|
||||
signal_ = false;
|
||||
|
@ -425,13 +424,13 @@ class PosixCondition<Timer> : public PosixConditionBase {
|
|||
QueueTimerRecurring(&CompletionRoutine, this, due_time, period);
|
||||
}
|
||||
|
||||
void Cancel() {
|
||||
void Cancel() const {
|
||||
if (auto wait_item = wait_item_.lock()) {
|
||||
wait_item->Disarm();
|
||||
}
|
||||
}
|
||||
|
||||
void* native_handle() const override {
|
||||
[[nodiscard]] void* native_handle() const override {
|
||||
assert_always();
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -439,12 +438,12 @@ class PosixCondition<Timer> : public PosixConditionBase {
|
|||
private:
|
||||
static void CompletionRoutine(void* userdata) {
|
||||
assert_not_null(userdata);
|
||||
auto timer = reinterpret_cast<PosixCondition<Timer>*>(userdata);
|
||||
auto timer = static_cast<PosixCondition*>(userdata);
|
||||
timer->Signal();
|
||||
// As the callback may reset the timer, store local.
|
||||
std::function<void()> callback;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(timer->mutex_);
|
||||
std::lock_guard lock(timer->mutex_);
|
||||
callback = timer->callback_;
|
||||
}
|
||||
if (callback) {
|
||||
|
@ -452,9 +451,8 @@ class PosixCondition<Timer> : public PosixConditionBase {
|
|||
}
|
||||
}
|
||||
|
||||
private:
|
||||
inline bool signaled() const override { return signal_; }
|
||||
inline void post_execution() override {
|
||||
[[nodiscard]] bool signaled() const override { return signal_; }
|
||||
void post_execution() override {
|
||||
if (!manual_reset_) {
|
||||
signal_ = false;
|
||||
}
|
||||
|
@ -472,7 +470,7 @@ struct ThreadStartData {
|
|||
};
|
||||
|
||||
template <>
|
||||
class PosixCondition<Thread> : public PosixConditionBase {
|
||||
class PosixCondition<Thread> final : public PosixConditionBase {
|
||||
enum class State {
|
||||
kUninitialized,
|
||||
kRunning,
|
||||
|
@ -526,13 +524,18 @@ class PosixCondition<Thread> : public PosixConditionBase {
|
|||
: thread_(thread),
|
||||
signaled_(false),
|
||||
exit_code_(0),
|
||||
state_(State::kRunning) {
|
||||
state_(State::kRunning),
|
||||
suspend_count_(0) {
|
||||
#if XE_PLATFORM_ANDROID
|
||||
android_pre_api_26_name_[0] = '\0';
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual ~PosixCondition() {
|
||||
~PosixCondition() override {
|
||||
// FIXME(RodoMa92): This causes random crashes.
|
||||
// The proper way to handle them according to the webs is properly shutdown
|
||||
// instead on relying on killing them using pthread_cancel.
|
||||
/*
|
||||
if (thread_ && !signaled_) {
|
||||
#if XE_PLATFORM_ANDROID
|
||||
if (pthread_kill(thread_,
|
||||
|
@ -548,6 +551,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
|
|||
assert_always();
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
bool Signal() override { return true; }
|
||||
|
@ -555,7 +559,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
|
|||
std::string name() const {
|
||||
WaitStarted();
|
||||
auto result = std::array<char, 17>{'\0'};
|
||||
std::unique_lock<std::mutex> lock(state_mutex_);
|
||||
std::unique_lock lock(state_mutex_);
|
||||
if (state_ != State::kUninitialized && state_ != State::kFinished) {
|
||||
#if XE_PLATFORM_ANDROID
|
||||
// pthread_getname_np was added in API 26 - below that, store the name in
|
||||
|
@ -579,7 +583,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
|
|||
return std::string(result.data());
|
||||
}
|
||||
|
||||
void set_name(const std::string& name) {
|
||||
void set_name(const std::string& name) const {
|
||||
WaitStarted();
|
||||
std::unique_lock<std::mutex> lock(state_mutex_);
|
||||
if (state_ != State::kUninitialized && state_ != State::kFinished) {
|
||||
|
@ -603,7 +607,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
|
|||
|
||||
uint32_t system_id() const { return static_cast<uint32_t>(thread_); }
|
||||
|
||||
uint64_t affinity_mask() {
|
||||
uint64_t affinity_mask() const {
|
||||
WaitStarted();
|
||||
cpu_set_t cpu_set;
|
||||
#if XE_PLATFORM_ANDROID
|
||||
|
@ -625,7 +629,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
|
|||
return result;
|
||||
}
|
||||
|
||||
void set_affinity_mask(uint64_t mask) {
|
||||
void set_affinity_mask(uint64_t mask) const {
|
||||
WaitStarted();
|
||||
cpu_set_t cpu_set;
|
||||
CPU_ZERO(&cpu_set);
|
||||
|
@ -646,7 +650,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
|
|||
#endif
|
||||
}
|
||||
|
||||
int priority() {
|
||||
int priority() const {
|
||||
WaitStarted();
|
||||
int policy;
|
||||
sched_param param{};
|
||||
|
@ -658,7 +662,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
|
|||
return param.sched_priority;
|
||||
}
|
||||
|
||||
void set_priority(int new_priority) {
|
||||
void set_priority(int new_priority) const {
|
||||
WaitStarted();
|
||||
sched_param param{};
|
||||
param.sched_priority = new_priority;
|
||||
|
@ -678,7 +682,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
|
|||
|
||||
void QueueUserCallback(std::function<void()> callback) {
|
||||
WaitStarted();
|
||||
std::unique_lock<std::mutex> lock(callback_mutex_);
|
||||
std::unique_lock lock(callback_mutex_);
|
||||
user_callback_ = std::move(callback);
|
||||
sigval value{};
|
||||
value.sival_ptr = this;
|
||||
|
@ -691,8 +695,8 @@ class PosixCondition<Thread> : public PosixConditionBase {
|
|||
#endif
|
||||
}
|
||||
|
||||
void CallUserCallback() {
|
||||
std::unique_lock<std::mutex> lock(callback_mutex_);
|
||||
void CallUserCallback() const {
|
||||
std::unique_lock lock(callback_mutex_);
|
||||
user_callback_();
|
||||
}
|
||||
|
||||
|
@ -701,7 +705,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
|
|||
*out_previous_suspend_count = 0;
|
||||
}
|
||||
WaitStarted();
|
||||
std::unique_lock<std::mutex> lock(state_mutex_);
|
||||
std::unique_lock lock(state_mutex_);
|
||||
if (state_ != State::kSuspended) return false;
|
||||
if (out_previous_suspend_count) {
|
||||
*out_previous_suspend_count = suspend_count_;
|
||||
|
@ -731,7 +735,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
|
|||
void Terminate(int exit_code) {
|
||||
bool is_current_thread = pthread_self() == thread_;
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(state_mutex_);
|
||||
std::unique_lock lock(state_mutex_);
|
||||
if (state_ == State::kFinished) {
|
||||
if (is_current_thread) {
|
||||
// This is really bad. Some thread must have called Terminate() on us
|
||||
|
@ -747,7 +751,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
|
|||
}
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
std::lock_guard lock(mutex_);
|
||||
|
||||
exit_code_ = exit_code;
|
||||
signaled_ = true;
|
||||
|
@ -755,29 +759,28 @@ class PosixCondition<Thread> : public PosixConditionBase {
|
|||
}
|
||||
if (is_current_thread) {
|
||||
pthread_exit(reinterpret_cast<void*>(exit_code));
|
||||
} else {
|
||||
#ifdef XE_PLATFORM_ANDROID
|
||||
if (pthread_kill(thread_,
|
||||
GetSystemSignal(SignalType::kThreadTerminate)) != 0) {
|
||||
assert_always();
|
||||
}
|
||||
#else
|
||||
if (pthread_cancel(thread_) != 0) {
|
||||
assert_always();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#ifdef XE_PLATFORM_ANDROID
|
||||
if (pthread_kill(thread_, GetSystemSignal(SignalType::kThreadTerminate)) !=
|
||||
0) {
|
||||
assert_always();
|
||||
}
|
||||
#else
|
||||
if (pthread_cancel(thread_) != 0) {
|
||||
assert_always();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void WaitStarted() const {
|
||||
std::unique_lock<std::mutex> lock(state_mutex_);
|
||||
std::unique_lock lock(state_mutex_);
|
||||
state_signal_.wait(lock,
|
||||
[this] { return state_ != State::kUninitialized; });
|
||||
}
|
||||
|
||||
/// Set state to suspended and wait until it reset by another thread
|
||||
void WaitSuspended() {
|
||||
std::unique_lock<std::mutex> lock(state_mutex_);
|
||||
std::unique_lock lock(state_mutex_);
|
||||
state_signal_.wait(lock, [this] { return suspend_count_ == 0; });
|
||||
state_ = State::kRunning;
|
||||
}
|
||||
|
@ -788,8 +791,8 @@ class PosixCondition<Thread> : public PosixConditionBase {
|
|||
|
||||
private:
|
||||
static void* ThreadStartRoutine(void* parameter);
|
||||
inline bool signaled() const override { return signaled_; }
|
||||
inline void post_execution() override {
|
||||
bool signaled() const override { return signaled_; }
|
||||
void post_execution() override {
|
||||
if (thread_) {
|
||||
pthread_join(thread_, nullptr);
|
||||
}
|
||||
|
@ -813,6 +816,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
|
|||
|
||||
class PosixWaitHandle {
|
||||
public:
|
||||
virtual ~PosixWaitHandle() = default;
|
||||
virtual PosixConditionBase& condition() = 0;
|
||||
};
|
||||
|
||||
|
@ -829,7 +833,9 @@ class PosixConditionHandle : public T, public PosixWaitHandle {
|
|||
~PosixConditionHandle() override = default;
|
||||
|
||||
PosixCondition<T>& condition() override { return handle_; }
|
||||
void* native_handle() const override { return handle_.native_handle(); }
|
||||
[[nodiscard]] void* native_handle() const override {
|
||||
return handle_.native_handle();
|
||||
}
|
||||
|
||||
protected:
|
||||
PosixCondition<T> handle_;
|
||||
|
@ -910,7 +916,7 @@ std::pair<WaitResult, size_t> WaitMultiple(WaitHandle* wait_handles[],
|
|||
return result;
|
||||
}
|
||||
|
||||
class PosixEvent : public PosixConditionHandle<Event> {
|
||||
class PosixEvent final : public PosixConditionHandle<Event> {
|
||||
public:
|
||||
PosixEvent(bool manual_reset, bool initial_state)
|
||||
: PosixConditionHandle(manual_reset, initial_state) {}
|
||||
|
@ -939,7 +945,7 @@ std::unique_ptr<Event> Event::CreateAutoResetEvent(bool initial_state) {
|
|||
return std::make_unique<PosixEvent>(false, initial_state);
|
||||
}
|
||||
|
||||
class PosixSemaphore : public PosixConditionHandle<Semaphore> {
|
||||
class PosixSemaphore final : public PosixConditionHandle<Semaphore> {
|
||||
public:
|
||||
PosixSemaphore(int initial_count, int maximum_count)
|
||||
: PosixConditionHandle(static_cast<uint32_t>(initial_count),
|
||||
|
@ -963,7 +969,7 @@ std::unique_ptr<Semaphore> Semaphore::Create(int initial_count,
|
|||
return std::make_unique<PosixSemaphore>(initial_count, maximum_count);
|
||||
}
|
||||
|
||||
class PosixMutant : public PosixConditionHandle<Mutant> {
|
||||
class PosixMutant final : public PosixConditionHandle<Mutant> {
|
||||
public:
|
||||
explicit PosixMutant(bool initial_owner)
|
||||
: PosixConditionHandle(initial_owner) {}
|
||||
|
@ -975,9 +981,9 @@ std::unique_ptr<Mutant> Mutant::Create(bool initial_owner) {
|
|||
return std::make_unique<PosixMutant>(initial_owner);
|
||||
}
|
||||
|
||||
class PosixTimer : public PosixConditionHandle<Timer> {
|
||||
using WClock_ = Timer::WClock_;
|
||||
using GClock_ = Timer::GClock_;
|
||||
class PosixTimer final : public PosixConditionHandle<Timer> {
|
||||
using WClock_ = WClock_;
|
||||
using GClock_ = GClock_;
|
||||
|
||||
public:
|
||||
explicit PosixTimer(bool manual_reset) : PosixConditionHandle(manual_reset) {}
|
||||
|
@ -1030,7 +1036,7 @@ std::unique_ptr<Timer> Timer::CreateSynchronizationTimer() {
|
|||
return std::make_unique<PosixTimer>(false);
|
||||
}
|
||||
|
||||
class PosixThread : public PosixConditionHandle<Thread> {
|
||||
class PosixThread final : public PosixConditionHandle<Thread> {
|
||||
public:
|
||||
PosixThread() = default;
|
||||
explicit PosixThread(pthread_t thread) : PosixConditionHandle(thread) {}
|
||||
|
@ -1102,14 +1108,14 @@ void* PosixCondition<Thread>::ThreadStartRoutine(void* parameter) {
|
|||
|
||||
current_thread_ = thread;
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(thread->handle_.state_mutex_);
|
||||
std::unique_lock lock(thread->handle_.state_mutex_);
|
||||
thread->handle_.state_ =
|
||||
create_suspended ? State::kSuspended : State::kRunning;
|
||||
thread->handle_.state_signal_.notify_all();
|
||||
}
|
||||
|
||||
if (create_suspended) {
|
||||
std::unique_lock<std::mutex> lock(thread->handle_.state_mutex_);
|
||||
std::unique_lock lock(thread->handle_.state_mutex_);
|
||||
thread->handle_.suspend_count_ = 1;
|
||||
thread->handle_.state_signal_.wait(
|
||||
lock, [thread] { return thread->handle_.suspend_count_ == 0; });
|
||||
|
@ -1118,11 +1124,11 @@ void* PosixCondition<Thread>::ThreadStartRoutine(void* parameter) {
|
|||
start_routine();
|
||||
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(thread->handle_.state_mutex_);
|
||||
std::unique_lock lock(thread->handle_.state_mutex_);
|
||||
thread->handle_.state_ = State::kFinished;
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
std::unique_lock lock(mutex_);
|
||||
thread->handle_.exit_code_ = 0;
|
||||
thread->handle_.signaled_ = true;
|
||||
cond_.notify_all();
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include <numeric>
|
||||
#include <tuple>
|
||||
|
||||
#define UTF_CPP_CPLUSPLUS 201703L
|
||||
#define UTF_CPP_CPLUSPLUS 202002L
|
||||
#include "third_party/utfcpp/source/utf8.h"
|
||||
|
||||
namespace utfcpp = utf8;
|
||||
|
@ -82,10 +82,10 @@ std::string upper_ascii(const std::string_view view) {
|
|||
|
||||
template <bool LOWER>
|
||||
inline size_t hash_fnv1a(const std::string_view view) {
|
||||
const size_t offset_basis = 0xCBF29CE484222325ull;
|
||||
constexpr size_t offset_basis = 0xCBF29CE484222325ull;
|
||||
// chrispy: constant capture errors on clang
|
||||
auto work = [](size_t hash, uint8_t byte_of_data) {
|
||||
const size_t prime = 0x00000100000001B3ull;
|
||||
constexpr size_t prime = 0x00000100000001B3ull;
|
||||
hash ^= byte_of_data;
|
||||
hash *= prime;
|
||||
return hash;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -636,7 +636,7 @@ HostToGuestThunk X64HelperEmitter::EmitHostToGuestThunk() {
|
|||
|
||||
_code_offsets code_offsets = {};
|
||||
|
||||
const size_t stack_size = StackLayout::THUNK_STACK_SIZE;
|
||||
constexpr size_t stack_size = StackLayout::THUNK_STACK_SIZE;
|
||||
|
||||
code_offsets.prolog = getSize();
|
||||
|
||||
|
@ -681,13 +681,10 @@ HostToGuestThunk X64HelperEmitter::EmitHostToGuestThunk() {
|
|||
size_t tail;
|
||||
} code_offsets = {};
|
||||
|
||||
const size_t stack_size = StackLayout::THUNK_STACK_SIZE;
|
||||
constexpr size_t stack_size = StackLayout::THUNK_STACK_SIZE;
|
||||
|
||||
code_offsets.prolog = getSize();
|
||||
// rsp + 0 = return address
|
||||
mov(qword[rsp + 8 * 3], rdx);
|
||||
mov(qword[rsp + 8 * 2], rsi);
|
||||
mov(qword[rsp + 8 * 1], rdi);
|
||||
sub(rsp, stack_size);
|
||||
|
||||
code_offsets.prolog_stack_alloc = getSize();
|
||||
|
@ -707,9 +704,6 @@ HostToGuestThunk X64HelperEmitter::EmitHostToGuestThunk() {
|
|||
code_offsets.epilog = getSize();
|
||||
|
||||
add(rsp, stack_size);
|
||||
mov(rdi, qword[rsp + 8 * 1]);
|
||||
mov(rsi, qword[rsp + 8 * 2]);
|
||||
mov(rdx, qword[rsp + 8 * 3]);
|
||||
ret();
|
||||
#else
|
||||
assert_always("Unknown platform ABI in host to guest thunk!");
|
||||
|
@ -741,7 +735,7 @@ GuestToHostThunk X64HelperEmitter::EmitGuestToHostThunk() {
|
|||
|
||||
_code_offsets code_offsets = {};
|
||||
|
||||
const size_t stack_size = StackLayout::THUNK_STACK_SIZE;
|
||||
constexpr size_t stack_size = StackLayout::THUNK_STACK_SIZE;
|
||||
|
||||
code_offsets.prolog = getSize();
|
||||
|
||||
|
@ -787,7 +781,7 @@ GuestToHostThunk X64HelperEmitter::EmitGuestToHostThunk() {
|
|||
size_t tail;
|
||||
} code_offsets = {};
|
||||
|
||||
const size_t stack_size = StackLayout::THUNK_STACK_SIZE;
|
||||
constexpr size_t stack_size = StackLayout::THUNK_STACK_SIZE;
|
||||
|
||||
code_offsets.prolog = getSize();
|
||||
|
||||
|
@ -844,7 +838,7 @@ ResolveFunctionThunk X64HelperEmitter::EmitResolveFunctionThunk() {
|
|||
|
||||
_code_offsets code_offsets = {};
|
||||
|
||||
const size_t stack_size = StackLayout::THUNK_STACK_SIZE;
|
||||
constexpr size_t stack_size = StackLayout::THUNK_STACK_SIZE;
|
||||
|
||||
code_offsets.prolog = getSize();
|
||||
|
||||
|
@ -884,7 +878,7 @@ ResolveFunctionThunk X64HelperEmitter::EmitResolveFunctionThunk() {
|
|||
size_t epilog;
|
||||
size_t tail;
|
||||
} code_offsets = {};
|
||||
const size_t stack_size = StackLayout::THUNK_STACK_SIZE;
|
||||
constexpr size_t stack_size = StackLayout::THUNK_STACK_SIZE;
|
||||
|
||||
code_offsets.prolog = getSize();
|
||||
|
||||
|
@ -1743,7 +1737,7 @@ void X64Backend::PrepareForReentry(void* ctx) {
|
|||
bctx->current_stackpoint_depth = 0;
|
||||
}
|
||||
|
||||
const uint32_t mxcsr_table[8] = {
|
||||
constexpr uint32_t mxcsr_table[8] = {
|
||||
0x1F80, 0x7F80, 0x5F80, 0x3F80, 0x9F80, 0xFF80, 0xDF80, 0xBF80,
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.",
|
||||
|
|
|
@ -2100,7 +2100,7 @@ Value* HIRBuilder::CountLeadingZeros(Value* value) {
|
|||
ASSERT_INTEGER_TYPE(value);
|
||||
|
||||
if (value->IsConstantZero()) {
|
||||
static const uint8_t zeros[] = {
|
||||
static constexpr uint8_t zeros[] = {
|
||||
8,
|
||||
16,
|
||||
32,
|
||||
|
|
|
@ -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, \
|
||||
|
|
|
@ -20,8 +20,8 @@ namespace cpu {
|
|||
namespace ppc {
|
||||
|
||||
constexpr size_t kNamePad = 11;
|
||||
const uint8_t kSpaces[kNamePad] = {0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20};
|
||||
constexpr uint8_t kSpaces[kNamePad] = {0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20};
|
||||
void PadStringBuffer(StringBuffer* str, size_t base, size_t pad);
|
||||
|
||||
void PrintDisasm_bcx(const PPCDecodeData& d, StringBuffer* str);
|
||||
|
|
|
@ -44,7 +44,7 @@ using namespace xe::literals;
|
|||
|
||||
typedef std::vector<std::pair<std::string, std::string>> AnnotationList;
|
||||
|
||||
const uint32_t START_ADDRESS = 0x80000000;
|
||||
constexpr uint32_t START_ADDRESS = 0x80000000;
|
||||
|
||||
struct TestCase {
|
||||
TestCase(uint32_t address, std::string& name)
|
||||
|
|
|
@ -43,7 +43,7 @@ struct Context {
|
|||
|
||||
typedef std::vector<std::pair<std::string, std::string>> AnnotationList;
|
||||
|
||||
const uint32_t START_ADDRESS = 0x00000000;
|
||||
constexpr uint32_t START_ADDRESS = 0x00000000;
|
||||
|
||||
struct TestCase {
|
||||
TestCase(uint32_t address, std::string& name)
|
||||
|
|
|
@ -17,6 +17,7 @@ project("xenia-cpu-ppc-tests")
|
|||
"xenia-base",
|
||||
"xenia-kernel",
|
||||
"xenia-patcher",
|
||||
"xenia-hid-skylander",
|
||||
})
|
||||
files({
|
||||
"ppc_testing_main.cc",
|
||||
|
|
|
@ -21,9 +21,7 @@ project("xenia-cpu")
|
|||
local_platform_files("hir")
|
||||
local_platform_files("ppc")
|
||||
|
||||
include("testing")
|
||||
include("ppc/testing")
|
||||
-- filter({"configurations:Release", "platforms:Windows"})
|
||||
-- buildoptions({
|
||||
-- "/O1",
|
||||
-- })
|
||||
if enableTests then
|
||||
include("testing")
|
||||
include("ppc/testing")
|
||||
end
|
||||
|
|
|
@ -104,7 +104,7 @@ bool InitializeStackWalker() {
|
|||
options |= SYMOPT_LOAD_LINES;
|
||||
options |= SYMOPT_FAIL_CRITICAL_ERRORS;
|
||||
sym_set_options_(options);
|
||||
if (!sym_initialize_(GetCurrentProcess(), nullptr, TRUE)) {
|
||||
if (!sym_initialize_(GetCurrentProcess(), nullptr, true)) {
|
||||
XELOGE("Unable to initialize symbol services - already in use?");
|
||||
return false;
|
||||
}
|
||||
|
@ -192,7 +192,7 @@ class Win32StackWalker : public StackWalker {
|
|||
}
|
||||
|
||||
// Setup the frame for walking.
|
||||
STACKFRAME64 stack_frame = {0};
|
||||
STACKFRAME64 stack_frame = {};
|
||||
stack_frame.AddrPC.Mode = AddrModeFlat;
|
||||
stack_frame.AddrPC.Offset = thread_context.Rip;
|
||||
stack_frame.AddrFrame.Mode = AddrModeFlat;
|
||||
|
|
|
@ -10,6 +10,7 @@ test_suite("xenia-cpu-tests", project_root, ".", {
|
|||
"xenia-core",
|
||||
"xenia-cpu",
|
||||
"xenia-gpu",
|
||||
"xenia-hid-skylander",
|
||||
|
||||
-- TODO(benvanik): cut these dependencies?
|
||||
"xenia-kernel",
|
||||
|
|
|
@ -50,10 +50,10 @@ DEFINE_bool(
|
|||
|
||||
DECLARE_bool(allow_plugins);
|
||||
|
||||
static const uint8_t xe_xex2_retail_key[16] = {
|
||||
static constexpr uint8_t xe_xex2_retail_key[16] = {
|
||||
0x20, 0xB1, 0x85, 0xA5, 0x9D, 0x28, 0xFD, 0xC3,
|
||||
0x40, 0x58, 0x3F, 0xBB, 0x08, 0x96, 0xBF, 0x91};
|
||||
static const uint8_t xe_xex2_devkit_key[16] = {
|
||||
static constexpr uint8_t xe_xex2_devkit_key[16] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
|
@ -1505,13 +1505,13 @@ std::vector<uint32_t> XexModule::PreanalyzeCode() {
|
|||
uint32_t* range_end = (uint32_t*)memory()->TranslateVirtual(
|
||||
high_8_aligned); // align down to multiple of 8
|
||||
|
||||
const uint8_t mfspr_r12_lr[4] = {0x7D, 0x88, 0x02, 0xA6};
|
||||
constexpr uint8_t mfspr_r12_lr[4] = {0x7D, 0x88, 0x02, 0xA6};
|
||||
|
||||
// a blr instruction, with 4 zero bytes afterwards to pad the next address
|
||||
// to 8 byte alignment
|
||||
// if we see this prior to our address, we can assume we are a function
|
||||
// start
|
||||
const uint8_t blr[4] = {0x4E, 0x80, 0x0, 0x20};
|
||||
constexpr uint8_t blr[4] = {0x4E, 0x80, 0x0, 0x20};
|
||||
|
||||
uint32_t blr32 = *reinterpret_cast<const uint32_t*>(&blr[0]);
|
||||
|
||||
|
@ -1631,7 +1631,7 @@ bool XexModule::FindSaveRest() {
|
|||
// special codegen.
|
||||
// __savegprlr_14 to __savegprlr_31
|
||||
// __restgprlr_14 to __restgprlr_31
|
||||
static const uint32_t gprlr_code_values[] = {
|
||||
static constexpr uint32_t gprlr_code_values[] = {
|
||||
0x68FFC1F9, // __savegprlr_14
|
||||
0x70FFE1F9, // __savegprlr_15
|
||||
0x78FF01FA, // __savegprlr_16
|
||||
|
@ -1673,7 +1673,7 @@ bool XexModule::FindSaveRest() {
|
|||
};
|
||||
// __savefpr_14 to __savefpr_31
|
||||
// __restfpr_14 to __restfpr_31
|
||||
static const uint32_t fpr_code_values[] = {
|
||||
static constexpr uint32_t fpr_code_values[] = {
|
||||
0x70FFCCD9, // __savefpr_14
|
||||
0x78FFECD9, // __savefpr_15
|
||||
0x80FF0CDA, // __savefpr_16
|
||||
|
@ -1717,7 +1717,7 @@ bool XexModule::FindSaveRest() {
|
|||
// __savevmx_64 to __savevmx_127
|
||||
// __restvmx_14 to __restvmx_31
|
||||
// __restvmx_64 to __restvmx_127
|
||||
static const uint32_t vmx_code_values[] = {
|
||||
static constexpr uint32_t vmx_code_values[] = {
|
||||
0xE0FE6039, // __savevmx_14
|
||||
0xCE61CB7D, 0xF0FE6039, 0xCE61EB7D, 0x00FF6039, 0xCE610B7E, 0x10FF6039,
|
||||
0xCE612B7E, 0x20FF6039, 0xCE614B7E, 0x30FF6039, 0xCE616B7E, 0x40FF6039,
|
||||
|
|
|
@ -55,7 +55,7 @@ void DebugWindow::DebugDialog::OnDraw(ImGuiIO& io) {
|
|||
debug_window_.DrawFrame(io);
|
||||
}
|
||||
|
||||
static const std::string kBaseTitle = "Xenia Debugger";
|
||||
static constexpr std::string_view kBaseTitle = "Xenia Debugger";
|
||||
|
||||
DebugWindow::DebugWindow(Emulator* emulator,
|
||||
xe::ui::WindowedAppContext& app_context)
|
||||
|
@ -1460,7 +1460,7 @@ void DebugWindow::UpdateCache() {
|
|||
auto object_table = kernel_state->object_table();
|
||||
|
||||
app_context_.CallInUIThread([this]() {
|
||||
std::string title = kBaseTitle;
|
||||
std::string title = std::string(kBaseTitle);
|
||||
switch (processor_->execution_state()) {
|
||||
case cpu::ExecutionState::kEnded:
|
||||
title += " (ended)";
|
||||
|
|
|
@ -137,8 +137,8 @@ class DebugWindow : public cpu::DebugListener {
|
|||
// The current state of the UI. Use this to synchronize multiple parts of the
|
||||
// UI.
|
||||
struct ImState {
|
||||
static const int kRightPaneThreads = 0;
|
||||
static const int kRightPaneMemory = 1;
|
||||
static constexpr int kRightPaneThreads = 0;
|
||||
static constexpr int kRightPaneMemory = 1;
|
||||
int right_pane_tab = kRightPaneThreads;
|
||||
|
||||
cpu::ThreadDebugInfo* thread_info = nullptr;
|
||||
|
|
|
@ -41,9 +41,9 @@
|
|||
#include "xenia/hid/input_system.h"
|
||||
#include "xenia/kernel/kernel_state.h"
|
||||
#include "xenia/kernel/user_module.h"
|
||||
#include "xenia/kernel/util/xdbf_utils.h"
|
||||
#include "xenia/kernel/xam/achievement_manager.h"
|
||||
#include "xenia/kernel/xam/xam_module.h"
|
||||
#include "xenia/kernel/xam/xdbf/spa_info.h"
|
||||
#include "xenia/kernel/xbdm/xbdm_module.h"
|
||||
#include "xenia/kernel/xboxkrnl/xboxkrnl_module.h"
|
||||
#include "xenia/memory.h"
|
||||
|
@ -215,12 +215,15 @@ X_STATUS Emulator::Setup(
|
|||
// logical processors.
|
||||
xe::threading::EnableAffinityConfiguration();
|
||||
|
||||
XELOGI("{}: Initializing Memory...", __func__);
|
||||
// Create memory system first, as it is required for other systems.
|
||||
memory_ = std::make_unique<Memory>();
|
||||
if (!memory_->Initialize()) {
|
||||
return false;
|
||||
XELOGE("{}: Cannot initalize memory!", __func__);
|
||||
return result;
|
||||
}
|
||||
|
||||
XELOGI("{}: Initializing Exports...", __func__);
|
||||
// Shared export resolver used to attach and query for HLE exports.
|
||||
export_resolver_ = std::make_unique<xe::cpu::ExportResolver>();
|
||||
|
||||
|
@ -241,30 +244,38 @@ X_STATUS Emulator::Setup(
|
|||
backend.reset(new xe::cpu::backend::NullBackend());
|
||||
}
|
||||
|
||||
XELOGI("{}: Initializing Processor...", __func__);
|
||||
// Initialize the CPU.
|
||||
processor_ = std::make_unique<xe::cpu::Processor>(memory_.get(),
|
||||
export_resolver_.get());
|
||||
if (!processor_->Setup(std::move(backend))) {
|
||||
XELOGE("{}: Cannot initalize processor!", __func__);
|
||||
return X_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
XELOGI("{}: Initializing Audio...", __func__);
|
||||
// Initialize the APU.
|
||||
if (audio_system_factory) {
|
||||
audio_system_ = audio_system_factory(processor_.get());
|
||||
if (!audio_system_) {
|
||||
XELOGE("{}: Cannot initalize audio_system!", __func__);
|
||||
return X_STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
}
|
||||
|
||||
XELOGI("{}: Initializing Graphics...", __func__);
|
||||
// Initialize the GPU.
|
||||
graphics_system_ = graphics_system_factory();
|
||||
if (!graphics_system_) {
|
||||
XELOGE("{}: Cannot initalize graphics_system!", __func__);
|
||||
return X_STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
XELOGI("{}: Initializing HID...", __func__);
|
||||
// Initialize the HID.
|
||||
input_system_ = std::make_unique<xe::hid::InputSystem>(display_window_);
|
||||
if (!input_system_) {
|
||||
XELOGE("{}: Cannot initalize input_system!", __func__);
|
||||
return X_STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
if (input_driver_factory) {
|
||||
|
@ -282,11 +293,13 @@ X_STATUS Emulator::Setup(
|
|||
return result;
|
||||
}
|
||||
|
||||
XELOGI("{}: Initializing VFS...", __func__);
|
||||
// Bring up the virtual filesystem used by the kernel.
|
||||
file_system_ = std::make_unique<xe::vfs::VirtualFileSystem>();
|
||||
|
||||
patcher_ = std::make_unique<xe::patcher::Patcher>(storage_root_);
|
||||
|
||||
XELOGI("{}: Initializing Kernel...", __func__);
|
||||
// Shared kernel state.
|
||||
kernel_state_ = std::make_unique<xe::kernel::KernelState>(this);
|
||||
#define LOAD_KERNEL_MODULE(t) \
|
||||
|
@ -299,18 +312,22 @@ X_STATUS Emulator::Setup(
|
|||
plugin_loader_ = std::make_unique<xe::patcher::PluginLoader>(
|
||||
kernel_state_.get(), storage_root() / "plugins");
|
||||
|
||||
XELOGI("{}: Starting graphics_system...", __func__);
|
||||
// Setup the core components.
|
||||
result = graphics_system_->Setup(
|
||||
processor_.get(), kernel_state_.get(),
|
||||
display_window_ ? &display_window_->app_context() : nullptr,
|
||||
display_window_ != nullptr);
|
||||
if (result) {
|
||||
XELOGE("{}: Failed to setup graphics_system!", __func__);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (audio_system_) {
|
||||
XELOGI("{}: Starting audio_system...", __func__);
|
||||
result = audio_system_->Setup(kernel_state_.get());
|
||||
if (result) {
|
||||
XELOGE("{}: Failed to setup audio_system!", __func__);
|
||||
return result;
|
||||
}
|
||||
audio_media_player_ = std::make_unique<apu::AudioMediaPlayer>(
|
||||
|
@ -444,7 +461,7 @@ Emulator::FileSignatureType Emulator::GetFileSignature(
|
|||
}
|
||||
|
||||
const uint64_t file_size = std::filesystem::file_size(path);
|
||||
const int64_t header_size = 4;
|
||||
constexpr int64_t header_size = 4;
|
||||
|
||||
if (file_size < header_size) {
|
||||
return FileSignatureType::Unknown;
|
||||
|
@ -768,53 +785,93 @@ X_STATUS Emulator::DataMigration(const uint64_t xuid) {
|
|||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
X_STATUS Emulator::InstallContentPackage(
|
||||
const std::filesystem::path& path,
|
||||
ContentInstallationInfo& installation_info) {
|
||||
std::unique_ptr<vfs::Device> device =
|
||||
vfs::XContentContainerDevice::CreateContentDevice("", path);
|
||||
X_STATUS Emulator::ProcessContentPackageHeader(
|
||||
const std::filesystem::path& path, ContentInstallEntry& installation_info) {
|
||||
installation_info.name_ = "Invalid Content Package!";
|
||||
installation_info.content_type_ = XContentType::kInvalid;
|
||||
installation_info.data_installation_path_ = xe::path_to_utf8(path.filename());
|
||||
|
||||
installation_info.content_name = "Invalid Content Package!";
|
||||
installation_info.content_type = static_cast<XContentType>(0);
|
||||
installation_info.installation_path = xe::path_to_utf8(path.filename());
|
||||
const auto header = vfs::XContentContainerDevice::ReadContainerHeader(path);
|
||||
|
||||
if (!device || !device->Initialize()) {
|
||||
if (!header || !header->content_header.is_magic_valid()) {
|
||||
installation_info.installation_state_ = InstallState::failed;
|
||||
installation_info.installation_result_ = X_STATUS_INVALID_PARAMETER;
|
||||
installation_info.installation_error_message_ = "Invalid Package Type!";
|
||||
XELOGE("Failed to initialize device");
|
||||
return X_STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
const vfs::XContentContainerDevice* dev =
|
||||
(vfs::XContentContainerDevice*)device.get();
|
||||
|
||||
// Always install savefiles to user signed to slot 0.
|
||||
const auto profile =
|
||||
kernel_state_->xam_state()->profile_manager()->GetProfile(
|
||||
static_cast<uint8_t>(0));
|
||||
|
||||
uint64_t xuid = dev->xuid();
|
||||
if (dev->content_type() == static_cast<uint32_t>(XContentType::kSavedGame) &&
|
||||
uint64_t xuid = header->content_metadata.profile_id;
|
||||
if (header->content_metadata.content_type == XContentType::kSavedGame &&
|
||||
profile) {
|
||||
xuid = profile->xuid();
|
||||
}
|
||||
|
||||
std::filesystem::path installation_path =
|
||||
content_root() / fmt::format("{:016X}", xuid) /
|
||||
fmt::format("{:08X}", dev->title_id()) /
|
||||
fmt::format("{:08X}", dev->content_type()) / path.filename();
|
||||
installation_info.data_installation_path_ = fmt::format(
|
||||
"{:016X}/{:08X}/{:08X}/{}", xuid,
|
||||
header->content_metadata.execution_info.title_id.get(),
|
||||
static_cast<uint32_t>(header->content_metadata.content_type.get()),
|
||||
path.filename());
|
||||
|
||||
std::filesystem::path header_path =
|
||||
content_root() / fmt::format("{:016X}", xuid) /
|
||||
fmt::format("{:08X}", dev->title_id()) / "Headers" /
|
||||
fmt::format("{:08X}", dev->content_type()) / path.filename();
|
||||
installation_info.header_installation_path_ = fmt::format(
|
||||
"{:016X}/{:08X}/Headers/{:08X}/{}", xuid,
|
||||
header->content_metadata.execution_info.title_id.get(),
|
||||
static_cast<uint32_t>(header->content_metadata.content_type.get()),
|
||||
path.filename());
|
||||
|
||||
installation_info.installation_path =
|
||||
fmt::format("{:016X}/{:08X}/{:08X}/{}", xuid, dev->title_id(),
|
||||
dev->content_type(), path.filename());
|
||||
installation_info.name_ =
|
||||
xe::to_utf8(header->content_metadata.display_name(XLanguage::kEnglish));
|
||||
installation_info.content_type_ =
|
||||
static_cast<XContentType>(header->content_metadata.content_type);
|
||||
installation_info.content_size_ = header->content_metadata.content_size;
|
||||
installation_info.installation_state_ = InstallState::pending;
|
||||
|
||||
installation_info.content_name =
|
||||
xe::to_utf8(dev->content_header().display_name());
|
||||
installation_info.content_type =
|
||||
static_cast<XContentType>(dev->content_type());
|
||||
installation_info.icon_ = imgui_drawer_->LoadImGuiIcon(
|
||||
std::span<const uint8_t>(header->content_metadata.title_thumbnail,
|
||||
header->content_metadata.title_thumbnail_size));
|
||||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
X_STATUS Emulator::InstallContentPackage(
|
||||
const std::filesystem::path& path, ContentInstallEntry& installation_info) {
|
||||
installation_info.installation_state_ = InstallState::preparing;
|
||||
|
||||
std::unique_ptr<vfs::XContentContainerDevice> device =
|
||||
vfs::XContentContainerDevice::CreateContentDevice("", path);
|
||||
|
||||
if (!device || !device->Initialize()) {
|
||||
XELOGE("Failed to initialize device");
|
||||
return X_STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
const std::filesystem::path installation_path =
|
||||
content_root() / installation_info.data_installation_path_;
|
||||
|
||||
const std::filesystem::path header_path =
|
||||
content_root() / installation_info.header_installation_path_;
|
||||
|
||||
if (!std::filesystem::exists(content_root())) {
|
||||
const std::error_code ec = xe::filesystem::CreateFolder(content_root());
|
||||
if (ec) {
|
||||
installation_info.installation_state_ = InstallState::failed;
|
||||
installation_info.installation_error_message_ = ec.message();
|
||||
installation_info.installation_result_ = X_STATUS_ACCESS_DENIED;
|
||||
return X_STATUS_ACCESS_DENIED;
|
||||
}
|
||||
}
|
||||
|
||||
const auto disk_space = std::filesystem::space(content_root());
|
||||
if (disk_space.available < installation_info.content_size_ * 1.1f) {
|
||||
installation_info.installation_state_ = InstallState::failed;
|
||||
installation_info.installation_error_message_ = "Insufficient disk space!";
|
||||
installation_info.installation_result_ = X_STATUS_DISK_FULL;
|
||||
return X_STATUS_DISK_FULL;
|
||||
}
|
||||
|
||||
if (std::filesystem::exists(installation_path)) {
|
||||
// TODO(Gliniak): Popup
|
||||
|
@ -823,21 +880,35 @@ X_STATUS Emulator::InstallContentPackage(
|
|||
std::error_code error_code;
|
||||
std::filesystem::create_directories(installation_path, error_code);
|
||||
if (error_code) {
|
||||
installation_info.content_name = "Cannot Create Content Directory!";
|
||||
installation_info.installation_state_ = InstallState::failed;
|
||||
installation_info.installation_error_message_ =
|
||||
"Cannot Create Content Directory!";
|
||||
installation_info.installation_result_ = error_code.value();
|
||||
return error_code.value();
|
||||
}
|
||||
}
|
||||
|
||||
installation_info.content_size_ = device->data_size();
|
||||
installation_info.installation_state_ = InstallState::installing;
|
||||
|
||||
vfs::VirtualFileSystem::ExtractContentHeader(device.get(), header_path);
|
||||
|
||||
X_STATUS error_code = vfs::VirtualFileSystem::ExtractContentFiles(
|
||||
device.get(), installation_path);
|
||||
device.get(), installation_path,
|
||||
installation_info.currently_installed_size_);
|
||||
if (error_code != X_ERROR_SUCCESS) {
|
||||
installation_info.installation_state_ = InstallState::failed;
|
||||
return error_code;
|
||||
}
|
||||
|
||||
installation_info.installation_state_ = InstallState::installed;
|
||||
installation_info.currently_installed_size_ = installation_info.content_size_;
|
||||
kernel_state()->BroadcastNotification(kXNotificationLiveContentInstalled, 0);
|
||||
|
||||
if (installation_info.content_type_ == XContentType::kProfile) {
|
||||
kernel_state_->xam_state()->profile_manager()->ReloadProfiles();
|
||||
}
|
||||
|
||||
return error_code;
|
||||
}
|
||||
|
||||
|
@ -862,7 +933,9 @@ X_STATUS Emulator::ExtractZarchivePackage(
|
|||
}
|
||||
}
|
||||
|
||||
return vfs::VirtualFileSystem::ExtractContentFiles(device.get(), extract_dir);
|
||||
uint64_t progress = 0;
|
||||
return vfs::VirtualFileSystem::ExtractContentFiles(device.get(), extract_dir,
|
||||
progress);
|
||||
}
|
||||
|
||||
X_STATUS Emulator::CreateZarchivePackage(
|
||||
|
@ -1316,19 +1389,9 @@ std::string Emulator::FindLaunchModule() {
|
|||
}
|
||||
|
||||
static std::string format_version(xex2_version version) {
|
||||
// fmt::format doesn't like bit fields
|
||||
uint32_t major, minor, build, qfe;
|
||||
major = version.major;
|
||||
minor = version.minor;
|
||||
build = version.build;
|
||||
qfe = version.qfe;
|
||||
if (qfe) {
|
||||
return fmt::format("{}.{}.{}.{}", major, minor, build, qfe);
|
||||
}
|
||||
if (build) {
|
||||
return fmt::format("{}.{}.{}", major, minor, build);
|
||||
}
|
||||
return fmt::format("{}.{}", major, minor);
|
||||
// fmt::format doesn't like bit fields we use + to bypass it
|
||||
return fmt::format("{}.{}.{}.{}", +version.major, +version.minor,
|
||||
+version.build, +version.qfe);
|
||||
}
|
||||
|
||||
X_STATUS Emulator::CompleteLaunch(const std::filesystem::path& path,
|
||||
|
@ -1427,9 +1490,13 @@ X_STATUS Emulator::CompleteLaunch(const std::filesystem::path& path,
|
|||
}
|
||||
game_config_load_callback_loop_next_index_ = SIZE_MAX;
|
||||
|
||||
const kernel::util::XdbfGameData db = kernel_state_->module_xdbf(module);
|
||||
const auto db = kernel_state_->module_xdbf(module);
|
||||
|
||||
game_info_database_ = std::make_unique<kernel::util::GameInfoDatabase>(&db);
|
||||
game_info_database_ =
|
||||
std::make_unique<kernel::util::GameInfoDatabase>(db.get());
|
||||
kernel_state_->xam_state()->LoadSpaInfo(db.get());
|
||||
|
||||
kernel_state_->xam_state()->user_tracker()->AddTitleToPlayedList();
|
||||
|
||||
if (game_info_database_->IsValid()) {
|
||||
title_name_ = game_info_database_->GetTitleName(
|
||||
|
@ -1490,17 +1557,6 @@ X_STATUS Emulator::CompleteLaunch(const std::filesystem::path& path,
|
|||
if (!icon_block.empty()) {
|
||||
display_window_->SetIcon(icon_block.data(), icon_block.size());
|
||||
}
|
||||
|
||||
for (uint8_t slot = 0; slot < XUserMaxUserCount; slot++) {
|
||||
auto user =
|
||||
kernel_state_->xam_state()->profile_manager()->GetProfile(slot);
|
||||
|
||||
if (user) {
|
||||
kernel_state_->xam_state()
|
||||
->achievement_manager()
|
||||
->LoadTitleAchievements(user->xuid(), db);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1526,7 +1582,8 @@ X_STATUS Emulator::CompleteLaunch(const std::filesystem::path& path,
|
|||
if (cvars::allow_plugins) {
|
||||
if (plugin_loader_->IsAnyPluginForTitleAvailable(title_id_.value(),
|
||||
module->hash().value())) {
|
||||
plugin_loader_->LoadTitlePlugins(title_id_.value());
|
||||
plugin_loader_->LoadTitlePlugins(title_id_.value(),
|
||||
module->hash().value());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "xenia/memory.h"
|
||||
#include "xenia/patcher/patcher.h"
|
||||
#include "xenia/patcher/plugin_loader.h"
|
||||
#include "xenia/ui/immediate_drawer.h"
|
||||
#include "xenia/vfs/device.h"
|
||||
#include "xenia/vfs/virtual_file_system.h"
|
||||
#include "xenia/xbox.h"
|
||||
|
@ -55,8 +56,8 @@ class Window;
|
|||
namespace xe {
|
||||
|
||||
constexpr fourcc_t kEmulatorSaveSignature = make_fourcc("XSAV");
|
||||
static const std::string kDefaultGameSymbolicLink = "GAME:";
|
||||
static const std::string kDefaultPartitionSymbolicLink = "D:";
|
||||
static constexpr std::string_view kDefaultGameSymbolicLink = "GAME:";
|
||||
static constexpr std::string_view kDefaultPartitionSymbolicLink = "D:";
|
||||
|
||||
// The main type that runs the whole emulator.
|
||||
// This is responsible for initializing and managing all the various subsystems.
|
||||
|
@ -171,6 +172,9 @@ class Emulator {
|
|||
|
||||
patcher::PluginLoader* plugin_loader() const { return plugin_loader_.get(); }
|
||||
|
||||
kernel::util::GameInfoDatabase* game_info_database() const {
|
||||
return game_info_database_.get();
|
||||
}
|
||||
// Initializes the emulator and configures all components.
|
||||
// The given window is used for display and the provided functions are used
|
||||
// to create subsystems as required.
|
||||
|
@ -231,18 +235,45 @@ class Emulator {
|
|||
|
||||
X_STATUS LaunchDefaultModule(const std::filesystem::path& path);
|
||||
|
||||
struct ContentInstallationInfo {
|
||||
XContentType content_type;
|
||||
std::string installation_path;
|
||||
std::string content_name;
|
||||
enum class InstallState : uint8_t {
|
||||
preparing,
|
||||
pending,
|
||||
installing,
|
||||
installed,
|
||||
failed
|
||||
};
|
||||
|
||||
constexpr static std::string_view installStateStringName[5] = {
|
||||
"Preparing", "Pending", "Installing", "Success", "Failed"};
|
||||
|
||||
struct ContentInstallEntry {
|
||||
ContentInstallEntry(std::filesystem::path path) : path_(path) {};
|
||||
|
||||
std::string name_{};
|
||||
std::filesystem::path path_;
|
||||
std::filesystem::path data_installation_path_;
|
||||
std::filesystem::path header_installation_path_;
|
||||
|
||||
uint64_t content_size_ = 0;
|
||||
uint64_t currently_installed_size_ = 0;
|
||||
XContentType content_type_{};
|
||||
|
||||
InstallState installation_state_{};
|
||||
X_STATUS installation_result_{};
|
||||
std::string installation_error_message_{};
|
||||
|
||||
std::unique_ptr<ui::ImmediateTexture> icon_;
|
||||
};
|
||||
|
||||
// Migrates data from content to content/xuid with respect to common data.
|
||||
X_STATUS DataMigration(const uint64_t xuid);
|
||||
|
||||
X_STATUS ProcessContentPackageHeader(const std::filesystem::path& path,
|
||||
ContentInstallEntry& installation_info);
|
||||
|
||||
// Extract content of package to content specific directory.
|
||||
X_STATUS InstallContentPackage(const std::filesystem::path& path,
|
||||
ContentInstallationInfo& installation_info);
|
||||
ContentInstallEntry& installation_info);
|
||||
|
||||
// Extract content of zar package to desired directory.
|
||||
X_STATUS ExtractZarchivePackage(const std::filesystem::path& path,
|
||||
|
|
|
@ -285,7 +285,7 @@ void CommandProcessor::WorkerThreadMain() {
|
|||
do {
|
||||
// If we spin around too much, revert to a "low-power" state.
|
||||
if (loop_count > 500) {
|
||||
const int wait_time_ms = 2;
|
||||
constexpr int wait_time_ms = 2;
|
||||
xe::threading::Wait(write_ptr_index_event_.get(), true,
|
||||
std::chrono::milliseconds(wait_time_ms));
|
||||
} else {
|
||||
|
|
|
@ -810,7 +810,7 @@ bool D3D12CommandProcessor::SetupContext() {
|
|||
ID3D12Device* device = provider.GetDevice();
|
||||
ID3D12CommandQueue* direct_queue = provider.GetDirectQueue();
|
||||
|
||||
fence_completion_event_ = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||
fence_completion_event_ = CreateEvent(nullptr, false, false, nullptr);
|
||||
if (fence_completion_event_ == nullptr) {
|
||||
XELOGE("Failed to create the fence completion event");
|
||||
return false;
|
||||
|
|
|
@ -109,7 +109,7 @@ namespace shaders {
|
|||
#include "xenia/gpu/shaders/bytecode/d3d12_5_1/resolve_full_8bpp_scaled_cs.h"
|
||||
} // namespace shaders
|
||||
|
||||
const D3D12RenderTargetCache::ResolveCopyShaderCode
|
||||
constexpr D3D12RenderTargetCache::ResolveCopyShaderCode
|
||||
D3D12RenderTargetCache::kResolveCopyShaders[size_t(
|
||||
draw_util::ResolveCopyShaderIndex::kCount)] = {
|
||||
{shaders::resolve_fast_32bpp_1x2xmsaa_cs,
|
||||
|
@ -146,7 +146,7 @@ const D3D12RenderTargetCache::ResolveCopyShaderCode
|
|||
sizeof(shaders::resolve_full_128bpp_scaled_cs)},
|
||||
};
|
||||
|
||||
const uint32_t D3D12RenderTargetCache::kTransferUsedRootParameters[size_t(
|
||||
constexpr uint32_t D3D12RenderTargetCache::kTransferUsedRootParameters[size_t(
|
||||
TransferRootSignatureIndex::kCount)] = {
|
||||
// kColor
|
||||
kTransferUsedRootParameterColorSRVBit |
|
||||
|
@ -184,7 +184,7 @@ const uint32_t D3D12RenderTargetCache::kTransferUsedRootParameters[size_t(
|
|||
kTransferUsedRootParameterHostDepthAddressConstantBit,
|
||||
};
|
||||
|
||||
const D3D12RenderTargetCache::TransferModeInfo
|
||||
constexpr D3D12RenderTargetCache::TransferModeInfo
|
||||
D3D12RenderTargetCache::kTransferModes[size_t(TransferMode::kCount)] = {
|
||||
// kColorToDepth
|
||||
{TransferOutput::kDepth, TransferRootSignatureIndex::kColor,
|
||||
|
@ -467,7 +467,7 @@ bool D3D12RenderTargetCache::Initialize() {
|
|||
// instead.
|
||||
if (cvars::native_2x_msaa) {
|
||||
msaa_2x_supported_ = true;
|
||||
static const DXGI_FORMAT kRenderTargetDXGIFormats[] = {
|
||||
static constexpr DXGI_FORMAT kRenderTargetDXGIFormats[] = {
|
||||
DXGI_FORMAT_R16G16B16A16_FLOAT,
|
||||
DXGI_FORMAT_R16G16B16A16_SNORM,
|
||||
DXGI_FORMAT_R32G32_FLOAT,
|
||||
|
@ -969,7 +969,7 @@ bool D3D12RenderTargetCache::Initialize() {
|
|||
D3D12_FILL_MODE_SOLID;
|
||||
uint32_rtv_clear_pipeline_desc.RasterizerState.CullMode =
|
||||
D3D12_CULL_MODE_NONE;
|
||||
uint32_rtv_clear_pipeline_desc.RasterizerState.DepthClipEnable = TRUE;
|
||||
uint32_rtv_clear_pipeline_desc.RasterizerState.DepthClipEnable = true;
|
||||
uint32_rtv_clear_pipeline_desc.PrimitiveTopologyType =
|
||||
D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
||||
uint32_rtv_clear_pipeline_desc.NumRenderTargets = 1;
|
||||
|
@ -4327,12 +4327,12 @@ D3D12RenderTargetCache::GetOrCreateTransferPipelines(TransferShaderKey key) {
|
|||
}
|
||||
pipeline_desc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID;
|
||||
pipeline_desc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE;
|
||||
pipeline_desc.RasterizerState.DepthClipEnable = TRUE;
|
||||
pipeline_desc.RasterizerState.DepthClipEnable = true;
|
||||
pipeline_desc.InputLayout.pInputElementDescs = &pipeline_input_element_desc;
|
||||
pipeline_desc.InputLayout.NumElements = 1;
|
||||
pipeline_desc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
||||
if (dest_is_stencil_bit) {
|
||||
pipeline_desc.DepthStencilState.StencilEnable = TRUE;
|
||||
pipeline_desc.DepthStencilState.StencilEnable = true;
|
||||
pipeline_desc.DepthStencilState.FrontFace.StencilFailOp =
|
||||
D3D12_STENCIL_OP_KEEP;
|
||||
pipeline_desc.DepthStencilState.FrontFace.StencilDepthFailOp =
|
||||
|
@ -4375,14 +4375,14 @@ D3D12RenderTargetCache::GetOrCreateTransferPipelines(TransferShaderKey key) {
|
|||
pipeline_desc.RTVFormats[0] =
|
||||
GetColorOwnershipTransferDXGIFormat(dest_color_format);
|
||||
} else {
|
||||
pipeline_desc.DepthStencilState.DepthEnable = TRUE;
|
||||
pipeline_desc.DepthStencilState.DepthEnable = true;
|
||||
pipeline_desc.DepthStencilState.DepthWriteMask =
|
||||
D3D12_DEPTH_WRITE_MASK_ALL;
|
||||
pipeline_desc.DepthStencilState.DepthFunc =
|
||||
cvars::depth_transfer_not_equal_test ? D3D12_COMPARISON_FUNC_NOT_EQUAL
|
||||
: D3D12_COMPARISON_FUNC_ALWAYS;
|
||||
if (use_stencil_reference_output_) {
|
||||
pipeline_desc.DepthStencilState.StencilEnable = TRUE;
|
||||
pipeline_desc.DepthStencilState.StencilEnable = true;
|
||||
pipeline_desc.DepthStencilState.StencilWriteMask = UINT8_MAX;
|
||||
pipeline_desc.DepthStencilState.FrontFace.StencilFailOp =
|
||||
D3D12_STENCIL_OP_KEEP;
|
||||
|
@ -4804,7 +4804,7 @@ void D3D12RenderTargetCache::PerformTransfersAndResolveClears(
|
|||
are_current_command_list_render_targets_valid_ = false;
|
||||
if (dest_rt_key.is_depth) {
|
||||
auto handle = dest_d3d12_rt.descriptor_draw().GetHandle();
|
||||
command_list.D3DOMSetRenderTargets(0, nullptr, FALSE, &handle);
|
||||
command_list.D3DOMSetRenderTargets(0, nullptr, false, &handle);
|
||||
if (!use_stencil_reference_output_) {
|
||||
command_processor_.SetStencilReference(UINT8_MAX);
|
||||
}
|
||||
|
@ -4812,7 +4812,7 @@ void D3D12RenderTargetCache::PerformTransfersAndResolveClears(
|
|||
auto handle = dest_d3d12_rt.descriptor_load_separate().IsValid()
|
||||
? dest_d3d12_rt.descriptor_load_separate().GetHandle()
|
||||
: dest_d3d12_rt.descriptor_draw().GetHandle();
|
||||
command_list.D3DOMSetRenderTargets(1, &handle, FALSE, nullptr);
|
||||
command_list.D3DOMSetRenderTargets(1, &handle, false, nullptr);
|
||||
}
|
||||
|
||||
uint32_t dest_pitch_tiles = dest_rt_key.GetPitchTiles();
|
||||
|
@ -5432,7 +5432,7 @@ void D3D12RenderTargetCache::PerformTransfersAndResolveClears(
|
|||
? dest_d3d12_rt.descriptor_load_separate().GetHandle()
|
||||
: dest_d3d12_rt.descriptor_draw().GetHandle());
|
||||
|
||||
command_list.D3DOMSetRenderTargets(1, &handle, FALSE, nullptr);
|
||||
command_list.D3DOMSetRenderTargets(1, &handle, false, nullptr);
|
||||
are_current_command_list_render_targets_valid_ = true;
|
||||
D3D12_VIEWPORT clear_viewport;
|
||||
clear_viewport.TopLeftX = float(clear_rect.left);
|
||||
|
@ -5553,7 +5553,7 @@ void D3D12RenderTargetCache::SetCommandListRenderTargets(
|
|||
: d3d12_rt.descriptor_draw().GetHandle();
|
||||
}
|
||||
command_processor_.GetDeferredCommandList().D3DOMSetRenderTargets(
|
||||
rtv_count, rtv_handles, FALSE,
|
||||
rtv_count, rtv_handles, false,
|
||||
depth_and_color_render_targets[0] ? &dsv_handle : nullptr);
|
||||
are_current_command_list_render_targets_valid_ = true;
|
||||
}
|
||||
|
|
|
@ -394,7 +394,7 @@ bool D3D12SharedMemory::AllocateSparseHostGpuMemoryRange(
|
|||
region_start_coordinates.Subresource = 0;
|
||||
D3D12_TILE_REGION_SIZE region_size;
|
||||
region_size.NumTiles = length_bytes / D3D12_TILED_RESOURCE_TILE_SIZE_IN_BYTES;
|
||||
region_size.UseBox = FALSE;
|
||||
region_size.UseBox = false;
|
||||
D3D12_TILE_RANGE_FLAGS range_flags = D3D12_TILE_RANGE_FLAG_NONE;
|
||||
UINT heap_range_start_offset = 0;
|
||||
direct_queue->UpdateTileMappings(
|
||||
|
|
|
@ -758,7 +758,7 @@ void D3D12TextureCache::WriteSampler(SamplerParameters parameters,
|
|||
D3D12_FILTER_REDUCTION_TYPE_STANDARD);
|
||||
desc.MaxAnisotropy = 1;
|
||||
}
|
||||
static const D3D12_TEXTURE_ADDRESS_MODE kAddressModeMap[] = {
|
||||
static constexpr D3D12_TEXTURE_ADDRESS_MODE kAddressModeMap[] = {
|
||||
/* kRepeat */ D3D12_TEXTURE_ADDRESS_MODE_WRAP,
|
||||
/* kMirroredRepeat */ D3D12_TEXTURE_ADDRESS_MODE_MIRROR,
|
||||
/* kClampToEdge */ D3D12_TEXTURE_ADDRESS_MODE_CLAMP,
|
||||
|
@ -968,7 +968,7 @@ bool D3D12TextureCache::EnsureScaledResolveMemoryCommitted(
|
|||
D3D12_TILE_REGION_SIZE region_size;
|
||||
region_size.NumTiles =
|
||||
kScaledResolveHeapSize / D3D12_TILED_RESOURCE_TILE_SIZE_IN_BYTES;
|
||||
region_size.UseBox = FALSE;
|
||||
region_size.UseBox = false;
|
||||
D3D12_TILE_RANGE_FLAGS range_flags = D3D12_TILE_RANGE_FLAG_NONE;
|
||||
UINT heap_range_start_offset = 0;
|
||||
UINT range_tile_count =
|
||||
|
|
|
@ -144,7 +144,7 @@ void DeferredCommandList::Execute(ID3D12GraphicsCommandList* command_list,
|
|||
*reinterpret_cast<const D3DOMSetRenderTargetsArguments*>(stream);
|
||||
command_list->OMSetRenderTargets(
|
||||
args.num_render_target_descriptors, args.render_target_descriptors,
|
||||
args.rts_single_handle_to_descriptor_range ? TRUE : FALSE,
|
||||
args.rts_single_handle_to_descriptor_range ? true : false,
|
||||
args.depth_stencil ? &args.depth_stencil_descriptor : nullptr);
|
||||
} break;
|
||||
case Command::kD3DOMSetStencilRef: {
|
||||
|
|
|
@ -269,7 +269,7 @@ class DeferredCommandList {
|
|||
return;
|
||||
}
|
||||
static_assert(alignof(D3D12_RESOURCE_BARRIER) <= alignof(uintmax_t));
|
||||
const size_t header_size =
|
||||
constexpr size_t header_size =
|
||||
xe::align(sizeof(UINT), alignof(D3D12_RESOURCE_BARRIER));
|
||||
uint8_t* args = reinterpret_cast<uint8_t*>(WriteCommand(
|
||||
Command::kD3DResourceBarrier,
|
||||
|
|
|
@ -272,7 +272,7 @@ void PipelineCache::InitializeShaderStorage(
|
|||
}
|
||||
pipeline_storage_file_flush_needed_ = false;
|
||||
// 'XEPS'.
|
||||
const uint32_t pipeline_storage_magic = 0x53504558;
|
||||
constexpr uint32_t pipeline_storage_magic = 0x53504558;
|
||||
// 'DXRO' or 'DXRT'.
|
||||
const uint32_t pipeline_storage_magic_api =
|
||||
edram_rov_used ? 0x4F525844 : 0x54525844;
|
||||
|
@ -367,7 +367,7 @@ void PipelineCache::InitializeShaderStorage(
|
|||
uint32_t version_swapped;
|
||||
} shader_storage_file_header;
|
||||
// 'XESH'.
|
||||
const uint32_t shader_storage_magic = 0x48534558;
|
||||
constexpr uint32_t shader_storage_magic = 0x48534558;
|
||||
if (fread(&shader_storage_file_header, sizeof(shader_storage_file_header), 1,
|
||||
shader_storage_file_) &&
|
||||
shader_storage_file_header.magic == shader_storage_magic &&
|
||||
|
@ -1577,7 +1577,7 @@ bool PipelineCache::GetCurrentStateDescription(
|
|||
|
||||
// Render targets and blending state. 32 because of 0x1F mask, for safety
|
||||
// (all unknown to zero).
|
||||
static const PipelineBlendFactor kBlendFactorMap[32] = {
|
||||
static constexpr PipelineBlendFactor kBlendFactorMap[32] = {
|
||||
/* 0 */ PipelineBlendFactor::kZero,
|
||||
/* 1 */ PipelineBlendFactor::kOne,
|
||||
/* 2 */ PipelineBlendFactor::kZero, // ?
|
||||
|
@ -1603,7 +1603,7 @@ bool PipelineCache::GetCurrentStateDescription(
|
|||
// Like kBlendFactorMap, but with color modes changed to alpha. Some
|
||||
// pipelines aren't created in 545407E0 because a color mode is used for
|
||||
// alpha.
|
||||
static const PipelineBlendFactor kBlendFactorAlphaMap[32] = {
|
||||
static constexpr PipelineBlendFactor kBlendFactorAlphaMap[32] = {
|
||||
/* 0 */ PipelineBlendFactor::kZero,
|
||||
/* 1 */ PipelineBlendFactor::kOne,
|
||||
/* 2 */ PipelineBlendFactor::kZero, // ?
|
||||
|
@ -3029,7 +3029,7 @@ ID3D12PipelineState* PipelineCache::CreateD3D12Pipeline(
|
|||
break;
|
||||
}
|
||||
state_desc.RasterizerState.FrontCounterClockwise =
|
||||
description.front_counter_clockwise ? TRUE : FALSE;
|
||||
description.front_counter_clockwise ? true : false;
|
||||
state_desc.RasterizerState.DepthBias = description.depth_bias;
|
||||
state_desc.RasterizerState.DepthBiasClamp = 0.0f;
|
||||
// With non-square resolution scaling, make sure the worst-case impact is
|
||||
|
@ -3041,7 +3041,7 @@ ID3D12PipelineState* PipelineCache::CreateD3D12Pipeline(
|
|||
float(std::max(render_target_cache_.draw_resolution_scale_x(),
|
||||
render_target_cache_.draw_resolution_scale_y()));
|
||||
state_desc.RasterizerState.DepthClipEnable =
|
||||
description.depth_clip ? TRUE : FALSE;
|
||||
description.depth_clip ? true : false;
|
||||
uint32_t msaa_sample_count = uint32_t(1)
|
||||
<< uint32_t(description.host_msaa_samples);
|
||||
if (edram_rov_used) {
|
||||
|
@ -3082,7 +3082,7 @@ ID3D12PipelineState* PipelineCache::CreateD3D12Pipeline(
|
|||
// Depth/stencil.
|
||||
if (description.depth_func != xenos::CompareFunction::kAlways ||
|
||||
description.depth_write) {
|
||||
state_desc.DepthStencilState.DepthEnable = TRUE;
|
||||
state_desc.DepthStencilState.DepthEnable = true;
|
||||
state_desc.DepthStencilState.DepthWriteMask =
|
||||
description.depth_write ? D3D12_DEPTH_WRITE_MASK_ALL
|
||||
: D3D12_DEPTH_WRITE_MASK_ZERO;
|
||||
|
@ -3093,7 +3093,7 @@ ID3D12PipelineState* PipelineCache::CreateD3D12Pipeline(
|
|||
uint32_t(description.depth_func));
|
||||
}
|
||||
if (description.stencil_enable) {
|
||||
state_desc.DepthStencilState.StencilEnable = TRUE;
|
||||
state_desc.DepthStencilState.StencilEnable = true;
|
||||
state_desc.DepthStencilState.StencilReadMask =
|
||||
description.stencil_read_mask;
|
||||
state_desc.DepthStencilState.StencilWriteMask =
|
||||
|
@ -3131,8 +3131,8 @@ ID3D12PipelineState* PipelineCache::CreateD3D12Pipeline(
|
|||
}
|
||||
|
||||
// Render targets and blending.
|
||||
state_desc.BlendState.IndependentBlendEnable = TRUE;
|
||||
static const D3D12_BLEND kBlendFactorMap[] = {
|
||||
state_desc.BlendState.IndependentBlendEnable = true;
|
||||
static constexpr D3D12_BLEND kBlendFactorMap[] = {
|
||||
D3D12_BLEND_ZERO, D3D12_BLEND_ONE,
|
||||
D3D12_BLEND_SRC_COLOR, D3D12_BLEND_INV_SRC_COLOR,
|
||||
D3D12_BLEND_SRC_ALPHA, D3D12_BLEND_INV_SRC_ALPHA,
|
||||
|
@ -3142,7 +3142,7 @@ ID3D12PipelineState* PipelineCache::CreateD3D12Pipeline(
|
|||
D3D12_BLEND_SRC_ALPHA_SAT,
|
||||
};
|
||||
// 8 entries for safety since 3 bits from the guest are passed directly.
|
||||
static const D3D12_BLEND_OP kBlendOpMap[] = {
|
||||
static constexpr D3D12_BLEND_OP kBlendOpMap[] = {
|
||||
D3D12_BLEND_OP_ADD, D3D12_BLEND_OP_SUBTRACT, D3D12_BLEND_OP_MIN,
|
||||
D3D12_BLEND_OP_MAX, D3D12_BLEND_OP_REV_SUBTRACT, D3D12_BLEND_OP_ADD,
|
||||
D3D12_BLEND_OP_ADD, D3D12_BLEND_OP_ADD};
|
||||
|
@ -3169,7 +3169,7 @@ ID3D12PipelineState* PipelineCache::CreateD3D12Pipeline(
|
|||
rt.src_blend_alpha != PipelineBlendFactor::kOne ||
|
||||
rt.dest_blend_alpha != PipelineBlendFactor::kZero ||
|
||||
rt.blend_op_alpha != xenos::BlendOp::kAdd) {
|
||||
blend_desc.BlendEnable = TRUE;
|
||||
blend_desc.BlendEnable = true;
|
||||
blend_desc.SrcBlend = kBlendFactorMap[uint32_t(rt.src_blend)];
|
||||
blend_desc.DestBlend = kBlendFactorMap[uint32_t(rt.dest_blend)];
|
||||
blend_desc.BlendOp = kBlendOpMap[uint32_t(rt.blend_op)];
|
||||
|
@ -3196,8 +3196,8 @@ ID3D12PipelineState* PipelineCache::CreateD3D12Pipeline(
|
|||
if (description.cull_mode == PipelineCullMode::kDisableRasterization) {
|
||||
state_desc.PS.pShaderBytecode = nullptr;
|
||||
state_desc.PS.BytecodeLength = 0;
|
||||
state_desc.DepthStencilState.DepthEnable = FALSE;
|
||||
state_desc.DepthStencilState.StencilEnable = FALSE;
|
||||
state_desc.DepthStencilState.DepthEnable = false;
|
||||
state_desc.DepthStencilState.StencilEnable = false;
|
||||
}
|
||||
|
||||
// Create the D3D12 pipeline state object.
|
||||
|
|
|
@ -19,106 +19,110 @@ project("xenia-gpu-d3d12")
|
|||
"../shaders/bytecode/d3d12_5_1/*.h",
|
||||
})
|
||||
|
||||
group("src")
|
||||
project("xenia-gpu-d3d12-trace-viewer")
|
||||
uuid("7b5b9fcb-7bf1-43ff-a774-d4c41c8706be")
|
||||
single_library_windowed_app_kind()
|
||||
language("C++")
|
||||
links({
|
||||
"xenia-apu",
|
||||
"xenia-apu-nop",
|
||||
"xenia-base",
|
||||
"xenia-core",
|
||||
"xenia-cpu",
|
||||
"xenia-gpu",
|
||||
"xenia-gpu-d3d12",
|
||||
"xenia-hid",
|
||||
"xenia-hid-nop",
|
||||
"xenia-kernel",
|
||||
"xenia-patcher",
|
||||
"xenia-ui",
|
||||
"xenia-ui-d3d12",
|
||||
"xenia-vfs",
|
||||
})
|
||||
links({
|
||||
"aes_128",
|
||||
"capstone",
|
||||
"dxbc",
|
||||
"fmt",
|
||||
"imgui",
|
||||
"libavcodec",
|
||||
"libavutil",
|
||||
"mspack",
|
||||
"snappy",
|
||||
"xxhash",
|
||||
})
|
||||
files({
|
||||
"d3d12_trace_viewer_main.cc",
|
||||
"../../ui/windowed_app_main_"..platform_suffix..".cc",
|
||||
})
|
||||
-- Only create the .user file if it doesn't already exist.
|
||||
local user_file = project_root.."/build/xenia-gpu-d3d12-trace-viewer.vcxproj.user"
|
||||
if not os.isfile(user_file) then
|
||||
debugdir(project_root)
|
||||
debugargs({
|
||||
"2>&1",
|
||||
"1>scratch/stdout-trace-viewer.txt",
|
||||
})
|
||||
end
|
||||
|
||||
filter("architecture:x86_64")
|
||||
if enableMiscSubprojects then
|
||||
group("src")
|
||||
project("xenia-gpu-d3d12-trace-viewer")
|
||||
uuid("7b5b9fcb-7bf1-43ff-a774-d4c41c8706be")
|
||||
single_library_windowed_app_kind()
|
||||
language("C++")
|
||||
links({
|
||||
"xenia-cpu-backend-x64",
|
||||
"xenia-apu",
|
||||
"xenia-apu-nop",
|
||||
"xenia-base",
|
||||
"xenia-core",
|
||||
"xenia-cpu",
|
||||
"xenia-gpu",
|
||||
"xenia-gpu-d3d12",
|
||||
"xenia-hid",
|
||||
"xenia-hid-nop",
|
||||
"xenia-hid-skylander",
|
||||
"xenia-kernel",
|
||||
"xenia-patcher",
|
||||
"xenia-ui",
|
||||
"xenia-ui-d3d12",
|
||||
"xenia-vfs",
|
||||
})
|
||||
|
||||
group("src")
|
||||
project("xenia-gpu-d3d12-trace-dump")
|
||||
uuid("686b859c-0046-44c4-a02c-41fc3fb75698")
|
||||
kind("ConsoleApp")
|
||||
language("C++")
|
||||
links({
|
||||
"xenia-apu",
|
||||
"xenia-apu-nop",
|
||||
"xenia-base",
|
||||
"xenia-core",
|
||||
"xenia-cpu",
|
||||
"xenia-gpu",
|
||||
"xenia-gpu-d3d12",
|
||||
"xenia-hid",
|
||||
"xenia-hid-nop",
|
||||
"xenia-kernel",
|
||||
"xenia-ui",
|
||||
"xenia-ui-d3d12",
|
||||
"xenia-vfs",
|
||||
"xenia-patcher",
|
||||
})
|
||||
links({
|
||||
"aes_128",
|
||||
"capstone",
|
||||
"dxbc",
|
||||
"fmt",
|
||||
"imgui",
|
||||
"libavcodec",
|
||||
"libavutil",
|
||||
"mspack",
|
||||
"snappy",
|
||||
"xxhash",
|
||||
})
|
||||
files({
|
||||
"d3d12_trace_dump_main.cc",
|
||||
"../../base/console_app_main_"..platform_suffix..".cc",
|
||||
})
|
||||
-- Only create the .user file if it doesn't already exist.
|
||||
local user_file = project_root.."/build/xenia-gpu-d3d12-trace-dump.vcxproj.user"
|
||||
if not os.isfile(user_file) then
|
||||
debugdir(project_root)
|
||||
debugargs({
|
||||
"2>&1",
|
||||
"1>scratch/stdout-trace-dump.txt",
|
||||
})
|
||||
end
|
||||
|
||||
filter("architecture:x86_64")
|
||||
links({
|
||||
"xenia-cpu-backend-x64",
|
||||
"aes_128",
|
||||
"capstone",
|
||||
"dxbc",
|
||||
"fmt",
|
||||
"imgui",
|
||||
"libavcodec",
|
||||
"libavutil",
|
||||
"mspack",
|
||||
"snappy",
|
||||
"xxhash",
|
||||
})
|
||||
files({
|
||||
"d3d12_trace_viewer_main.cc",
|
||||
"../../ui/windowed_app_main_"..platform_suffix..".cc",
|
||||
})
|
||||
-- Only create the .user file if it doesn't already exist.
|
||||
local user_file = project_root.."/build/xenia-gpu-d3d12-trace-viewer.vcxproj.user"
|
||||
if not os.isfile(user_file) then
|
||||
debugdir(project_root)
|
||||
debugargs({
|
||||
"2>&1",
|
||||
"1>scratch/stdout-trace-viewer.txt",
|
||||
})
|
||||
end
|
||||
|
||||
filter("architecture:x86_64")
|
||||
links({
|
||||
"xenia-cpu-backend-x64",
|
||||
})
|
||||
|
||||
group("src")
|
||||
project("xenia-gpu-d3d12-trace-dump")
|
||||
uuid("686b859c-0046-44c4-a02c-41fc3fb75698")
|
||||
kind("ConsoleApp")
|
||||
language("C++")
|
||||
links({
|
||||
"xenia-apu",
|
||||
"xenia-apu-nop",
|
||||
"xenia-base",
|
||||
"xenia-core",
|
||||
"xenia-cpu",
|
||||
"xenia-gpu",
|
||||
"xenia-gpu-d3d12",
|
||||
"xenia-hid",
|
||||
"xenia-hid-nop",
|
||||
"xenia-hid-skylander",
|
||||
"xenia-kernel",
|
||||
"xenia-ui",
|
||||
"xenia-ui-d3d12",
|
||||
"xenia-vfs",
|
||||
"xenia-patcher",
|
||||
})
|
||||
links({
|
||||
"aes_128",
|
||||
"capstone",
|
||||
"dxbc",
|
||||
"fmt",
|
||||
"imgui",
|
||||
"libavcodec",
|
||||
"libavutil",
|
||||
"mspack",
|
||||
"snappy",
|
||||
"xxhash",
|
||||
})
|
||||
files({
|
||||
"d3d12_trace_dump_main.cc",
|
||||
"../../base/console_app_main_"..platform_suffix..".cc",
|
||||
})
|
||||
-- Only create the .user file if it doesn't already exist.
|
||||
local user_file = project_root.."/build/xenia-gpu-d3d12-trace-dump.vcxproj.user"
|
||||
if not os.isfile(user_file) then
|
||||
debugdir(project_root)
|
||||
debugargs({
|
||||
"2>&1",
|
||||
"1>scratch/stdout-trace-dump.txt",
|
||||
})
|
||||
end
|
||||
|
||||
filter("architecture:x86_64")
|
||||
links({
|
||||
"xenia-cpu-backend-x64",
|
||||
})
|
||||
end
|
|
@ -77,8 +77,8 @@ reg::RB_DEPTHCONTROL GetNormalizedDepthControl(const RegisterFile& regs) {
|
|||
}
|
||||
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/d3d11/ne-d3d11-d3d11_standard_multisample_quality_levels
|
||||
const int8_t kD3D10StandardSamplePositions2x[2][2] = {{4, 4}, {-4, -4}};
|
||||
const int8_t kD3D10StandardSamplePositions4x[4][2] = {
|
||||
constexpr int8_t kD3D10StandardSamplePositions2x[2][2] = {{4, 4}, {-4, -4}};
|
||||
constexpr int8_t kD3D10StandardSamplePositions4x[4][2] = {
|
||||
{-2, -6}, {6, -2}, {-6, 2}, {2, 6}};
|
||||
|
||||
void GetPreferredFacePolygonOffset(const RegisterFile& regs,
|
||||
|
@ -907,7 +907,7 @@ void GetResolveEdramTileSpan(ResolveEdramInfo edram_info,
|
|||
rows_out = y1 - y0;
|
||||
}
|
||||
|
||||
const ResolveCopyShaderInfo
|
||||
constexpr ResolveCopyShaderInfo
|
||||
resolve_copy_shader_info[size_t(ResolveCopyShaderIndex::kCount)] = {
|
||||
{"Resolve Copy Fast 32bpp 1x/2xMSAA", false, 4, 4, 6, 3},
|
||||
{"Resolve Copy Fast 32bpp 4xMSAA", false, 4, 4, 6, 3},
|
||||
|
|
|
@ -2051,7 +2051,7 @@ void DxbcShaderTranslator::ProcessAllocInstruction(
|
|||
}
|
||||
}
|
||||
|
||||
const DxbcShaderTranslator::ShaderRdefType
|
||||
constexpr DxbcShaderTranslator::ShaderRdefType
|
||||
DxbcShaderTranslator::rdef_types_[size_t(
|
||||
DxbcShaderTranslator::ShaderRdefTypeIndex::kCount)] = {
|
||||
// kFloat
|
||||
|
@ -2104,7 +2104,7 @@ const DxbcShaderTranslator::ShaderRdefType
|
|||
dxbc::RdefVariableType::kUInt, 1, 4, 0, ShaderRdefTypeIndex::kUint4},
|
||||
};
|
||||
|
||||
const DxbcShaderTranslator::SystemConstantRdef
|
||||
constexpr DxbcShaderTranslator::SystemConstantRdef
|
||||
DxbcShaderTranslator::system_constant_rdef_[size_t(
|
||||
DxbcShaderTranslator::SystemConstants::Index::kCount)] = {
|
||||
{"xe_flags", ShaderRdefTypeIndex::kUint, sizeof(uint32_t)},
|
||||
|
|
|
@ -585,7 +585,7 @@ uint32_t DxbcShaderTranslator::FindOrAddSamplerBinding(
|
|||
name << "xe_sampler" << fetch_constant;
|
||||
if (aniso_filter == xenos::AnisoFilter::kDisabled ||
|
||||
aniso_filter == xenos::AnisoFilter::kUseFetchConst) {
|
||||
static const char kFilterSuffixes[] = {'p', 'l', 'b', 'f'};
|
||||
static constexpr char kFilterSuffixes[] = {'p', 'l', 'b', 'f'};
|
||||
name << '_' << kFilterSuffixes[uint32_t(mag_filter)]
|
||||
<< kFilterSuffixes[uint32_t(min_filter)]
|
||||
<< kFilterSuffixes[uint32_t(mip_filter)];
|
||||
|
@ -762,7 +762,7 @@ void DxbcShaderTranslator::ProcessTextureFetchInstruction(
|
|||
// sampling apparently round differently, so `mul` gives a value that would
|
||||
// be floored as expected, but the left/upper pixel is still sampled
|
||||
// instead.
|
||||
const float rounding_offset = 1.5f / 1024.0f;
|
||||
constexpr float rounding_offset = 1.5f / 1024.0f;
|
||||
switch (instr.dimension) {
|
||||
case xenos::FetchOpDimension::k1D:
|
||||
offsets[0] = instr.attributes.offset_x + rounding_offset;
|
||||
|
|
|
@ -173,7 +173,7 @@ X_STATUS GraphicsSystem::Setup(cpu::Processor* processor,
|
|||
: 1.0;
|
||||
uint64_t last_frame_time = Clock::QueryGuestTickCount();
|
||||
// Sleep for 90% of the vblank duration, spin for 10%
|
||||
const double duration_scalar = 0.90;
|
||||
constexpr double duration_scalar = 0.90;
|
||||
|
||||
while (frame_limiter_worker_running_) {
|
||||
register_file()->values[XE_GPU_REG_D1MODE_V_COUNTER] +=
|
||||
|
|
|
@ -47,8 +47,8 @@ PacketCategory PacketDisassembler::GetPacketCategory(const uint8_t* base_ptr) {
|
|||
bool PacketDisassembler::DisasmPacketType0(const uint8_t* base_ptr,
|
||||
uint32_t packet,
|
||||
PacketInfo* out_info) {
|
||||
static const PacketTypeInfo type_0_info = {PacketCategory::kGeneric,
|
||||
"PM4_TYPE0"};
|
||||
static constexpr PacketTypeInfo type_0_info = {PacketCategory::kGeneric,
|
||||
"PM4_TYPE0"};
|
||||
out_info->type_info = &type_0_info;
|
||||
|
||||
uint32_t count = ((packet >> 16) & 0x3FFF) + 1;
|
||||
|
@ -72,8 +72,8 @@ bool PacketDisassembler::DisasmPacketType0(const uint8_t* base_ptr,
|
|||
bool PacketDisassembler::DisasmPacketType1(const uint8_t* base_ptr,
|
||||
uint32_t packet,
|
||||
PacketInfo* out_info) {
|
||||
static const PacketTypeInfo type_1_info = {PacketCategory::kGeneric,
|
||||
"PM4_TYPE1"};
|
||||
static constexpr PacketTypeInfo type_1_info = {PacketCategory::kGeneric,
|
||||
"PM4_TYPE1"};
|
||||
out_info->type_info = &type_1_info;
|
||||
|
||||
out_info->count = 1 + 2;
|
||||
|
@ -94,8 +94,8 @@ bool PacketDisassembler::DisasmPacketType1(const uint8_t* base_ptr,
|
|||
bool PacketDisassembler::DisasmPacketType2(const uint8_t* base_ptr,
|
||||
uint32_t packet,
|
||||
PacketInfo* out_info) {
|
||||
static const PacketTypeInfo type_2_info = {PacketCategory::kGeneric,
|
||||
"PM4_TYPE2"};
|
||||
static constexpr PacketTypeInfo type_2_info = {PacketCategory::kGeneric,
|
||||
"PM4_TYPE2"};
|
||||
out_info->type_info = &type_2_info;
|
||||
|
||||
out_info->count = 1;
|
||||
|
@ -106,8 +106,8 @@ bool PacketDisassembler::DisasmPacketType2(const uint8_t* base_ptr,
|
|||
bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
|
||||
uint32_t packet,
|
||||
PacketInfo* out_info) {
|
||||
static const PacketTypeInfo type_3_unknown_info = {PacketCategory::kGeneric,
|
||||
"PM4_TYPE3_UNKNOWN"};
|
||||
static constexpr PacketTypeInfo type_3_unknown_info = {
|
||||
PacketCategory::kGeneric, "PM4_TYPE3_UNKNOWN"};
|
||||
out_info->type_info = &type_3_unknown_info;
|
||||
|
||||
uint32_t opcode = (packet >> 8) & 0x7F;
|
||||
|
@ -127,8 +127,8 @@ bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
|
|||
switch (opcode) {
|
||||
case PM4_ME_INIT: {
|
||||
// initialize CP's micro-engine
|
||||
static const PacketTypeInfo op_info = {PacketCategory::kGeneric,
|
||||
"PM4_ME_INIT"};
|
||||
static constexpr PacketTypeInfo op_info = {PacketCategory::kGeneric,
|
||||
"PM4_ME_INIT"};
|
||||
|
||||
out_actions.emplace_back(PacketAction::MeInit((uint32_t*)ptr, count));
|
||||
|
||||
|
@ -138,15 +138,15 @@ bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
|
|||
case PM4_NOP: {
|
||||
// skip N 32-bit words to get to the next packet
|
||||
// No-op, ignore some data.
|
||||
static const PacketTypeInfo op_info = {PacketCategory::kGeneric,
|
||||
"PM4_NOP"};
|
||||
static constexpr PacketTypeInfo op_info = {PacketCategory::kGeneric,
|
||||
"PM4_NOP"};
|
||||
out_info->type_info = &op_info;
|
||||
break;
|
||||
}
|
||||
case PM4_INTERRUPT: {
|
||||
// generate interrupt from the command stream
|
||||
static const PacketTypeInfo op_info = {PacketCategory::kGeneric,
|
||||
"PM4_INTERRUPT"};
|
||||
static constexpr PacketTypeInfo op_info = {PacketCategory::kGeneric,
|
||||
"PM4_INTERRUPT"};
|
||||
out_info->type_info = &op_info;
|
||||
|
||||
PacketAction intaction;
|
||||
|
@ -160,8 +160,8 @@ bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
|
|||
// VdSwap will post this to tell us we need to swap the screen/fire an
|
||||
// interrupt.
|
||||
// 63 words here, but only the first has any data.
|
||||
static const PacketTypeInfo op_info = {PacketCategory::kSwap,
|
||||
"PM4_XE_SWAP"};
|
||||
static constexpr PacketTypeInfo op_info = {PacketCategory::kSwap,
|
||||
"PM4_XE_SWAP"};
|
||||
out_info->type_info = &op_info;
|
||||
|
||||
PacketAction xsa;
|
||||
|
@ -175,8 +175,8 @@ bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
|
|||
case PM4_INDIRECT_BUFFER:
|
||||
case PM4_INDIRECT_BUFFER_PFD: {
|
||||
// indirect buffer dispatch
|
||||
static const PacketTypeInfo op_info = {PacketCategory::kGeneric,
|
||||
"PM4_INDIRECT_BUFFER"};
|
||||
static constexpr PacketTypeInfo op_info = {PacketCategory::kGeneric,
|
||||
"PM4_INDIRECT_BUFFER"};
|
||||
out_info->type_info = &op_info;
|
||||
|
||||
PacketAction iba;
|
||||
|
@ -189,8 +189,8 @@ bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
|
|||
}
|
||||
case PM4_WAIT_REG_MEM: {
|
||||
// wait until a register or memory location is a specific value
|
||||
static const PacketTypeInfo op_info = {PacketCategory::kGeneric,
|
||||
"PM4_WAIT_REG_MEM"};
|
||||
static constexpr PacketTypeInfo op_info = {PacketCategory::kGeneric,
|
||||
"PM4_WAIT_REG_MEM"};
|
||||
out_info->type_info = &op_info;
|
||||
|
||||
PacketAction wait_action;
|
||||
|
@ -209,8 +209,8 @@ bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
|
|||
case PM4_REG_RMW: {
|
||||
// register read/modify/write
|
||||
// ? (used during shader upload and edram setup)
|
||||
static const PacketTypeInfo op_info = {PacketCategory::kGeneric,
|
||||
"PM4_REG_RMW"};
|
||||
static constexpr PacketTypeInfo op_info = {PacketCategory::kGeneric,
|
||||
"PM4_REG_RMW"};
|
||||
out_info->type_info = &op_info;
|
||||
PacketAction rmw_action;
|
||||
rmw_action.type = PacketAction::Type::kRegRmw;
|
||||
|
@ -227,8 +227,8 @@ bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
|
|||
}
|
||||
case PM4_COND_WRITE: {
|
||||
// conditional write to memory or register
|
||||
static const PacketTypeInfo op_info = {PacketCategory::kGeneric,
|
||||
"PM4_COND_WRITE"};
|
||||
static constexpr PacketTypeInfo op_info = {PacketCategory::kGeneric,
|
||||
"PM4_COND_WRITE"};
|
||||
out_info->type_info = &op_info;
|
||||
PacketAction cwr_action;
|
||||
cwr_action.type = PacketAction::Type::kCondWrite;
|
||||
|
@ -247,8 +247,8 @@ bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
|
|||
}
|
||||
case PM4_EVENT_WRITE: {
|
||||
// generate an event that creates a write to memory when completed
|
||||
static const PacketTypeInfo op_info = {PacketCategory::kGeneric,
|
||||
"PM4_EVENT_WRITE"};
|
||||
static constexpr PacketTypeInfo op_info = {PacketCategory::kGeneric,
|
||||
"PM4_EVENT_WRITE"};
|
||||
out_info->type_info = &op_info;
|
||||
PacketAction evw_action;
|
||||
evw_action.type = Type::kEventWrite;
|
||||
|
@ -260,8 +260,8 @@ bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
|
|||
}
|
||||
case PM4_EVENT_WRITE_SHD: {
|
||||
// generate a VS|PS_done event
|
||||
static const PacketTypeInfo op_info = {PacketCategory::kGeneric,
|
||||
"PM4_EVENT_WRITE_SHD"};
|
||||
static constexpr PacketTypeInfo op_info = {PacketCategory::kGeneric,
|
||||
"PM4_EVENT_WRITE_SHD"};
|
||||
out_info->type_info = &op_info;
|
||||
PacketAction evws_action;
|
||||
evws_action.type = Type::kEventWriteSHD;
|
||||
|
@ -276,8 +276,8 @@ bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
|
|||
}
|
||||
case PM4_EVENT_WRITE_EXT: {
|
||||
// generate a screen extent event
|
||||
static const PacketTypeInfo op_info = {PacketCategory::kGeneric,
|
||||
"PM4_EVENT_WRITE_EXT"};
|
||||
static constexpr PacketTypeInfo op_info = {PacketCategory::kGeneric,
|
||||
"PM4_EVENT_WRITE_EXT"};
|
||||
out_info->type_info = &op_info;
|
||||
|
||||
PacketAction eve_action;
|
||||
|
@ -295,8 +295,8 @@ bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
|
|||
case PM4_DRAW_INDX: {
|
||||
// initiate fetch of index buffer and draw
|
||||
// dword0 = viz query info
|
||||
static const PacketTypeInfo op_info = {PacketCategory::kDraw,
|
||||
"PM4_DRAW_INDX"};
|
||||
static constexpr PacketTypeInfo op_info = {PacketCategory::kDraw,
|
||||
"PM4_DRAW_INDX"};
|
||||
out_info->type_info = &op_info;
|
||||
uint32_t dword0 = xe::load_and_swap<uint32_t>(ptr + 0);
|
||||
uint32_t dword1 = xe::load_and_swap<uint32_t>(ptr + 4);
|
||||
|
@ -337,8 +337,8 @@ bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
|
|||
}
|
||||
case PM4_DRAW_INDX_2: {
|
||||
// draw using supplied indices in packet
|
||||
static const PacketTypeInfo op_info = {PacketCategory::kDraw,
|
||||
"PM4_DRAW_INDX_2"};
|
||||
static constexpr PacketTypeInfo op_info = {PacketCategory::kDraw,
|
||||
"PM4_DRAW_INDX_2"};
|
||||
out_info->type_info = &op_info;
|
||||
uint32_t dword0 = xe::load_and_swap<uint32_t>(ptr + 0);
|
||||
uint32_t index_count = dword0 >> 16;
|
||||
|
@ -372,8 +372,8 @@ bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
|
|||
// load constant into chip and to memory
|
||||
// PM4_REG(reg) ((0x4 << 16) | (GSL_HAL_SUBBLOCK_OFFSET(reg)))
|
||||
// reg - 0x2000
|
||||
static const PacketTypeInfo op_info = {PacketCategory::kGeneric,
|
||||
"PM4_SET_CONSTANT"};
|
||||
static constexpr PacketTypeInfo op_info = {PacketCategory::kGeneric,
|
||||
"PM4_SET_CONSTANT"};
|
||||
out_info->type_info = &op_info;
|
||||
uint32_t offset_type = xe::load_and_swap<uint32_t>(ptr + 0);
|
||||
uint32_t index = offset_type & 0x7FF;
|
||||
|
@ -407,8 +407,8 @@ bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
|
|||
break;
|
||||
}
|
||||
case PM4_SET_CONSTANT2: {
|
||||
static const PacketTypeInfo op_info = {PacketCategory::kGeneric,
|
||||
"PM4_SET_CONSTANT2"};
|
||||
static constexpr PacketTypeInfo op_info = {PacketCategory::kGeneric,
|
||||
"PM4_SET_CONSTANT2"};
|
||||
out_info->type_info = &op_info;
|
||||
uint32_t offset_type = xe::load_and_swap<uint32_t>(ptr + 0);
|
||||
uint32_t index = offset_type & 0xFFFF;
|
||||
|
@ -424,8 +424,8 @@ bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
|
|||
}
|
||||
case PM4_LOAD_ALU_CONSTANT: {
|
||||
// load constants from memory
|
||||
static const PacketTypeInfo op_info = {PacketCategory::kGeneric,
|
||||
"PM4_LOAD_ALU_CONSTANT"};
|
||||
static constexpr PacketTypeInfo op_info = {PacketCategory::kGeneric,
|
||||
"PM4_LOAD_ALU_CONSTANT"};
|
||||
out_info->type_info = &op_info;
|
||||
uint32_t address = xe::load_and_swap<uint32_t>(ptr + 0);
|
||||
address &= 0x3FFFFFFF;
|
||||
|
@ -465,8 +465,8 @@ bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
|
|||
break;
|
||||
}
|
||||
case PM4_SET_SHADER_CONSTANTS: {
|
||||
static const PacketTypeInfo op_info = {PacketCategory::kGeneric,
|
||||
"PM4_SET_SHADER_CONSTANTS"};
|
||||
static constexpr PacketTypeInfo op_info = {PacketCategory::kGeneric,
|
||||
"PM4_SET_SHADER_CONSTANTS"};
|
||||
out_info->type_info = &op_info;
|
||||
uint32_t offset_type = xe::load_and_swap<uint32_t>(ptr + 0);
|
||||
uint32_t index = offset_type & 0xFFFF;
|
||||
|
@ -481,8 +481,8 @@ bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
|
|||
}
|
||||
case PM4_IM_LOAD: {
|
||||
// load sequencer instruction memory (pointer-based)
|
||||
static const PacketTypeInfo op_info = {PacketCategory::kGeneric,
|
||||
"PM4_IM_LOAD"};
|
||||
static constexpr PacketTypeInfo op_info = {PacketCategory::kGeneric,
|
||||
"PM4_IM_LOAD"};
|
||||
out_info->type_info = &op_info;
|
||||
uint32_t addr_type = xe::load_and_swap<uint32_t>(ptr + 0);
|
||||
auto shader_type = static_cast<xenos::ShaderType>(addr_type & 0x3);
|
||||
|
@ -506,8 +506,8 @@ bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
|
|||
}
|
||||
case PM4_IM_LOAD_IMMEDIATE: {
|
||||
// load sequencer instruction memory (code embedded in packet)
|
||||
static const PacketTypeInfo op_info = {PacketCategory::kGeneric,
|
||||
"PM4_IM_LOAD_IMMEDIATE"};
|
||||
static constexpr PacketTypeInfo op_info = {PacketCategory::kGeneric,
|
||||
"PM4_IM_LOAD_IMMEDIATE"};
|
||||
out_info->type_info = &op_info;
|
||||
uint32_t dword0 = xe::load_and_swap<uint32_t>(ptr + 0);
|
||||
uint32_t dword1 = xe::load_and_swap<uint32_t>(ptr + 4);
|
||||
|
@ -534,8 +534,8 @@ bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
|
|||
}
|
||||
case PM4_INVALIDATE_STATE: {
|
||||
// selective invalidation of state pointers
|
||||
static const PacketTypeInfo op_info = {PacketCategory::kGeneric,
|
||||
"PM4_INVALIDATE_STATE"};
|
||||
static constexpr PacketTypeInfo op_info = {PacketCategory::kGeneric,
|
||||
"PM4_INVALIDATE_STATE"};
|
||||
out_info->type_info = &op_info;
|
||||
uint32_t mask = xe::load_and_swap<uint32_t>(ptr + 0);
|
||||
|
||||
|
@ -547,8 +547,8 @@ bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
|
|||
break;
|
||||
}
|
||||
case PM4_SET_BIN_MASK_LO: {
|
||||
static const PacketTypeInfo op_info = {PacketCategory::kGeneric,
|
||||
"PM4_SET_BIN_MASK_LO"};
|
||||
static constexpr PacketTypeInfo op_info = {PacketCategory::kGeneric,
|
||||
"PM4_SET_BIN_MASK_LO"};
|
||||
out_info->type_info = &op_info;
|
||||
uint32_t value = xe::load_and_swap<uint32_t>(ptr);
|
||||
// bin_mask_ = (bin_mask_ & 0xFFFFFFFF00000000ull) | value;
|
||||
|
@ -561,8 +561,8 @@ bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
|
|||
break;
|
||||
}
|
||||
case PM4_SET_BIN_MASK_HI: {
|
||||
static const PacketTypeInfo op_info = {PacketCategory::kGeneric,
|
||||
"PM4_SET_BIN_MASK_HI"};
|
||||
static constexpr PacketTypeInfo op_info = {PacketCategory::kGeneric,
|
||||
"PM4_SET_BIN_MASK_HI"};
|
||||
out_info->type_info = &op_info;
|
||||
uint32_t value = xe::load_and_swap<uint32_t>(ptr);
|
||||
|
||||
|
@ -573,8 +573,8 @@ bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
|
|||
break;
|
||||
}
|
||||
case PM4_SET_BIN_SELECT_LO: {
|
||||
static const PacketTypeInfo op_info = {PacketCategory::kGeneric,
|
||||
"PM4_SET_BIN_SELECT_LO"};
|
||||
static constexpr PacketTypeInfo op_info = {PacketCategory::kGeneric,
|
||||
"PM4_SET_BIN_SELECT_LO"};
|
||||
out_info->type_info = &op_info;
|
||||
uint32_t value = xe::load_and_swap<uint32_t>(ptr);
|
||||
PacketAction action;
|
||||
|
@ -585,8 +585,8 @@ bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
|
|||
break;
|
||||
}
|
||||
case PM4_SET_BIN_SELECT_HI: {
|
||||
static const PacketTypeInfo op_info = {PacketCategory::kGeneric,
|
||||
"PM4_SET_BIN_SELECT_HI"};
|
||||
static constexpr PacketTypeInfo op_info = {PacketCategory::kGeneric,
|
||||
"PM4_SET_BIN_SELECT_HI"};
|
||||
out_info->type_info = &op_info;
|
||||
uint32_t value = xe::load_and_swap<uint32_t>(ptr);
|
||||
|
||||
|
@ -670,14 +670,14 @@ bool PacketDisassembler::DisasmPacketType3(const uint8_t* base_ptr,
|
|||
|
||||
// Ignored packets - useful if breaking on the default handler below.
|
||||
case 0x50: { // 0xC0015000 usually 2 words, 0xFFFFFFFF / 0x00000000
|
||||
static const PacketTypeInfo op_info = {PacketCategory::kGeneric,
|
||||
"PM4_TYPE3_0x50"};
|
||||
static constexpr PacketTypeInfo op_info = {PacketCategory::kGeneric,
|
||||
"PM4_TYPE3_0x50"};
|
||||
out_info->type_info = &op_info;
|
||||
break;
|
||||
}
|
||||
case 0x51: { // 0xC0015100 usually 2 words, 0xFFFFFFFF / 0xFFFFFFFF
|
||||
static const PacketTypeInfo op_info = {PacketCategory::kGeneric,
|
||||
"PM4_TYPE3_0x51"};
|
||||
static constexpr PacketTypeInfo op_info = {PacketCategory::kGeneric,
|
||||
"PM4_TYPE3_0x51"};
|
||||
out_info->type_info = &op_info;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -902,7 +902,8 @@ bool COMMAND_PROCESSOR::ExecutePacketType3_EVENT_WRITE_SHD(
|
|||
data_value = GpuSwap(data_value, endianness);
|
||||
uint8_t* write_destination = memory_->TranslatePhysical(address);
|
||||
if (address > 0x1FFFFFFF) {
|
||||
uint32_t writeback_base = register_file_->values[XE_GPU_REG_WRITEBACK_BASE];
|
||||
uint32_t writeback_base =
|
||||
register_file_->values[XE_GPU_REG_WRITEBACK_START];
|
||||
uint32_t writeback_size = register_file_->values[XE_GPU_REG_WRITEBACK_SIZE];
|
||||
uint32_t writeback_offset = address - writeback_base;
|
||||
// check whether the guest has written writeback base. if they haven't, skip
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -13,14 +13,14 @@ namespace xe {
|
|||
namespace gpu {
|
||||
namespace reg {
|
||||
|
||||
const Register RB_COLOR_INFO::rt_register_indices[4] = {
|
||||
constexpr Register RB_COLOR_INFO::rt_register_indices[4] = {
|
||||
XE_GPU_REG_RB_COLOR_INFO,
|
||||
XE_GPU_REG_RB_COLOR1_INFO,
|
||||
XE_GPU_REG_RB_COLOR2_INFO,
|
||||
XE_GPU_REG_RB_COLOR3_INFO,
|
||||
};
|
||||
|
||||
const Register RB_BLENDCONTROL::rt_register_indices[4] = {
|
||||
constexpr Register RB_BLENDCONTROL::rt_register_indices[4] = {
|
||||
XE_GPU_REG_RB_BLENDCONTROL0,
|
||||
XE_GPU_REG_RB_BLENDCONTROL1,
|
||||
XE_GPU_REG_RB_BLENDCONTROL2,
|
||||
|
|
|
@ -121,11 +121,11 @@ constexpr SwizzleSource GetSwizzledAluSourceComponent(
|
|||
component_index));
|
||||
}
|
||||
inline char GetCharForComponentIndex(uint32_t i) {
|
||||
const static char kChars[] = {'x', 'y', 'z', 'w'};
|
||||
constexpr static char kChars[] = {'x', 'y', 'z', 'w'};
|
||||
return kChars[i];
|
||||
}
|
||||
inline char GetCharForSwizzle(SwizzleSource swizzle_source) {
|
||||
const static char kChars[] = {'x', 'y', 'z', 'w', '0', '1'};
|
||||
constexpr static char kChars[] = {'x', 'y', 'z', 'w', '0', '1'};
|
||||
return kChars[static_cast<uint32_t>(swizzle_source)];
|
||||
}
|
||||
|
||||
|
|
|
@ -144,7 +144,7 @@ spv::Id SpirvShaderTranslator::ProcessVectorAluOperation(
|
|||
EnsureBuildPointAvailable();
|
||||
|
||||
// Lookup table for variants of instructions with similar structure.
|
||||
static const unsigned int kOps[] = {
|
||||
static constexpr unsigned int kOps[] = {
|
||||
static_cast<unsigned int>(spv::OpNop), // kAdd
|
||||
static_cast<unsigned int>(spv::OpNop), // kMul
|
||||
static_cast<unsigned int>(spv::OpFOrdGreaterThanEqual), // kMax
|
||||
|
@ -883,7 +883,7 @@ spv::Id SpirvShaderTranslator::ProcessScalarAluOperation(
|
|||
EnsureBuildPointAvailable();
|
||||
|
||||
// Lookup table for variants of instructions with similar structure.
|
||||
static const unsigned int kOps[] = {
|
||||
static constexpr unsigned int kOps[] = {
|
||||
static_cast<unsigned int>(spv::OpFAdd), // kAdds
|
||||
static_cast<unsigned int>(spv::OpFAdd), // kAddsPrev
|
||||
static_cast<unsigned int>(spv::OpNop), // kMuls
|
||||
|
|
|
@ -763,7 +763,7 @@ void SpirvShaderTranslator::ProcessTextureFetchInstruction(
|
|||
// multiplication in texture sampling apparently round differently, so
|
||||
// `mul` gives a value that would be floored as expected, but the
|
||||
// left/upper pixel is still sampled instead.
|
||||
const float kRoundingOffset = 1.5f / 1024.0f;
|
||||
constexpr float kRoundingOffset = 1.5f / 1024.0f;
|
||||
switch (instr.dimension) {
|
||||
case xenos::FetchOpDimension::k1D:
|
||||
offset_values[0] = instr.attributes.offset_x + kRoundingOffset;
|
||||
|
@ -2333,7 +2333,7 @@ size_t SpirvShaderTranslator::FindOrAddSamplerBinding(
|
|||
new_sampler_binding.mip_filter = mip_filter;
|
||||
new_sampler_binding.aniso_filter = aniso_filter;
|
||||
std::ostringstream name;
|
||||
static const char kFilterSuffixes[] = {'p', 'l', 'b', 'f'};
|
||||
static constexpr char kFilterSuffixes[] = {'p', 'l', 'b', 'f'};
|
||||
name << "xe_sampler" << fetch_constant << '_'
|
||||
<< kFilterSuffixes[uint32_t(mag_filter)]
|
||||
<< kFilterSuffixes[uint32_t(min_filter)]
|
||||
|
|
|
@ -566,7 +566,7 @@ void SpirvShaderTranslator::CompleteFragmentShaderInMain() {
|
|||
spv::Id alpha_test_result_non_not_equal;
|
||||
{
|
||||
// Function other than "not equal".
|
||||
static const spv::Op kAlphaTestOps[] = {
|
||||
static constexpr spv::Op kAlphaTestOps[] = {
|
||||
spv::OpFOrdLessThan, spv::OpFOrdEqual, spv::OpFOrdGreaterThan};
|
||||
for (uint32_t i = 0; i < 3; ++i) {
|
||||
spv::Id alpha_test_comparison_result = builder_->createBinOp(
|
||||
|
|
|
@ -60,7 +60,7 @@ void ConvertTexelCTX1ToR8G8(xenos::Endian endian, void* output,
|
|||
} block;
|
||||
static_assert(sizeof(block) == 8, "CTX1 block mismatch");
|
||||
|
||||
const uint32_t bytes_per_block = 8;
|
||||
constexpr uint32_t bytes_per_block = 8;
|
||||
CopySwapBlock(endian, block.data, input, bytes_per_block);
|
||||
|
||||
uint8_t cr[4] = {
|
||||
|
@ -84,7 +84,7 @@ void ConvertTexelCTX1ToR8G8(xenos::Endian endian, void* output,
|
|||
|
||||
void ConvertTexelDXT3AToDXT3(xenos::Endian endian, void* output,
|
||||
const void* input, size_t length) {
|
||||
const uint32_t bytes_per_block = 16;
|
||||
constexpr uint32_t bytes_per_block = 16;
|
||||
auto output_bytes = static_cast<uint8_t*>(output);
|
||||
CopySwapBlock(endian, &output_bytes[0], input, 8);
|
||||
std::memset(&output_bytes[8], 0, 8);
|
||||
|
|
|
@ -100,7 +100,7 @@ void TextureDump(const TextureInfo& src, void* buffer, size_t length) {
|
|||
|
||||
FILE* handle = filesystem::OpenFile(path, "wb");
|
||||
if (handle) {
|
||||
const char signature[4] = {'D', 'D', 'S', ' '};
|
||||
constexpr char signature[4] = {'D', 'D', 'S', ' '};
|
||||
fwrite(&signature, sizeof(signature), 1, handle);
|
||||
fwrite(&dds_header, sizeof(dds_header), 1, handle);
|
||||
fwrite(buffer, 1, length, handle);
|
||||
|
|
|
@ -19,7 +19,7 @@ using namespace xe::gpu::xenos;
|
|||
#define FORMAT_INFO(texture_format, format, block_width, block_height, bits_per_pixel) \
|
||||
{xenos::TextureFormat::texture_format, FormatType::format, block_width, block_height, bits_per_pixel}
|
||||
const FormatInfo* FormatInfo::Get(uint32_t gpu_format) {
|
||||
static const FormatInfo format_infos[64] = {
|
||||
static constexpr FormatInfo format_infos[64] = {
|
||||
#include "texture_info_formats.inl"
|
||||
};
|
||||
return &format_infos[gpu_format];
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace xe {
|
|||
namespace gpu {
|
||||
|
||||
// Trace file extension.
|
||||
static const char kTraceExtension[] = "xtr";
|
||||
static constexpr char kTraceExtension[] = "xtr";
|
||||
|
||||
// Any byte changes to the files should bump this version.
|
||||
// Only builds with matching versions will work.
|
||||
|
|
|
@ -47,11 +47,11 @@ namespace gpu {
|
|||
|
||||
using namespace xe::gpu::xenos;
|
||||
|
||||
static const ImVec4 kColorError =
|
||||
static constexpr ImVec4 kColorError =
|
||||
ImVec4(255 / 255.0f, 0 / 255.0f, 0 / 255.0f, 255 / 255.0f);
|
||||
static const ImVec4 kColorComment =
|
||||
static constexpr ImVec4 kColorComment =
|
||||
ImVec4(42 / 255.0f, 179 / 255.0f, 0 / 255.0f, 255 / 255.0f);
|
||||
static const ImVec4 kColorIgnored =
|
||||
static constexpr ImVec4 kColorIgnored =
|
||||
ImVec4(100 / 255.0f, 100 / 255.0f, 100 / 255.0f, 255 / 255.0f);
|
||||
|
||||
TraceViewer::TraceViewer(xe::ui::WindowedAppContext& app_context,
|
||||
|
@ -815,10 +815,11 @@ void TraceViewer::DrawVertexFetcher(Shader* shader,
|
|||
}
|
||||
ImGui::BeginChild("#indices", ImVec2(0, 300));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(10, 0));
|
||||
int display_start, display_end;
|
||||
ImGui::CalcListClipping(vertex_count, ImGui::GetTextLineHeight(),
|
||||
&display_start, &display_end);
|
||||
ImGui::Dummy(ImVec2(0, (display_start)*ImGui::GetTextLineHeight()));
|
||||
int display_start = 0;
|
||||
int display_end = 0;
|
||||
// ImGui::CalcListClipping(vertex_count, ImGui::GetTextLineHeight(),
|
||||
// &display_start, &display_end);
|
||||
// ImGui::Dummy(ImVec2(0, (display_start)*ImGui::GetTextLineHeight()));
|
||||
ImGui::Columns(column_count);
|
||||
if (display_start <= 1) {
|
||||
for (size_t el_index = 0; el_index < vertex_binding.attributes.size();
|
||||
|
@ -1641,11 +1642,12 @@ void TraceViewer::DrawStateUI() {
|
|||
|
||||
ImGui::BeginChild("#vsvertices", ImVec2(0, 300));
|
||||
|
||||
int display_start, display_end;
|
||||
ImGui::CalcListClipping(int(vertices.size() / 4),
|
||||
ImGui::GetTextLineHeight(), &display_start,
|
||||
&display_end);
|
||||
ImGui::Dummy(ImVec2(0, (display_start)*ImGui::GetTextLineHeight()));
|
||||
int display_start = 0;
|
||||
int display_end = 0;
|
||||
// ImGui::CalcListClipping(int(vertices.size() / 4),
|
||||
// ImGui::GetTextLineHeight(), &display_start,
|
||||
// &display_end);
|
||||
// ImGui::Dummy(ImVec2(0, (display_start)*ImGui::GetTextLineHeight()));
|
||||
|
||||
ImGui::Columns(int(el_size), "#vsvertices", true);
|
||||
for (size_t i = display_start; i < display_end; i++) {
|
||||
|
@ -1706,11 +1708,12 @@ void TraceViewer::DrawStateUI() {
|
|||
}
|
||||
ImGui::BeginChild("#indices", ImVec2(0, 300));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
|
||||
int display_start, display_end;
|
||||
ImGui::CalcListClipping(1 + draw_info.index_count,
|
||||
ImGui::GetTextLineHeight(), &display_start,
|
||||
&display_end);
|
||||
ImGui::Dummy(ImVec2(0, (display_start)*ImGui::GetTextLineHeight()));
|
||||
int display_start = 0;
|
||||
int display_end = 0;
|
||||
// ImGui::CalcListClipping(1 + draw_info.index_count,
|
||||
// ImGui::GetTextLineHeight(), &display_start,
|
||||
// &display_end);
|
||||
// ImGui::Dummy(ImVec2(0, (display_start)*ImGui::GetTextLineHeight()));
|
||||
ImGui::Columns(2, "#indices", true);
|
||||
ImGui::SetColumnOffset(1, 60);
|
||||
if (display_start <= 1) {
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace xe {
|
|||
namespace gpu {
|
||||
namespace ucode {
|
||||
|
||||
const AluScalarOpcodeInfo kAluScalarOpcodeInfos[64] = {
|
||||
constexpr AluScalarOpcodeInfo kAluScalarOpcodeInfos[64] = {
|
||||
{"adds", 1, true, kAluOpChangedStateNone},
|
||||
{"adds_prev", 1, false, kAluOpChangedStateNone},
|
||||
{"muls", 1, true, kAluOpChangedStateNone},
|
||||
|
@ -80,7 +80,7 @@ const AluScalarOpcodeInfo kAluScalarOpcodeInfos[64] = {
|
|||
{"opcode_63", 0, false, kAluOpChangedStateNone},
|
||||
};
|
||||
|
||||
const AluVectorOpcodeInfo kAluVectorOpcodeInfos[32] = {
|
||||
constexpr AluVectorOpcodeInfo kAluVectorOpcodeInfos[32] = {
|
||||
{"add", {0b1111, 0b1111}, kAluOpChangedStateNone},
|
||||
{"mul", {0b1111, 0b1111}, kAluOpChangedStateNone},
|
||||
{"max", {0b1111, 0b1111}, kAluOpChangedStateNone},
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue