Merge branch 'stenzek:master' into master

This commit is contained in:
Daniel Nylander 2024-12-05 07:56:25 +01:00 committed by GitHub
commit 390e796ffc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
207 changed files with 9545 additions and 4436 deletions

View File

@ -2,6 +2,7 @@ name: 🐧 Linux AppImage
on:
workflow_call:
workflow_dispatch:
jobs:
linux-x64-appimage-build:
@ -14,7 +15,7 @@ jobs:
fetch-depth: 0
- name: Install Packages
run: scripts/appimage/install-packages.sh
run: scripts/packaging/appimage/install-packages.sh
- name: Cache Dependencies
id: cache-deps
@ -66,7 +67,7 @@ jobs:
cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON -DCMAKE_PREFIX_PATH="$HOME/deps" -DCMAKE_C_COMPILER=clang-18 -DCMAKE_CXX_COMPILER=clang++-18 -DCMAKE_EXE_LINKER_FLAGS_INIT="-fuse-ld=lld" -DCMAKE_MODULE_LINKER_FLAGS_INIT="-fuse-ld=lld" -DCMAKE_SHARED_LINKER_FLAGS_INIT="-fuse-ld=lld" ..
cmake --build . --parallel
cd ..
scripts/appimage/make-appimage.sh $(realpath .) $(realpath ./build) $HOME/deps DuckStation-x64
scripts/packaging/appimage/make-appimage.sh $(realpath .) $(realpath ./build) $HOME/deps DuckStation-x64
- name: Upload Qt AppImage
uses: actions/upload-artifact@v4.3.3
@ -85,7 +86,7 @@ jobs:
fetch-depth: 0
- name: Install Packages
run: scripts/appimage/install-packages.sh
run: scripts/packaging/appimage/install-packages.sh
- name: Cache Dependencies
id: cache-deps
@ -137,7 +138,7 @@ jobs:
cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DDISABLE_SSE4=ON -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON -DCMAKE_PREFIX_PATH="$HOME/deps" -DCMAKE_C_COMPILER=clang-18 -DCMAKE_CXX_COMPILER=clang++-18 -DCMAKE_EXE_LINKER_FLAGS_INIT="-fuse-ld=lld" -DCMAKE_MODULE_LINKER_FLAGS_INIT="-fuse-ld=lld" -DCMAKE_SHARED_LINKER_FLAGS_INIT="-fuse-ld=lld" ..
cmake --build . --parallel
cd ..
scripts/appimage/make-appimage.sh $(realpath .) $(realpath ./build) $HOME/deps DuckStation-x64-SSE2
scripts/packaging/appimage/make-appimage.sh $(realpath .) $(realpath ./build) $HOME/deps DuckStation-x64-SSE2
- name: Upload Qt AppImage
uses: actions/upload-artifact@v4.3.3

View File

@ -11,6 +11,7 @@ on:
required: false
type: string
default: "stable"
workflow_dispatch:
jobs:
linux-flatpak-build:
@ -59,21 +60,21 @@ jobs:
- name: Generate AppStream XML
run: |
scripts/generate-metainfo.sh scripts/flatpak
cat scripts/flatpak/org.duckstation.DuckStation.metainfo.xml
scripts/packaging/generate-metainfo.sh scripts/packaging/flatpak
cat scripts/packaging/flatpak/org.duckstation.DuckStation.metainfo.xml
- name: Validate AppStream XML
run: flatpak-builder-lint appstream scripts/flatpak/org.duckstation.DuckStation.metainfo.xml
run: flatpak-builder-lint appstream scripts/packaging/flatpak/org.duckstation.DuckStation.metainfo.xml
- name: Validate Manifest
run: flatpak-builder-lint manifest scripts/flatpak/org.duckstation.DuckStation.yaml
run: flatpak-builder-lint manifest scripts/packaging/flatpak/org.duckstation.DuckStation.yaml
- name: Build Flatpak
uses: flathub-infra/flatpak-github-actions/flatpak-builder@23796715b3dfa4c86ddf50cf29c3cc8b3c82dca8
with:
bundle: duckstation-x64.flatpak
upload-artifact: false
manifest-path: scripts/flatpak/org.duckstation.DuckStation.yaml
manifest-path: scripts/packaging/flatpak/org.duckstation.DuckStation.yaml
arch: x86_64
build-bundle: true
verbose: true
@ -81,7 +82,7 @@ jobs:
branch: stable
cache: true
restore-cache: true
cache-key: flatpak-x64-${{ hashFiles('scripts/flatpak/**/*.yaml') }}
cache-key: flatpak-x64-${{ hashFiles('scripts/packaging/flatpak/**/*.yaml') }}
- name: Validate Build
run: |

View File

@ -2,6 +2,7 @@ name: 🍎 MacOS
on:
workflow_call:
workflow_dispatch:
jobs:
macos-build:
@ -13,8 +14,8 @@ jobs:
with:
fetch-depth: 0
- name: Use Xcode 15.4
run: sudo xcode-select -s /Applications/Xcode_15.4.app
- name: Use Xcode 16.1
run: sudo xcode-select -s /Applications/Xcode_16.1.app
- name: Install packages
shell: bash

View File

@ -1,6 +1,7 @@
name: Automated Builds
on:
workflow_dispatch:
pull_request:
paths-ignore:
- '**.md'

View File

@ -2,6 +2,7 @@ name: 💻 Windows
on:
workflow_call:
workflow_dispatch:
jobs:
windows-x64-build:

View File

@ -42,10 +42,6 @@ if(LINUX OR BSD)
set(CMAKE_POSITION_INDEPENDENT_CODE TRUE)
endif()
# Set _DEBUG macro for Debug builds.
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D_DEBUG")
# Release build optimizations for MSVC.
if(MSVC)
add_definitions("/D_CRT_SECURE_NO_WARNINGS")
@ -59,14 +55,18 @@ if(MSVC)
# RelWithDebInfo is set to Ob1 instead of Ob2.
string(REPLACE "/Ob1" "/Ob2" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
string(REPLACE "/Ob1" "/Ob2" CMAKE_C_FLAGS_DEVEL "${CMAKE_C_FLAGS_DEVEL}")
string(REPLACE "/Ob1" "/Ob2" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
string(REPLACE "/Ob1" "/Ob2" CMAKE_CXX_FLAGS_DEVEL "${CMAKE_CXX_FLAGS_DEVEL}")
# Disable incremental linking in RelWithDebInfo.
string(REPLACE "/INCREMENTAL" "/INCREMENTAL:NO" CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO}")
string(REPLACE "/INCREMENTAL" "/INCREMENTAL:NO" CMAKE_EXE_LINKER_FLAGS_DEVEL "${CMAKE_EXE_LINKER_FLAGS_DEVEL}")
# COMDAT folding/remove unused functions.
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /OPT:REF /OPT:ICF")
set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} /OPT:REF /OPT:ICF")
set(CMAKE_EXE_LINKER_FLAGS_DEVEL "${CMAKE_EXE_LINKER_FLAGS_DEVEL} /OPT:REF /OPT:ICF")
endif()
# Warning disables.

View File

@ -16,3 +16,17 @@ endif()
if(APPLE)
option(SKIP_POSTPROCESS_BUNDLE "Disable bundle post-processing, including Qt additions" OFF)
endif()
# Set _DEBUG macro for Debug builds.
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D_DEBUG")
# Create the Devel build type based on RelWithDebInfo.
set(CMAKE_C_FLAGS_DEVEL "${CMAKE_C_FLAGS_RELWITHDEBINFO} -D_DEVEL" CACHE STRING "Flags used by the C compiler during DEVEL builds." FORCE)
set(CMAKE_CXX_FLAGS_DEVEL "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -D_DEVEL" CACHE STRING "Flags used by the CXX compiler during DEVEL builds." FORCE)
set(CMAKE_EXE_LINKER_FLAGS_DEVEL "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO}" CACHE STRING "Flags used for the linker during DEVEL builds." FORCE)
set(CMAKE_MODULE_LINKER_FLAGS_DEVEL "${CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO}" CACHE STRING "Flags used by the linker during the creation of modules during DEVEL builds." FORCE)
set(CMAKE_SHARED_LINKER_FLAGS_DEVEL "${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO}" CACHE STRING "Flags used by the linker during the creation of shared libraries during DEVEL builds." FORCE)
set(CMAKE_STATIC_LINKER_FLAGS_DEVEL "${CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO}" CACHE STRING "Flags used by the linker during the creation of static libraries during DEVEL builds." FORCE)
list(APPEND CMAKE_CONFIGURATION_TYPES "Devel")
mark_as_advanced(CMAKE_C_FLAGS_DEVEL CMAKE_CXX_FLAGS_DEVEL CMAKE_EXE_LINKER_FLAGS_DEVEL CMAKE_MODULE_LINKER_FLAGS_DEVEL CMAKE_SHARED_LINKER_FLAGS_DEVEL CMAKE_STATIC_LINKER_FLAGS_DEVEL)

View File

@ -9735,6 +9735,9 @@ SLES-02626:
controllers:
- AnalogController
- DigitalController
settings:
dmaMaxSliceTicks: 100 # Stops large VRAM transfer DMA from blazing
dmaHaltTicks: 200 # past the deferred CDROM async interrupt.
metadata:
publisher: "3DO"
developer: "3DO"
@ -9754,6 +9757,9 @@ SLES-02627:
controllers:
- AnalogController
- DigitalController
settings:
dmaMaxSliceTicks: 100 # Stops large VRAM transfer DMA from blazing
dmaHaltTicks: 200 # past the deferred CDROM async interrupt.
metadata:
publisher: "3DO"
developer: "3DO"
@ -9773,6 +9779,9 @@ SLES-02628:
controllers:
- AnalogController
- DigitalController
settings:
dmaMaxSliceTicks: 100 # Stops large VRAM transfer DMA from blazing
dmaHaltTicks: 200 # past the deferred CDROM async interrupt.
metadata:
publisher: "3DO"
developer: "3DO"
@ -9792,6 +9801,9 @@ SLES-02630:
controllers:
- AnalogController
- DigitalController
settings:
dmaMaxSliceTicks: 100 # Stops large VRAM transfer DMA from blazing
dmaHaltTicks: 200 # past the deferred CDROM async interrupt.
metadata:
publisher: "3DO"
developer: "3DO"
@ -9811,6 +9823,9 @@ SLES-02629:
controllers:
- AnalogController
- DigitalController
settings:
dmaMaxSliceTicks: 100 # Stops large VRAM transfer DMA from blazing
dmaHaltTicks: 200 # past the deferred CDROM async interrupt.
metadata:
publisher: "3DO"
developer: "3DO"
@ -9833,6 +9848,9 @@ SLUS-00914:
controllers:
- AnalogController
- DigitalController
settings:
dmaMaxSliceTicks: 100 # Stops large VRAM transfer DMA from blazing
dmaHaltTicks: 200 # past the deferred CDROM async interrupt.
metadata:
publisher: "3DO"
developer: "3DO"
@ -15751,6 +15769,7 @@ SLPS-02300:
traits:
- DisableWidescreen
- ForcePGXPCPUMode # Fixes jitter in character models.
- ForceRecompilerICache # Fixes hangs in CD code.
metadata:
publisher: "Capcom"
developer: "Capcom Production Studio 4"
@ -15772,6 +15791,7 @@ SLPM-80485:
traits:
- DisableWidescreen
- ForcePGXPCPUMode # Fixes jitter in character models.
- ForceRecompilerICache # Fixes hangs in CD code.
SLPM-87224:
name: "Biohazard 3 - Last Escape (Japan) (Rev 1)"
controllers:
@ -15780,6 +15800,7 @@ SLPM-87224:
traits:
- DisableWidescreen
- ForcePGXPCPUMode # Fixes jitter in character models.
- ForceRecompilerICache # Fixes hangs in CD code.
metadata:
publisher: "Capcom"
developer: "Capcom Production Studio 4"
@ -19208,6 +19229,7 @@ SLUS-01170:
- AnalogController
- DigitalController
- PlayStationMouse
- JogCon
metadata:
publisher: "Atari / Hasbro Interactive"
developer: "Supersonic Software Ltd"
@ -19228,6 +19250,7 @@ SLES-02854:
- AnalogController
- DigitalController
- PlayStationMouse
- JogCon
metadata:
publisher: "Atari / Hasbro Interactive"
developer: "Supersonic Software Ltd"
@ -113120,6 +113143,7 @@ SLUS-01003:
- AnalogController
- DigitalController
- NeGcon
- JogCon
metadata:
publisher: "Electronic Arts / Infogrames"
developer: "Eden Studios"
@ -131665,6 +131689,7 @@ SCPS-45354:
- AnalogController
- DigitalController
- NeGcon
- JogCon
codes:
- SCPS-45354
- SCPS-45355
@ -131688,6 +131713,7 @@ SLPS-01798:
- AnalogController
- DigitalController
- NeGcon
- JogCon
metadata:
publisher: "Namco"
developer: "Namco"
@ -131708,6 +131734,7 @@ SCPS-45356:
- AnalogController
- DigitalController
- NeGcon
- JogCon
codes:
- SCPS-45356
- SLPS-01800
@ -131733,6 +131760,7 @@ SLUS-00797:
- AnalogController
- DigitalController
- NeGcon
- JogCon
metadata:
publisher: "Namco"
developer: "Namco"
@ -131753,6 +131781,7 @@ SLPS-91463:
- AnalogController
- DigitalController
- NeGcon
- JogCon
metadata:
publisher: "Namco"
developer: "Namco"
@ -135716,6 +135745,7 @@ SLES-02529:
traits:
- DisableWidescreen
- ForcePGXPCPUMode # Fixes jitter in character models.
- ForceRecompilerICache # Fixes hangs in CD code.
libcrypt: true
metadata:
publisher: "Eidos Interactive"
@ -135738,6 +135768,7 @@ SLED-02541:
traits:
- DisableWidescreen
- ForcePGXPCPUMode # Fixes jitter in character models.
- ForceRecompilerICache # Fixes hangs in CD code.
SLES-02530:
name: "Resident Evil 3 - Nemesis (France)"
controllers:
@ -135746,6 +135777,7 @@ SLES-02530:
traits:
- DisableWidescreen
- ForcePGXPCPUMode # Fixes jitter in character models.
- ForceRecompilerICache # Fixes hangs in CD code.
libcrypt: true
metadata:
publisher: "Eidos Interactive"
@ -135769,6 +135801,7 @@ SLES-02531:
traits:
- DisableWidescreen
- ForcePGXPCPUMode # Fixes jitter in character models.
- ForceRecompilerICache # Fixes hangs in CD code.
libcrypt: true
metadata:
publisher: "Eidos Interactive"
@ -135792,6 +135825,7 @@ SLES-02698:
traits:
- DisableWidescreen
- ForcePGXPCPUMode # Fixes jitter in character models.
- ForceRecompilerICache # Fixes hangs in CD code.
libcrypt: true
metadata:
publisher: "Eidos Interactive"
@ -135815,6 +135849,7 @@ SLES-02533:
traits:
- DisableWidescreen
- ForcePGXPCPUMode # Fixes jitter in character models.
- ForceRecompilerICache # Fixes hangs in CD code.
libcrypt: true
metadata:
publisher: "Eidos Interactive"
@ -135841,6 +135876,7 @@ SLES-02532:
traits:
- DisableWidescreen
- ForcePGXPCPUMode # Fixes jitter in character models.
- ForceRecompilerICache # Fixes hangs in CD code.
libcrypt: true
metadata:
publisher: "Proein / Eidos Interactive"
@ -135867,6 +135903,7 @@ SLUS-00923:
traits:
- DisableWidescreen
- ForcePGXPCPUMode # Fixes jitter in character models.
- ForceRecompilerICache # Fixes hangs in CD code.
metadata:
publisher: "Capcom"
developer: "Capcom Production Studio 4"
@ -135888,6 +135925,7 @@ SLUS-90064:
traits:
- DisableWidescreen
- ForcePGXPCPUMode # Fixes jitter in character models.
- ForceRecompilerICache # Fixes hangs in CD code.
SLPS-01974:
name: "Restaurant Dream (Japan)"
controllers:
@ -136471,6 +136509,7 @@ SCES-01706:
- AnalogController
- DigitalController
- NeGcon
- JogCon
metadata:
publisher: "Sony Computer Entertaiment Europe"
developer: "Namco"
@ -179398,6 +179437,7 @@ SLES-01907:
- AnalogController
- DigitalController
- NeGcon
- JogCon
libcrypt: true
metadata:
publisher: "Infogrames"
@ -179421,6 +179461,7 @@ SLPS-02516:
- AnalogController
- DigitalController
- NeGcon
- JogCon
codes:
- SLPS-02516
- SLPS-91467

View File

@ -82,4 +82,9 @@
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="$(Configuration.Contains(Devel))">
<ClCompile>
<PreprocessorDefinitions>_DEVEL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
</Project>

View File

@ -57,6 +57,14 @@
<Configuration>Release-Clang</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Devel-Clang|ARM64">
<Configuration>Devel-Clang</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Devel-Clang|x64">
<Configuration>Devel-Clang</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">

View File

@ -67,6 +67,8 @@ Global
DebugFast|x64 = DebugFast|x64
DebugFast-Clang|ARM64 = DebugFast-Clang|ARM64
DebugFast-Clang|x64 = DebugFast-Clang|x64
Devel-Clang|ARM64 = Devel-Clang|ARM64
Devel-Clang|x64 = Devel-Clang|x64
Release|ARM64 = Release|ARM64
Release|x64 = Release|x64
Release-Clang|ARM64 = Release-Clang|ARM64
@ -79,6 +81,44 @@ Global
ReleaseLTCG-Clang-SSE2|x64 = ReleaseLTCG-Clang-SSE2|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug|ARM64.ActiveCfg = Debug-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug|x64.ActiveCfg = Debug|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug|x64.Build.0 = Debug|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug-Clang|ARM64.ActiveCfg = Debug-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug-Clang|ARM64.Build.0 = Debug-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug-Clang|x64.ActiveCfg = Debug-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug-Clang|x64.Build.0 = Debug-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug-Clang-SSE2|ARM64.ActiveCfg = Debug-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug-Clang-SSE2|x64.ActiveCfg = Debug-Clang-SSE2|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug-Clang-SSE2|x64.Build.0 = Debug-Clang-SSE2|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.DebugFast|ARM64.ActiveCfg = DebugFast-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.DebugFast|x64.ActiveCfg = DebugFast|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.DebugFast|x64.Build.0 = DebugFast|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.DebugFast-Clang|ARM64.ActiveCfg = DebugFast-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Release|x64.ActiveCfg = Release|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Release|x64.Build.0 = Release|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Release-Clang|ARM64.ActiveCfg = Release-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Release-Clang|ARM64.Build.0 = Release-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Release-Clang|x64.ActiveCfg = Release-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Release-Clang|x64.Build.0 = Release-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG|ARM64.ActiveCfg = ReleaseLTCG-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG|x64.ActiveCfg = ReleaseLTCG|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG|x64.Build.0 = ReleaseLTCG|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG-Clang|ARM64.ActiveCfg = ReleaseLTCG-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG-Clang|ARM64.Build.0 = ReleaseLTCG-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG-Clang|x64.ActiveCfg = ReleaseLTCG-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG-Clang|x64.Build.0 = ReleaseLTCG-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG-Clang-SSE2|ARM64.ActiveCfg = ReleaseLTCG-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG-Clang-SSE2|x64.ActiveCfg = ReleaseLTCG-Clang-SSE2|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG-Clang-SSE2|x64.Build.0 = ReleaseLTCG-Clang-SSE2|x64
{43540154-9E1E-409C-834F-B84BE5621388}.Debug|ARM64.ActiveCfg = Debug-Clang|ARM64
{43540154-9E1E-409C-834F-B84BE5621388}.Debug|x64.ActiveCfg = Debug|x64
{43540154-9E1E-409C-834F-B84BE5621388}.Debug|x64.Build.0 = Debug|x64
@ -96,6 +136,10 @@ Global
{43540154-9E1E-409C-834F-B84BE5621388}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{43540154-9E1E-409C-834F-B84BE5621388}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{43540154-9E1E-409C-834F-B84BE5621388}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{43540154-9E1E-409C-834F-B84BE5621388}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{43540154-9E1E-409C-834F-B84BE5621388}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{43540154-9E1E-409C-834F-B84BE5621388}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{43540154-9E1E-409C-834F-B84BE5621388}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{43540154-9E1E-409C-834F-B84BE5621388}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{43540154-9E1E-409C-834F-B84BE5621388}.Release|x64.ActiveCfg = Release|x64
{43540154-9E1E-409C-834F-B84BE5621388}.Release|x64.Build.0 = Release|x64
@ -130,6 +174,10 @@ Global
{BB08260F-6FBC-46AF-8924-090EE71360C6}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{BB08260F-6FBC-46AF-8924-090EE71360C6}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{BB08260F-6FBC-46AF-8924-090EE71360C6}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{BB08260F-6FBC-46AF-8924-090EE71360C6}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{BB08260F-6FBC-46AF-8924-090EE71360C6}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{BB08260F-6FBC-46AF-8924-090EE71360C6}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{BB08260F-6FBC-46AF-8924-090EE71360C6}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{BB08260F-6FBC-46AF-8924-090EE71360C6}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{BB08260F-6FBC-46AF-8924-090EE71360C6}.Release|x64.ActiveCfg = Release|x64
{BB08260F-6FBC-46AF-8924-090EE71360C6}.Release|x64.Build.0 = Release|x64
@ -164,6 +212,10 @@ Global
{EE054E08-3799-4A59-A422-18259C105FFD}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{EE054E08-3799-4A59-A422-18259C105FFD}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{EE054E08-3799-4A59-A422-18259C105FFD}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{EE054E08-3799-4A59-A422-18259C105FFD}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{EE054E08-3799-4A59-A422-18259C105FFD}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{EE054E08-3799-4A59-A422-18259C105FFD}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{EE054E08-3799-4A59-A422-18259C105FFD}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{EE054E08-3799-4A59-A422-18259C105FFD}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{EE054E08-3799-4A59-A422-18259C105FFD}.Release|x64.ActiveCfg = Release|x64
{EE054E08-3799-4A59-A422-18259C105FFD}.Release|x64.Build.0 = Release|x64
@ -198,6 +250,10 @@ Global
{868B98C8-65A1-494B-8346-250A73A48C0A}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{868B98C8-65A1-494B-8346-250A73A48C0A}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{868B98C8-65A1-494B-8346-250A73A48C0A}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{868B98C8-65A1-494B-8346-250A73A48C0A}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{868B98C8-65A1-494B-8346-250A73A48C0A}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{868B98C8-65A1-494B-8346-250A73A48C0A}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{868B98C8-65A1-494B-8346-250A73A48C0A}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{868B98C8-65A1-494B-8346-250A73A48C0A}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{868B98C8-65A1-494B-8346-250A73A48C0A}.Release|x64.ActiveCfg = Release|x64
{868B98C8-65A1-494B-8346-250A73A48C0A}.Release|x64.Build.0 = Release|x64
@ -232,6 +288,10 @@ Global
{3773F4CC-614E-4028-8595-22E08CA649E3}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{3773F4CC-614E-4028-8595-22E08CA649E3}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{3773F4CC-614E-4028-8595-22E08CA649E3}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{3773F4CC-614E-4028-8595-22E08CA649E3}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{3773F4CC-614E-4028-8595-22E08CA649E3}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{3773F4CC-614E-4028-8595-22E08CA649E3}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{3773F4CC-614E-4028-8595-22E08CA649E3}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{3773F4CC-614E-4028-8595-22E08CA649E3}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{3773F4CC-614E-4028-8595-22E08CA649E3}.Release|x64.ActiveCfg = Release|x64
{3773F4CC-614E-4028-8595-22E08CA649E3}.Release|x64.Build.0 = Release|x64
@ -249,40 +309,6 @@ Global
{3773F4CC-614E-4028-8595-22E08CA649E3}.ReleaseLTCG-Clang-SSE2|ARM64.ActiveCfg = ReleaseLTCG-Clang|ARM64
{3773F4CC-614E-4028-8595-22E08CA649E3}.ReleaseLTCG-Clang-SSE2|x64.ActiveCfg = ReleaseLTCG-Clang-SSE2|x64
{3773F4CC-614E-4028-8595-22E08CA649E3}.ReleaseLTCG-Clang-SSE2|x64.Build.0 = ReleaseLTCG-Clang-SSE2|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug|ARM64.ActiveCfg = Debug-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug|x64.ActiveCfg = Debug|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug|x64.Build.0 = Debug|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug-Clang|ARM64.ActiveCfg = Debug-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug-Clang|ARM64.Build.0 = Debug-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug-Clang|x64.ActiveCfg = Debug-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug-Clang|x64.Build.0 = Debug-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug-Clang-SSE2|ARM64.ActiveCfg = Debug-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug-Clang-SSE2|x64.ActiveCfg = Debug-Clang-SSE2|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Debug-Clang-SSE2|x64.Build.0 = Debug-Clang-SSE2|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.DebugFast|ARM64.ActiveCfg = DebugFast-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.DebugFast|x64.ActiveCfg = DebugFast|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.DebugFast|x64.Build.0 = DebugFast|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.DebugFast-Clang|ARM64.ActiveCfg = DebugFast-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Release|x64.ActiveCfg = Release|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Release|x64.Build.0 = Release|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Release-Clang|ARM64.ActiveCfg = Release-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Release-Clang|ARM64.Build.0 = Release-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Release-Clang|x64.ActiveCfg = Release-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.Release-Clang|x64.Build.0 = Release-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG|ARM64.ActiveCfg = ReleaseLTCG-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG|x64.ActiveCfg = ReleaseLTCG|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG|x64.Build.0 = ReleaseLTCG|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG-Clang|ARM64.ActiveCfg = ReleaseLTCG-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG-Clang|ARM64.Build.0 = ReleaseLTCG-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG-Clang|x64.ActiveCfg = ReleaseLTCG-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG-Clang|x64.Build.0 = ReleaseLTCG-Clang|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG-Clang-SSE2|ARM64.ActiveCfg = ReleaseLTCG-Clang|ARM64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG-Clang-SSE2|x64.ActiveCfg = ReleaseLTCG-Clang-SSE2|x64
{28F14272-0EC4-41BB-849F-182ADB81AF70}.ReleaseLTCG-Clang-SSE2|x64.Build.0 = ReleaseLTCG-Clang-SSE2|x64
{72F9423C-91EE-4487-AAC6-555ED6F61AA1}.Debug|ARM64.ActiveCfg = Debug-Clang|ARM64
{72F9423C-91EE-4487-AAC6-555ED6F61AA1}.Debug|x64.ActiveCfg = Debug|x64
{72F9423C-91EE-4487-AAC6-555ED6F61AA1}.Debug|x64.Build.0 = Debug|x64
@ -300,6 +326,10 @@ Global
{72F9423C-91EE-4487-AAC6-555ED6F61AA1}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{72F9423C-91EE-4487-AAC6-555ED6F61AA1}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{72F9423C-91EE-4487-AAC6-555ED6F61AA1}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{72F9423C-91EE-4487-AAC6-555ED6F61AA1}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{72F9423C-91EE-4487-AAC6-555ED6F61AA1}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{72F9423C-91EE-4487-AAC6-555ED6F61AA1}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{72F9423C-91EE-4487-AAC6-555ED6F61AA1}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{72F9423C-91EE-4487-AAC6-555ED6F61AA1}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{72F9423C-91EE-4487-AAC6-555ED6F61AA1}.Release|x64.ActiveCfg = Release|x64
{72F9423C-91EE-4487-AAC6-555ED6F61AA1}.Release|x64.Build.0 = Release|x64
@ -334,6 +364,10 @@ Global
{8BDA439C-6358-45FB-9994-2FF083BABE06}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{8BDA439C-6358-45FB-9994-2FF083BABE06}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{8BDA439C-6358-45FB-9994-2FF083BABE06}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{8BDA439C-6358-45FB-9994-2FF083BABE06}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{8BDA439C-6358-45FB-9994-2FF083BABE06}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{8BDA439C-6358-45FB-9994-2FF083BABE06}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{8BDA439C-6358-45FB-9994-2FF083BABE06}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{8BDA439C-6358-45FB-9994-2FF083BABE06}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{8BDA439C-6358-45FB-9994-2FF083BABE06}.Release|x64.ActiveCfg = Release|x64
{8BDA439C-6358-45FB-9994-2FF083BABE06}.Release|x64.Build.0 = Release|x64
@ -368,6 +402,10 @@ Global
{425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.Release|x64.ActiveCfg = Release|x64
{425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.Release|x64.Build.0 = Release|x64
@ -402,6 +440,10 @@ Global
{DD944834-7899-4C1C-A4C1-064B5009D239}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{DD944834-7899-4C1C-A4C1-064B5009D239}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{DD944834-7899-4C1C-A4C1-064B5009D239}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{DD944834-7899-4C1C-A4C1-064B5009D239}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{DD944834-7899-4C1C-A4C1-064B5009D239}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{DD944834-7899-4C1C-A4C1-064B5009D239}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{DD944834-7899-4C1C-A4C1-064B5009D239}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{DD944834-7899-4C1C-A4C1-064B5009D239}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{DD944834-7899-4C1C-A4C1-064B5009D239}.Release|x64.ActiveCfg = Release|x64
{DD944834-7899-4C1C-A4C1-064B5009D239}.Release|x64.Build.0 = Release|x64
@ -436,6 +478,10 @@ Global
{09553C96-9F39-49BF-8AE6-7ACBD07C410C}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{09553C96-9F39-49BF-8AE6-7ACBD07C410C}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{09553C96-9F39-49BF-8AE6-7ACBD07C410C}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{09553C96-9F39-49BF-8AE6-7ACBD07C410C}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{09553C96-9F39-49BF-8AE6-7ACBD07C410C}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{09553C96-9F39-49BF-8AE6-7ACBD07C410C}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{09553C96-9F39-49BF-8AE6-7ACBD07C410C}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{09553C96-9F39-49BF-8AE6-7ACBD07C410C}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{09553C96-9F39-49BF-8AE6-7ACBD07C410C}.Release|x64.ActiveCfg = Release|x64
{09553C96-9F39-49BF-8AE6-7ACBD07C410C}.Release|x64.Build.0 = Release|x64
@ -470,6 +516,10 @@ Global
{49953E1B-2EF7-46A4-B88B-1BF9E099093B}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{49953E1B-2EF7-46A4-B88B-1BF9E099093B}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{49953E1B-2EF7-46A4-B88B-1BF9E099093B}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{49953E1B-2EF7-46A4-B88B-1BF9E099093B}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{49953E1B-2EF7-46A4-B88B-1BF9E099093B}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{49953E1B-2EF7-46A4-B88B-1BF9E099093B}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{49953E1B-2EF7-46A4-B88B-1BF9E099093B}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{49953E1B-2EF7-46A4-B88B-1BF9E099093B}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{49953E1B-2EF7-46A4-B88B-1BF9E099093B}.Release|x64.ActiveCfg = Release|x64
{49953E1B-2EF7-46A4-B88B-1BF9E099093B}.Release|x64.Build.0 = Release|x64
@ -497,6 +547,8 @@ Global
{EA2B9C7A-B8CC-42F9-879B-191A98680C10}.DebugFast|x64.ActiveCfg = DebugFast|x64
{EA2B9C7A-B8CC-42F9-879B-191A98680C10}.DebugFast-Clang|ARM64.ActiveCfg = DebugFast-Clang|ARM64
{EA2B9C7A-B8CC-42F9-879B-191A98680C10}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{EA2B9C7A-B8CC-42F9-879B-191A98680C10}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{EA2B9C7A-B8CC-42F9-879B-191A98680C10}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{EA2B9C7A-B8CC-42F9-879B-191A98680C10}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{EA2B9C7A-B8CC-42F9-879B-191A98680C10}.Release|x64.ActiveCfg = Release|x64
{EA2B9C7A-B8CC-42F9-879B-191A98680C10}.Release-Clang|ARM64.ActiveCfg = Release-Clang|ARM64
@ -524,6 +576,10 @@ Global
{075CED82-6A20-46DF-94C7-9624AC9DDBEB}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{075CED82-6A20-46DF-94C7-9624AC9DDBEB}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{075CED82-6A20-46DF-94C7-9624AC9DDBEB}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{075CED82-6A20-46DF-94C7-9624AC9DDBEB}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{075CED82-6A20-46DF-94C7-9624AC9DDBEB}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{075CED82-6A20-46DF-94C7-9624AC9DDBEB}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{075CED82-6A20-46DF-94C7-9624AC9DDBEB}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{075CED82-6A20-46DF-94C7-9624AC9DDBEB}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{075CED82-6A20-46DF-94C7-9624AC9DDBEB}.Release|x64.ActiveCfg = Release|x64
{075CED82-6A20-46DF-94C7-9624AC9DDBEB}.Release|x64.Build.0 = Release|x64
@ -551,6 +607,8 @@ Global
{32EEAF44-57F8-4C6C-A6F0-DE5667123DD5}.DebugFast|x64.ActiveCfg = DebugFast|x64
{32EEAF44-57F8-4C6C-A6F0-DE5667123DD5}.DebugFast-Clang|ARM64.ActiveCfg = DebugFast-Clang|ARM64
{32EEAF44-57F8-4C6C-A6F0-DE5667123DD5}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{32EEAF44-57F8-4C6C-A6F0-DE5667123DD5}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{32EEAF44-57F8-4C6C-A6F0-DE5667123DD5}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{32EEAF44-57F8-4C6C-A6F0-DE5667123DD5}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{32EEAF44-57F8-4C6C-A6F0-DE5667123DD5}.Release|x64.ActiveCfg = Release|x64
{32EEAF44-57F8-4C6C-A6F0-DE5667123DD5}.Release-Clang|ARM64.ActiveCfg = Release-Clang|ARM64
@ -576,6 +634,9 @@ Global
{8906836E-F06E-46E8-B11A-74E5E8C7B8FB}.DebugFast-Clang|ARM64.ActiveCfg = DebugFast-Clang|ARM64
{8906836E-F06E-46E8-B11A-74E5E8C7B8FB}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{8906836E-F06E-46E8-B11A-74E5E8C7B8FB}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{8906836E-F06E-46E8-B11A-74E5E8C7B8FB}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{8906836E-F06E-46E8-B11A-74E5E8C7B8FB}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{8906836E-F06E-46E8-B11A-74E5E8C7B8FB}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{8906836E-F06E-46E8-B11A-74E5E8C7B8FB}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{8906836E-F06E-46E8-B11A-74E5E8C7B8FB}.Release|x64.ActiveCfg = Release|x64
{8906836E-F06E-46E8-B11A-74E5E8C7B8FB}.Release-Clang|ARM64.ActiveCfg = Release-Clang|ARM64
@ -605,6 +666,10 @@ Global
{4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.Release|x64.ActiveCfg = Release|x64
{4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.Release|x64.Build.0 = Release|x64
@ -633,6 +698,8 @@ Global
{3029310E-4211-4C87-801A-72E130A648EF}.DebugFast-Clang|ARM64.ActiveCfg = DebugFast-Clang|ARM64
{3029310E-4211-4C87-801A-72E130A648EF}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{3029310E-4211-4C87-801A-72E130A648EF}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{3029310E-4211-4C87-801A-72E130A648EF}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{3029310E-4211-4C87-801A-72E130A648EF}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{3029310E-4211-4C87-801A-72E130A648EF}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{3029310E-4211-4C87-801A-72E130A648EF}.Release|x64.ActiveCfg = Release|x64
{3029310E-4211-4C87-801A-72E130A648EF}.Release-Clang|ARM64.ActiveCfg = Release-Clang|ARM64
@ -661,6 +728,10 @@ Global
{E4357877-D459-45C7-B8F6-DCBB587BB528}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{E4357877-D459-45C7-B8F6-DCBB587BB528}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{E4357877-D459-45C7-B8F6-DCBB587BB528}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{E4357877-D459-45C7-B8F6-DCBB587BB528}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{E4357877-D459-45C7-B8F6-DCBB587BB528}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{E4357877-D459-45C7-B8F6-DCBB587BB528}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{E4357877-D459-45C7-B8F6-DCBB587BB528}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{E4357877-D459-45C7-B8F6-DCBB587BB528}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{E4357877-D459-45C7-B8F6-DCBB587BB528}.Release|x64.ActiveCfg = Release|x64
{E4357877-D459-45C7-B8F6-DCBB587BB528}.Release|x64.Build.0 = Release|x64
@ -695,6 +766,10 @@ Global
{8BE398E6-B882-4248-9065-FECC8728E038}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{8BE398E6-B882-4248-9065-FECC8728E038}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{8BE398E6-B882-4248-9065-FECC8728E038}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{8BE398E6-B882-4248-9065-FECC8728E038}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{8BE398E6-B882-4248-9065-FECC8728E038}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{8BE398E6-B882-4248-9065-FECC8728E038}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{8BE398E6-B882-4248-9065-FECC8728E038}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{8BE398E6-B882-4248-9065-FECC8728E038}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{8BE398E6-B882-4248-9065-FECC8728E038}.Release|x64.ActiveCfg = Release|x64
{8BE398E6-B882-4248-9065-FECC8728E038}.Release|x64.Build.0 = Release|x64
@ -729,6 +804,10 @@ Global
{57F6206D-F264-4B07-BAF8-11B9BBE1F455}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{57F6206D-F264-4B07-BAF8-11B9BBE1F455}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{57F6206D-F264-4B07-BAF8-11B9BBE1F455}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{57F6206D-F264-4B07-BAF8-11B9BBE1F455}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{57F6206D-F264-4B07-BAF8-11B9BBE1F455}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{57F6206D-F264-4B07-BAF8-11B9BBE1F455}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{57F6206D-F264-4B07-BAF8-11B9BBE1F455}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{57F6206D-F264-4B07-BAF8-11B9BBE1F455}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{57F6206D-F264-4B07-BAF8-11B9BBE1F455}.Release|x64.ActiveCfg = Release|x64
{57F6206D-F264-4B07-BAF8-11B9BBE1F455}.Release|x64.Build.0 = Release|x64
@ -761,6 +840,9 @@ Global
{C51A346A-86B2-46DF-9BB3-D0AA7E5D8699}.DebugFast-Clang|ARM64.ActiveCfg = DebugFast-Clang|ARM64
{C51A346A-86B2-46DF-9BB3-D0AA7E5D8699}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{C51A346A-86B2-46DF-9BB3-D0AA7E5D8699}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{C51A346A-86B2-46DF-9BB3-D0AA7E5D8699}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{C51A346A-86B2-46DF-9BB3-D0AA7E5D8699}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{C51A346A-86B2-46DF-9BB3-D0AA7E5D8699}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{C51A346A-86B2-46DF-9BB3-D0AA7E5D8699}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{C51A346A-86B2-46DF-9BB3-D0AA7E5D8699}.Release|x64.ActiveCfg = Release|x64
{C51A346A-86B2-46DF-9BB3-D0AA7E5D8699}.Release-Clang|ARM64.ActiveCfg = Release-Clang|ARM64
@ -788,6 +870,10 @@ Global
{F351C4D8-594A-4850-B77B-3C1249812CCE}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{F351C4D8-594A-4850-B77B-3C1249812CCE}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{F351C4D8-594A-4850-B77B-3C1249812CCE}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{F351C4D8-594A-4850-B77B-3C1249812CCE}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{F351C4D8-594A-4850-B77B-3C1249812CCE}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{F351C4D8-594A-4850-B77B-3C1249812CCE}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{F351C4D8-594A-4850-B77B-3C1249812CCE}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{F351C4D8-594A-4850-B77B-3C1249812CCE}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{F351C4D8-594A-4850-B77B-3C1249812CCE}.Release|x64.ActiveCfg = Release|x64
{F351C4D8-594A-4850-B77B-3C1249812CCE}.Release|x64.Build.0 = Release|x64
@ -822,6 +908,10 @@ Global
{27B8D4BB-4F01-4432-BC14-9BF6CA458EEE}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{27B8D4BB-4F01-4432-BC14-9BF6CA458EEE}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{27B8D4BB-4F01-4432-BC14-9BF6CA458EEE}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{27B8D4BB-4F01-4432-BC14-9BF6CA458EEE}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{27B8D4BB-4F01-4432-BC14-9BF6CA458EEE}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{27B8D4BB-4F01-4432-BC14-9BF6CA458EEE}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{27B8D4BB-4F01-4432-BC14-9BF6CA458EEE}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{27B8D4BB-4F01-4432-BC14-9BF6CA458EEE}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{27B8D4BB-4F01-4432-BC14-9BF6CA458EEE}.Release|x64.ActiveCfg = Release|x64
{27B8D4BB-4F01-4432-BC14-9BF6CA458EEE}.Release|x64.Build.0 = Release|x64
@ -856,6 +946,10 @@ Global
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.DebugFast-Clang|ARM64.Build.0 = DebugFast-Clang|ARM64
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.DebugFast-Clang|x64.Build.0 = DebugFast-Clang|x64
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.Devel-Clang|ARM64.Build.0 = Devel-Clang|ARM64
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.Devel-Clang|x64.Build.0 = Devel-Clang|x64
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.Release|x64.ActiveCfg = Release|x64
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.Release|x64.Build.0 = Release|x64

View File

@ -1,5 +0,0 @@
set(CMAKE_C_COMPILER /usr/bin/clang-16)
set(CMAKE_CXX_COMPILER /usr/bin/clang++-16)
set(CMAKE_EXE_LINKER_FLAGS_INIT "-fuse-ld=lld")
set(CMAKE_MODULE_LINKER_FLAGS_INIT "-fuse-ld=lld")
set(CMAKE_SHARED_LINKER_FLAGS_INIT "-fuse-ld=lld")

View File

@ -62,14 +62,14 @@ if [ "${INSTALLDIR:0:1}" != "/" ]; then
fi
FREETYPE=2.13.3
HARFBUZZ=10.0.1
HARFBUZZ=10.1.0
LIBBACKTRACE=86885d14049fab06ef8a33aac51664230ca09200
LIBJPEGTURBO=3.0.4
LIBPNG=1.6.44
LIBWEBP=1.4.0
LIBZIP=1.11.1
LIBZIP=1.11.2
SDL2=2.30.9
QT=6.8.0
QT=6.8.1
ZSTD=1.5.6
CPUINFO=7524ad504fdcfcf75a18a133da6abd75c5d48053
@ -116,7 +116,7 @@ if [ "$SKIP_HARFBUZZ" != true ]; then
curl -C - -L -o "harfbuzz-$HARFBUZZ.tar.gz" "https://github.com/harfbuzz/harfbuzz/archive/refs/tags/$HARFBUZZ.tar.gz"
fi
cat >> SHASUMS <<EOF
e7358ea86fe10fb9261931af6f010d4358dac64f7074420ca9bc94aae2bdd542 harfbuzz-$HARFBUZZ.tar.gz
c758fdce8587641b00403ee0df2cd5d30cbea7803d43c65fddd76224f7b49b88 harfbuzz-$HARFBUZZ.tar.gz
EOF
fi
if [ "$SKIP_LIBJPEG" != true ]; then
@ -148,7 +148,7 @@ if [ "$SKIP_LIBZIP" != true ]; then
curl -C - -L -O "https://github.com/nih-at/libzip/releases/download/v$LIBZIP/libzip-$LIBZIP.tar.xz"
fi
cat >> SHASUMS <<EOF
721e0e4e851073b508c243fd75eda04e4c5006158a900441de10ce274cc3b633 libzip-$LIBZIP.tar.xz
5d471308cef4c4752bbcf973d9cd37ba4cb53739116c30349d4764ba1410dfc1 libzip-$LIBZIP.tar.xz
EOF
fi
if [ "$SKIP_ZSTD" != true ]; then
@ -170,12 +170,12 @@ if [ "$SKIP_QT" != true ]; then
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtwayland-everywhere-src-$QT.tar.xz"
fi
cat >> SHASUMS <<EOF
1bad481710aa27f872de6c9f72651f89a6107f0077003d0ebfcc9fd15cba3c75 qtbase-everywhere-src-$QT.tar.xz
595bf8557b91e1f8ebc726f1e09868a3c7e610ff5045068f2d4ea2428c49a5d4 qtimageformats-everywhere-src-$QT.tar.xz
cf7a593d5e520f8177240610d9e55d5b75b0887fe5f385554ff64377f1646199 qtsvg-everywhere-src-$QT.tar.xz
403115d8268503c6cc6e43310c8ae28eb9e605072a5d04e4a2de8b6af39981f7 qttools-everywhere-src-$QT.tar.xz
84bf2b67c243cd0c50a08acd7bfa9df2b1965028511815c1b6b65a0687437cb6 qttranslations-everywhere-src-$QT.tar.xz
175758591638ebf1c6fbb66ac11c7fa0eb8d4ed52e9243cc59075d06a6a2060a qtwayland-everywhere-src-$QT.tar.xz
40b14562ef3bd779bc0e0418ea2ae08fa28235f8ea6e8c0cb3bce1d6ad58dcaf qtbase-everywhere-src-$QT.tar.xz
138cc2909aa98f5ff7283e36eb3936eb5e625d3ca3b4febae2ca21d8903dd237 qtimageformats-everywhere-src-$QT.tar.xz
3d0de73596e36b2daa7c48d77c4426bb091752856912fba720215f756c560dd0 qtsvg-everywhere-src-$QT.tar.xz
9d43d409be08b8681a0155a9c65114b69c9a3fc11aef6487bb7fdc5b283c432d qttools-everywhere-src-$QT.tar.xz
635a6093e99152243b807de51077485ceadd4786d4acb135b9340b2303035a4a qttranslations-everywhere-src-$QT.tar.xz
2226fbde4e2ddd12f8bf4b239c8f38fd706a54e789e63467dfddc77129eca203 qtwayland-everywhere-src-$QT.tar.xz
EOF
fi

View File

@ -37,16 +37,16 @@ if [ "${INSTALLDIR:0:1}" != "/" ]; then
fi
FREETYPE=2.13.3
HARFBUZZ=10.0.1
HARFBUZZ=10.1.0
SDL2=2.30.9
ZSTD=1.5.6
LIBPNG=1.6.44
LIBJPEGTURBO=3.0.4
LIBWEBP=1.4.0
LIBZIP=1.11.1
FFMPEG=7.0.2
LIBZIP=1.11.2
FFMPEG=7.1
MOLTENVK=1.2.9
QT=6.8.0
QT=6.8.1
CPUINFO=7524ad504fdcfcf75a18a133da6abd75c5d48053
DISCORD_RPC=144f3a3f1209994d8d9e8a87964a989cb9911c1e
@ -73,22 +73,28 @@ CMAKE_ARCH_X64=-DCMAKE_OSX_ARCHITECTURES="x86_64"
CMAKE_ARCH_ARM64=-DCMAKE_OSX_ARCHITECTURES="arm64"
CMAKE_ARCH_UNIVERSAL=-DCMAKE_OSX_ARCHITECTURES="x86_64;arm64"
# SBOM generation appears to be broken on MacOS, and I can't be arsed to debug it.
CMAKE_COMMON_QT=(
-DCMAKE_OSX_ARCHITECTURES="x86_64;arm64"
-DQT_GENERATE_SBOM=OFF
)
cat > SHASUMS <<EOF
0550350666d427c74daeb85d5ac7bb353acba5f76956395995311a9c6f063289 freetype-$FREETYPE.tar.xz
e7358ea86fe10fb9261931af6f010d4358dac64f7074420ca9bc94aae2bdd542 harfbuzz-$HARFBUZZ.tar.gz
c758fdce8587641b00403ee0df2cd5d30cbea7803d43c65fddd76224f7b49b88 harfbuzz-$HARFBUZZ.tar.gz
60c4da1d5b7f0aa8d158da48e8f8afa9773c1c8baa5d21974df61f1886b8ce8e libpng-$LIBPNG.tar.xz
99130559e7d62e8d695f2c0eaeef912c5828d5b84a0537dcb24c9678c9d5b76b libjpeg-turbo-$LIBJPEGTURBO.tar.gz
61f873ec69e3be1b99535634340d5bde750b2e4447caa1db9f61be3fd49ab1e5 libwebp-$LIBWEBP.tar.gz
721e0e4e851073b508c243fd75eda04e4c5006158a900441de10ce274cc3b633 libzip-$LIBZIP.tar.xz
5d471308cef4c4752bbcf973d9cd37ba4cb53739116c30349d4764ba1410dfc1 libzip-$LIBZIP.tar.xz
24b574f71c87a763f50704bbb630cbe38298d544a1f890f099a4696b1d6beba4 SDL2-$SDL2.tar.gz
8c29e06cf42aacc1eafc4077ae2ec6c6fcb96a626157e0593d5e82a34fd403c1 zstd-$ZSTD.tar.gz
8646515b638a3ad303e23af6a3587734447cb8fc0a0c064ecdb8e95c4fd8b389 ffmpeg-$FFMPEG.tar.xz
40973d44970dbc83ef302b0609f2e74982be2d85916dd2ee7472d30678a7abe6 ffmpeg-$FFMPEG.tar.xz
f415a09385030c6510a936155ce211f617c31506db5fbc563e804345f1ecf56e v$MOLTENVK.tar.gz
1bad481710aa27f872de6c9f72651f89a6107f0077003d0ebfcc9fd15cba3c75 qtbase-everywhere-src-$QT.tar.xz
595bf8557b91e1f8ebc726f1e09868a3c7e610ff5045068f2d4ea2428c49a5d4 qtimageformats-everywhere-src-$QT.tar.xz
cf7a593d5e520f8177240610d9e55d5b75b0887fe5f385554ff64377f1646199 qtsvg-everywhere-src-$QT.tar.xz
403115d8268503c6cc6e43310c8ae28eb9e605072a5d04e4a2de8b6af39981f7 qttools-everywhere-src-$QT.tar.xz
84bf2b67c243cd0c50a08acd7bfa9df2b1965028511815c1b6b65a0687437cb6 qttranslations-everywhere-src-$QT.tar.xz
40b14562ef3bd779bc0e0418ea2ae08fa28235f8ea6e8c0cb3bce1d6ad58dcaf qtbase-everywhere-src-$QT.tar.xz
138cc2909aa98f5ff7283e36eb3936eb5e625d3ca3b4febae2ca21d8903dd237 qtimageformats-everywhere-src-$QT.tar.xz
3d0de73596e36b2daa7c48d77c4426bb091752856912fba720215f756c560dd0 qtsvg-everywhere-src-$QT.tar.xz
9d43d409be08b8681a0155a9c65114b69c9a3fc11aef6487bb7fdc5b283c432d qttools-everywhere-src-$QT.tar.xz
635a6093e99152243b807de51077485ceadd4786d4acb135b9340b2303035a4a qttranslations-everywhere-src-$QT.tar.xz
e1351218d270db49c3dddcba04fb2153b09731ea3fa6830e423f5952f44585be cpuinfo-$CPUINFO.tar.gz
3eea5ccce6670c126282f1ba4d32c19d486db49a1a5cbfb8d6f48774784d310c discord-rpc-$DISCORD_RPC.tar.gz
3998b024b0d442614a9ee270e76e018bb37a17b8c6941212171731123cbbcac7 lunasvg-$LUNASVG.tar.gz
@ -301,7 +307,7 @@ patch -u src/tools/macdeployqt/shared/shared.cpp <<EOF
// Platforminputcontext plugins if QtGui is in use
EOF
cmake -B build "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_UNIVERSAL" -DFEATURE_dbus=OFF -DFEATURE_framework=OFF -DFEATURE_icu=OFF -DFEATURE_opengl=OFF -DFEATURE_sql=OFF -DFEATURE_gssapi=OFF -DFEATURE_system_png=ON -DFEATURE_system_jpeg=ON -DFEATURE_system_zlib=ON -DFEATURE_system_freetype=ON -DFEATURE_system_harfbuzz=ON
cmake -B build "${CMAKE_COMMON[@]}" "${CMAKE_COMMON_QT[@]}" -DFEATURE_dbus=OFF -DFEATURE_framework=OFF -DFEATURE_icu=OFF -DFEATURE_opengl=OFF -DFEATURE_sql=OFF -DFEATURE_gssapi=OFF -DFEATURE_system_png=ON -DFEATURE_system_jpeg=ON -DFEATURE_system_zlib=ON -DFEATURE_system_freetype=ON -DFEATURE_system_harfbuzz=ON
make -C build "-j$NPROCS"
make -C build install
cd ..
@ -312,7 +318,7 @@ tar xf "qtsvg-everywhere-src-$QT.tar.xz"
cd "qtsvg-everywhere-src-$QT"
mkdir build
cd build
"$INSTALLDIR/bin/qt-configure-module" .. -- "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_UNIVERSAL"
"$INSTALLDIR/bin/qt-configure-module" .. -- "${CMAKE_COMMON[@]}" "${CMAKE_COMMON_QT[@]}"
make "-j$NPROCS"
make install
cd ../..
@ -323,7 +329,7 @@ tar xf "qtimageformats-everywhere-src-$QT.tar.xz"
cd "qtimageformats-everywhere-src-$QT"
mkdir build
cd build
"$INSTALLDIR/bin/qt-configure-module" .. -- "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_UNIVERSAL" -DFEATURE_system_webp=ON
"$INSTALLDIR/bin/qt-configure-module" .. -- "${CMAKE_COMMON[@]}" "${CMAKE_COMMON_QT[@]}" -DFEATURE_system_webp=ON
make "-j$NPROCS"
make install
cd ../..
@ -334,7 +340,7 @@ tar xf "qttools-everywhere-src-$QT.tar.xz"
cd "qttools-everywhere-src-$QT"
mkdir build
cd build
"$INSTALLDIR/bin/qt-configure-module" .. -- "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_UNIVERSAL" -DFEATURE_assistant=OFF -DFEATURE_clang=OFF -DFEATURE_designer=ON -DFEATURE_kmap2qmap=OFF -DFEATURE_linguist=ON -DFEATURE_pixeltool=OFF -DFEATURE_pkg_config=OFF -DFEATURE_qev=OFF -DFEATURE_qtattributionsscanner=OFF -DFEATURE_qtdiag=OFF -DFEATURE_qtplugininfo=OFF
"$INSTALLDIR/bin/qt-configure-module" .. -- "${CMAKE_COMMON[@]}" "${CMAKE_COMMON_QT[@]}" -DFEATURE_assistant=OFF -DFEATURE_clang=OFF -DFEATURE_designer=ON -DFEATURE_kmap2qmap=OFF -DFEATURE_linguist=ON -DFEATURE_pixeltool=OFF -DFEATURE_pkg_config=OFF -DFEATURE_qev=OFF -DFEATURE_qtattributionsscanner=OFF -DFEATURE_qtdiag=OFF -DFEATURE_qtplugininfo=OFF
make "-j$NPROCS"
make install
cd ../..
@ -345,7 +351,7 @@ tar xf "qttranslations-everywhere-src-$QT.tar.xz"
cd "qttranslations-everywhere-src-$QT"
mkdir build
cd build
"$INSTALLDIR/bin/qt-configure-module" .. -- "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_UNIVERSAL"
"$INSTALLDIR/bin/qt-configure-module" .. -- "${CMAKE_COMMON[@]}" "${CMAKE_COMMON_QT[@]}"
make "-j$NPROCS"
make install
cd ../..

View File

@ -46,14 +46,14 @@ echo INSTALLDIR=%INSTALLDIR%
cd "%BUILDDIR%"
set FREETYPE=2.13.3
set HARFBUZZ=10.0.1
set HARFBUZZ=10.1.0
set LIBJPEGTURBO=3.0.4
set LIBPNG=1644
set QT=6.8.0
set QT=6.8.1
set QTMINOR=6.8
set SDL2=2.30.9
set WEBP=1.4.0
set LIBZIP=1.11.1
set LIBZIP=1.11.2
set ZLIB=1.3.1
set ZLIBSHORT=131
set ZSTD=1.5.6
@ -68,20 +68,20 @@ set DXCOMPILER=1.8.2407.12
set DXAGILITY=1.614.1
call :downloadfile "freetype-%FREETYPE%.tar.gz" "https://download.savannah.gnu.org/releases/freetype/freetype-%FREETYPE%.tar.gz" 5c3a8e78f7b24c20b25b54ee575d6daa40007a5f4eea2845861c3409b3021747 || goto error
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" "https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip" 8adf9f5a4b6022aa2744f45c89ce347df46fea8403e99f01d650b11c417d0aa8 || goto error
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" "https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip" f93ff7ec6f2fcb9242256976a7e6d1da2588b5e57a559fb71a025b74bd1f5539 || goto error
call :downloadfile "lpng%LIBPNG%.zip" "https://download.sourceforge.net/libpng/lpng%LIBPNG%.zip" 7d7571a1faa1898b69888716dfdea0e4d466f1a5cf518e6aa626df2242bbadbe || goto error
call :downloadfile "libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/%LIBJPEGTURBO%/libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" 99130559e7d62e8d695f2c0eaeef912c5828d5b84a0537dcb24c9678c9d5b76b || goto error
call :downloadfile "SDL2-%SDL2%.zip" "https://github.com/libsdl-org/SDL/releases/download/release-%SDL2%/SDL2-%SDL2%.zip" ec855bcd815b4b63d0c958c42c2923311c656227d6e0c1ae1e721406d346444b || goto error
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" c3b41915341d853b6374cf93f1fcced2c8e4be9360f29c656960e1d0d15046a3 || goto error
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 809081a7bdf7e48262fbe9437e4e756df6ad2649433e803c4040026e650d7c91 || goto error
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" 89f1ef4595f68c3d34c63a7c1c4ce475e701e103f0473f3fd0718a2e5234de6e || goto error
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" 3f813f49d6d28c532dc4b104084f60ff382337f184698fcd6e70ab9efad977c1 || goto error
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" 91c33d9946279c9c613b02e52a33df610cc01d13ea6e321b4c4d8ee708b9a03e || goto error
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" e22d997bd15b795a176c8da62c8c1da0a674eb534e02f7c01ca507bf11bce0c3 || goto error
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 247a0a58039275a5a4fb499a600a90f66dc6e00321bb6f86a9b8d8020344d853 || goto error
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" 57bd332e5550ff70a852560c591b786b6ba587c5e41cb5ef91038d82db137ab9 || goto error
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" c65a89140f5d68137ffec67d631ec97002fb37077d9b4eb4ee45cbec39b1c38a || goto error
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" 30a8e7773e1f274557e049a97f158b808f344247da03ae5240e4956c81d51cd5 || goto error
call :downloadfile "libwebp-%WEBP%.tar.gz" "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-%WEBP%.tar.gz" 61f873ec69e3be1b99535634340d5bde750b2e4447caa1db9f61be3fd49ab1e5 || goto error
call :downloadfile "libzip-%LIBZIP%.tar.gz" "https://github.com/nih-at/libzip/releases/download/v%LIBZIP%/libzip-%LIBZIP%.tar.gz" c0e6fa52a62ba11efd30262290dc6970947aef32e0cc294ee50e9005ceac092a || goto error
call :downloadfile "libzip-%LIBZIP%.tar.gz" "https://github.com/nih-at/libzip/releases/download/v%LIBZIP%/libzip-%LIBZIP%.tar.gz" 6b2a43837005e1c23fdfee532b78f806863e412d2089b9c42b49ab08cbcd7665 || goto error
call :downloadfile "zlib%ZLIBSHORT%.zip" "https://zlib.net/zlib%ZLIBSHORT%.zip" 72af66d44fcc14c22013b46b814d5d2514673dda3d115e64b690c1ad636e7b17 || goto error
call :downloadfile "zstd-%ZSTD%.zip" "https://github.com/facebook/zstd/archive/refs/tags/v%ZSTD%.zip" 3b1c3b46e416d36931efd34663122d7f51b550c87f74de2d38249516fe7d8be5 || goto error
call :downloadfile "zstd-fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch" https://github.com/facebook/zstd/commit/fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch 675f144b11f8ab2424b64bed8ccdca5d3f35b9326046fa7a883925dd180f0651 || goto error
call :downloadfile "zstd-fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch" https://github.com/facebook/zstd/commit/fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch 8df152f4969b308546306c074628de761f0b80265de7de534e3822fab22d7535 || goto error
call :downloadfile "cpuinfo-%CPUINFO%.zip" "https://github.com/pytorch/cpuinfo/archive/%CPUINFO%.zip" 13146ae7983d767a678dd01b0d6af591e77cec82babd41264b9164ab808d7d41 || goto error
call :downloadfile "discord-rpc-%DISCORD_RPC%.zip" "https://github.com/stenzek/discord-rpc/archive/%DISCORD_RPC%.zip" 61e185e75d37b360c314125bcdf4697192d15e2d5209db3306ed6cd736d508b3 || goto error

View File

@ -44,14 +44,14 @@ set "PATH=%PATH%;%INSTALLDIR%\bin"
cd "%BUILDDIR%"
set FREETYPE=2.13.3
set HARFBUZZ=10.0.1
set HARFBUZZ=10.1.0
set LIBJPEGTURBO=3.0.4
set LIBPNG=1644
set QT=6.8.0
set QT=6.8.1
set QTMINOR=6.8
set SDL2=2.30.9
set WEBP=1.4.0
set LIBZIP=1.11.1
set LIBZIP=1.11.2
set ZLIB=1.3.1
set ZLIBSHORT=131
set ZSTD=1.5.6
@ -66,20 +66,20 @@ set DXCOMPILER=1.8.2407.12
set DXAGILITY=1.614.1
call :downloadfile "freetype-%FREETYPE%.tar.gz" "https://download.savannah.gnu.org/releases/freetype/freetype-%FREETYPE%.tar.gz" 5c3a8e78f7b24c20b25b54ee575d6daa40007a5f4eea2845861c3409b3021747 || goto error
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" "https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip" 8adf9f5a4b6022aa2744f45c89ce347df46fea8403e99f01d650b11c417d0aa8 || goto error
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" "https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip" f93ff7ec6f2fcb9242256976a7e6d1da2588b5e57a559fb71a025b74bd1f5539 || goto error
call :downloadfile "lpng%LIBPNG%.zip" "https://download.sourceforge.net/libpng/lpng%LIBPNG%.zip" 7d7571a1faa1898b69888716dfdea0e4d466f1a5cf518e6aa626df2242bbadbe || goto error
call :downloadfile "libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/%LIBJPEGTURBO%/libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" 99130559e7d62e8d695f2c0eaeef912c5828d5b84a0537dcb24c9678c9d5b76b || goto error
call :downloadfile "SDL2-%SDL2%.zip" "https://github.com/libsdl-org/SDL/releases/download/release-%SDL2%/SDL2-%SDL2%.zip" ec855bcd815b4b63d0c958c42c2923311c656227d6e0c1ae1e721406d346444b || goto error
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" c3b41915341d853b6374cf93f1fcced2c8e4be9360f29c656960e1d0d15046a3 || goto error
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 809081a7bdf7e48262fbe9437e4e756df6ad2649433e803c4040026e650d7c91 || goto error
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" 89f1ef4595f68c3d34c63a7c1c4ce475e701e103f0473f3fd0718a2e5234de6e || goto error
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" 3f813f49d6d28c532dc4b104084f60ff382337f184698fcd6e70ab9efad977c1 || goto error
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" 91c33d9946279c9c613b02e52a33df610cc01d13ea6e321b4c4d8ee708b9a03e || goto error
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" e22d997bd15b795a176c8da62c8c1da0a674eb534e02f7c01ca507bf11bce0c3 || goto error
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 247a0a58039275a5a4fb499a600a90f66dc6e00321bb6f86a9b8d8020344d853 || goto error
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" 57bd332e5550ff70a852560c591b786b6ba587c5e41cb5ef91038d82db137ab9 || goto error
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" c65a89140f5d68137ffec67d631ec97002fb37077d9b4eb4ee45cbec39b1c38a || goto error
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" 30a8e7773e1f274557e049a97f158b808f344247da03ae5240e4956c81d51cd5 || goto error
call :downloadfile "libwebp-%WEBP%.tar.gz" "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-%WEBP%.tar.gz" 61f873ec69e3be1b99535634340d5bde750b2e4447caa1db9f61be3fd49ab1e5 || goto error
call :downloadfile "libzip-%LIBZIP%.tar.gz" "https://github.com/nih-at/libzip/releases/download/v%LIBZIP%/libzip-%LIBZIP%.tar.gz" c0e6fa52a62ba11efd30262290dc6970947aef32e0cc294ee50e9005ceac092a || goto error
call :downloadfile "libzip-%LIBZIP%.tar.gz" "https://github.com/nih-at/libzip/releases/download/v%LIBZIP%/libzip-%LIBZIP%.tar.gz" 6b2a43837005e1c23fdfee532b78f806863e412d2089b9c42b49ab08cbcd7665 || goto error
call :downloadfile "zlib%ZLIBSHORT%.zip" "https://zlib.net/zlib%ZLIBSHORT%.zip" 72af66d44fcc14c22013b46b814d5d2514673dda3d115e64b690c1ad636e7b17 || goto error
call :downloadfile "zstd-%ZSTD%.zip" "https://github.com/facebook/zstd/archive/refs/tags/v%ZSTD%.zip" 3b1c3b46e416d36931efd34663122d7f51b550c87f74de2d38249516fe7d8be5 || goto error
call :downloadfile "zstd-fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch" https://github.com/facebook/zstd/commit/fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch 675f144b11f8ab2424b64bed8ccdca5d3f35b9326046fa7a883925dd180f0651 || goto error
call :downloadfile "zstd-fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch" https://github.com/facebook/zstd/commit/fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch 8df152f4969b308546306c074628de761f0b80265de7de534e3822fab22d7535 || goto error
call :downloadfile "cpuinfo-%CPUINFO%.zip" "https://github.com/pytorch/cpuinfo/archive/%CPUINFO%.zip" 13146ae7983d767a678dd01b0d6af591e77cec82babd41264b9164ab808d7d41 || goto error
call :downloadfile "discord-rpc-%DISCORD_RPC%.zip" "https://github.com/stenzek/discord-rpc/archive/%DISCORD_RPC%.zip" 61e185e75d37b360c314125bcdf4697192d15e2d5209db3306ed6cd736d508b3 || goto error

View File

@ -127,8 +127,8 @@ DEPLOY_PLATFORM_THEMES="1" \
QMAKE="$DEPSDIR/bin/qmake" \
NO_STRIP="1" \
$LINUXDEPLOY --plugin qt --appdir="$OUTDIR" --executable="$BUILDDIR/bin/duckstation-qt" ${EXTRA_LIBS_ARGS[@]} \
--desktop-file="$ROOTDIR/scripts/org.duckstation.DuckStation.desktop" \
--icon-file="$ROOTDIR/scripts/org.duckstation.DuckStation.png" \
--desktop-file="$ROOTDIR/scripts/packaging/org.duckstation.DuckStation.desktop" \
--icon-file="$ROOTDIR/scripts/packaging/org.duckstation.DuckStation.png" \
echo "Copying resources into AppDir..."
cp -a "$BUILDDIR/bin/resources" "$OUTDIR/usr/bin"

View File

@ -26,7 +26,7 @@ build-options:
sources:
- type: git
url: "https://github.com/nih-at/libzip.git"
commit: "9c8b818a1de143a4a8ee445351fb8f92115e33e1"
commit: "64b62d6b1a686a1b0bac1b6b9dcb635be0499afb"
cleanup:
- /bin
- /include

View File

@ -80,21 +80,21 @@ modules:
- "-DCMAKE_SHARED_LINKER_FLAGS_INIT=-fuse-ld=lld"
sources:
- type: dir
path: ../..
path: ../../..
post-install:
# Manually copy desktop file/metadata, it's not done as part of the regular build.
- >-
install -Dm644
"${FLATPAK_BUILDER_BUILDDIR}/scripts/org.duckstation.DuckStation.png"
"${FLATPAK_BUILDER_BUILDDIR}/scripts/packaging/org.duckstation.DuckStation.png"
"${FLATPAK_DEST}/share/icons/hicolor/512x512/apps/org.duckstation.DuckStation.png"
- >-
install -Dm644
"${FLATPAK_BUILDER_BUILDDIR}/scripts/org.duckstation.DuckStation.desktop"
"${FLATPAK_BUILDER_BUILDDIR}/scripts/packaging/org.duckstation.DuckStation.desktop"
"${FLATPAK_DEST}/share/applications/org.duckstation.DuckStation.desktop"
- >-
install -Dm644
"${FLATPAK_BUILDER_BUILDDIR}/scripts/flatpak/org.duckstation.DuckStation.metainfo.xml"
"${FLATPAK_BUILDER_BUILDDIR}/scripts/packaging/flatpak/org.duckstation.DuckStation.metainfo.xml"
"${FLATPAK_DEST}/share/metainfo/org.duckstation.DuckStation.metainfo.xml"
# Ensure ffmpeg-full mount point exists.

View File

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 47 KiB

View File

@ -4,6 +4,7 @@ add_executable(common-tests
gsvector_yuvtorgb_test.cpp
path_tests.cpp
rectangle_tests.cpp
sha256_tests.cpp
string_tests.cpp
)

View File

@ -7,6 +7,7 @@
<ClCompile Include="file_system_tests.cpp" />
<ClCompile Include="path_tests.cpp" />
<ClCompile Include="rectangle_tests.cpp" />
<ClCompile Include="sha256_tests.cpp" />
<ClCompile Include="string_tests.cpp" />
<ClCompile Include="gsvector_yuvtorgb_test.cpp" />
</ItemGroup>

View File

@ -8,5 +8,6 @@
<ClCompile Include="path_tests.cpp" />
<ClCompile Include="string_tests.cpp" />
<ClCompile Include="gsvector_yuvtorgb_test.cpp" />
<ClCompile Include="sha256_tests.cpp" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,34 @@
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
#include "common/sha256_digest.h"
#include <gtest/gtest.h>
TEST(SHA256Digest, Simple)
{
// https://github.com/B-Con/crypto-algorithms/blob/master/sha256_test.c
static constexpr const char text1[] = "abc";
static constexpr const char text2[] = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
static constexpr const char text3[] = "aaaaaaaaaa";
static constexpr SHA256Digest::Digest hash1 = {{0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40,
0xde, 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17,
0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad}};
static constexpr SHA256Digest::Digest hash2 = {{0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5, 0xc0, 0x26,
0x93, 0x0c, 0x3e, 0x60, 0x39, 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff,
0x21, 0x67, 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1}};
static constexpr SHA256Digest::Digest hash3 = {{0xcd, 0xc7, 0x6e, 0x5c, 0x99, 0x14, 0xfb, 0x92, 0x81, 0xa1, 0xc7,
0xe2, 0x84, 0xd7, 0x3e, 0x67, 0xf1, 0x80, 0x9a, 0x48, 0xa4, 0x97,
0x20, 0x0e, 0x04, 0x6d, 0x39, 0xcc, 0xc7, 0x11, 0x2c, 0xd0}};
ASSERT_EQ(SHA256Digest::GetDigest(text1, std::size(text1) - 1), hash1);
ASSERT_EQ(SHA256Digest::GetDigest(text2, std::size(text2) - 1), hash2);
SHA256Digest ldigest;
for (u32 i = 0; i < 100000; i++)
ldigest.Update(text3, std::size(text3) - 1);
ASSERT_EQ(ldigest.Final(), hash3);
}

View File

@ -33,3 +33,41 @@ TEST(StringUtil, EllipsiseInPlace)
StringUtil::EllipsiseInPlace(s, 10, "...");
ASSERT_EQ(s, "Hello");
}
TEST(StringUtil, Base64EncodeDecode)
{
struct TestCase
{
const char* hexString;
const char* base64String;
};
static const TestCase testCases[] = {
{"33326a6f646933326a68663937683732383368", "MzJqb2RpMzJqaGY5N2g3MjgzaA=="},
{"32753965333268756979386672677537366967723839683432703075693132393065755c5d0931325c335c31323439303438753839333272",
"MnU5ZTMyaHVpeThmcmd1NzZpZ3I4OWg0MnAwdWkxMjkwZXVcXQkxMlwzXDEyNDkwNDh1ODkzMnI="},
{"3332726a33323738676838666233326830393233386637683938323139", "MzJyajMyNzhnaDhmYjMyaDA5MjM4ZjdoOTgyMTk="},
{"9956967BE9C96E10B27FF8897A5B768A2F4B103CE934718D020FE6B5B770", "mVaWe+nJbhCyf/iJelt2ii9LEDzpNHGNAg/mtbdw"},
{"BC94251814827A5D503D62D5EE6CBAB0FD55D2E2FCEDBB2261D6010084B95DD648766D8983F03AFA3908956D8201E26BB09FE52B515A61A9E"
"1D3ADC207BD9E622128F22929CDED456B595A410F7168B0BA6370289E6291E38E47C18278561C79A7297C21D23C06BB2F694DC2F65FAAF994"
"59E3FC14B1FA415A3320AF00ACE54C00BE",
"vJQlGBSCel1QPWLV7my6sP1V0uL87bsiYdYBAIS5XdZIdm2Jg/A6+jkIlW2CAeJrsJ/"
"lK1FaYanh063CB72eYiEo8ikpze1Fa1laQQ9xaLC6Y3AonmKR445HwYJ4Vhx5pyl8IdI8BrsvaU3C9l+q+ZRZ4/wUsfpBWjMgrwCs5UwAvg=="},
{"192B42CB0F66F69BE8A5", "GStCyw9m9pvopQ=="},
{"38ABD400F3BB6960EB60C056719B5362", "OKvUAPO7aWDrYMBWcZtTYg=="},
{"776FAB27DC7F8DA86F298D55B69F8C278D53871F8CBCCF", "d2+rJ9x/jahvKY1Vtp+MJ41Thx+MvM8="},
{"B1ED3EA2E35EE69C7E16707B05042A", "se0+ouNe5px+FnB7BQQq"},
};
for (const TestCase& tc : testCases)
{
std::optional<std::vector<u8>> bytes = StringUtil::DecodeHex(tc.hexString);
ASSERT_TRUE(bytes.has_value());
std::string encoded_b64 = StringUtil::EncodeBase64(bytes.value());
ASSERT_EQ(encoded_b64, tc.base64String);
std::optional<std::vector<u8>> dbytes = StringUtil::DecodeBase64(tc.base64String);
ASSERT_TRUE(dbytes.has_value());
ASSERT_EQ(dbytes.value(), bytes.value());
}
}

View File

@ -50,12 +50,16 @@ add_library(common
settings_interface.h
sha1_digest.cpp
sha1_digest.h
sha256_digest.cpp
sha256_digest.h
small_string.cpp
small_string.h
string_util.cpp
string_util.h
thirdparty/SmallVector.cpp
thirdparty/SmallVector.h
thirdparty/aes.cpp
thirdparty/aes.h
threading.cpp
threading.h
timer.cpp

View File

@ -19,7 +19,7 @@ void Y_OnAssertFailed(const char* szMessage, const char* szFunction, const char*
Y_OnAssertFailed("Assertion failed: '" msg "'", __FUNCTION__, __FILE__, __LINE__); \
}
#ifdef _DEBUG
#if defined(_DEBUG) || defined(_DEVEL)
#define DebugAssert(expr) \
if (!(expr)) \
{ \
@ -41,7 +41,7 @@ void Y_OnAssertFailed(const char* szMessage, const char* szFunction, const char*
// Kills the application, indicating a pure function call that should not have happened.
#define PureCall() Y_OnPanicReached("PureCall encountered", __FUNCTION__, __FILE__, __LINE__)
#ifdef _DEBUG
#if defined(_DEBUG) || defined(_DEVEL)
// Kills the application, indicating that code that was never supposed to be reached has been executed.
#define UnreachableCode() Y_OnPanicReached("Unreachable code reached", __FUNCTION__, __FILE__, __LINE__)
#else

View File

@ -36,10 +36,12 @@
<ClInclude Include="scoped_guard.h" />
<ClInclude Include="settings_interface.h" />
<ClInclude Include="sha1_digest.h" />
<ClInclude Include="sha256_digest.h" />
<ClInclude Include="small_string.h" />
<ClInclude Include="heterogeneous_containers.h" />
<ClInclude Include="binary_reader_writer.h" />
<ClInclude Include="string_util.h" />
<ClInclude Include="thirdparty\aes.h" />
<ClInclude Include="thirdparty\SmallVector.h" />
<ClInclude Include="thirdparty\StackWalker.h" />
<ClInclude Include="threading.h" />
@ -64,9 +66,11 @@
<ClCompile Include="perf_scope.cpp" />
<ClCompile Include="progress_callback.cpp" />
<ClCompile Include="sha1_digest.cpp" />
<ClCompile Include="sha256_digest.cpp" />
<ClCompile Include="small_string.cpp" />
<ClCompile Include="binary_reader_writer.cpp" />
<ClCompile Include="string_util.cpp" />
<ClCompile Include="thirdparty\aes.cpp" />
<ClCompile Include="thirdparty\SmallVector.cpp" />
<ClCompile Include="thirdparty\StackWalker.cpp" />
<ClCompile Include="threading.cpp" />

View File

@ -50,6 +50,8 @@
<ClInclude Include="gsvector_nosimd.h" />
<ClInclude Include="ryml_helpers.h" />
<ClInclude Include="log_channels.h" />
<ClInclude Include="sha256_digest.h" />
<ClInclude Include="thirdparty\aes.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="small_string.cpp" />
@ -78,6 +80,8 @@
<ClCompile Include="dynamic_library.cpp" />
<ClCompile Include="binary_reader_writer.cpp" />
<ClCompile Include="gsvector.cpp" />
<ClCompile Include="sha256_digest.cpp" />
<ClCompile Include="thirdparty\aes.cpp" />
</ItemGroup>
<ItemGroup>
<Natvis Include="bitfield.natvis" />

View File

@ -16,6 +16,7 @@
#include <cstring>
#include <limits>
#include <numeric>
#include <utility>
#ifdef __APPLE__
#include <mach-o/dyld.h>
@ -923,7 +924,7 @@ std::FILE* FileSystem::OpenExistingOrCreateCFile(const char* path, s32 retry_ms,
// if there's a sharing violation, keep retrying
if (file == INVALID_HANDLE_VALUE && GetLastError() == ERROR_SHARING_VIOLATION && retry_ms >= 0)
{
Common::Timer timer;
Timer timer;
while (retry_ms == 0 || timer.GetTimeMilliseconds() <= retry_ms)
{
Sleep(1);
@ -2787,19 +2788,25 @@ bool FileSystem::SetPathCompression(const char* path, bool enable)
return false;
}
static bool SetLock(int fd, bool lock)
static bool SetLock(int fd, bool lock, bool block, Error* error)
{
// We want to lock the whole file.
const off_t offs = lseek(fd, 0, SEEK_CUR);
if (offs < 0)
{
ERROR_LOG("lseek({}) failed: {}", fd, errno);
if (error)
error->SetErrno("lseek() failed: ", errno);
else
ERROR_LOG("lseek({}) failed: {}", fd, errno);
return false;
}
if (offs != 0 && lseek(fd, 0, SEEK_SET) < 0)
{
ERROR_LOG("lseek({}, 0) failed: {}", fd, errno);
if (error)
error->SetErrno("lseek(0) failed: ", errno);
else
ERROR_LOG("lseek({}, 0) failed: {}", fd, errno);
return false;
}
@ -2807,38 +2814,66 @@ static bool SetLock(int fd, bool lock)
bool res;
for (;;)
{
res = (lockf(fd, lock ? F_LOCK : F_ULOCK, 0) == 0);
res = (lockf(fd, lock ? (block ? F_TLOCK : F_LOCK) : F_ULOCK, 0) == 0);
if (!res && errno == EINTR)
continue;
else
break;
}
if (!res)
{
if (error)
error->SetErrno("lockf() failed: ", errno);
else
ERROR_LOG("lockf() for {} failed: {}", lock ? "lock" : "unlock", errno);
}
if (lseek(fd, offs, SEEK_SET) < 0)
Panic("Repositioning file descriptor after lock failed.");
if (!res)
ERROR_LOG("lockf() for {} failed: {}", lock ? "lock" : "unlock", errno);
return res;
}
FileSystem::POSIXLock::POSIXLock(int fd) : m_fd(fd)
FileSystem::POSIXLock::POSIXLock() : m_fd(-1)
{
if (!SetLock(m_fd, true))
}
FileSystem::POSIXLock::POSIXLock(int fd, bool block, Error* error) : m_fd(fd)
{
if (!SetLock(m_fd, true, block, error))
m_fd = -1;
}
FileSystem::POSIXLock::POSIXLock(std::FILE* fp) : m_fd(fileno(fp))
FileSystem::POSIXLock::POSIXLock(std::FILE* fp, bool block, Error* error) : m_fd(fileno(fp))
{
if (!SetLock(m_fd, true))
if (!SetLock(m_fd, true, block, error))
m_fd = -1;
}
FileSystem::POSIXLock::POSIXLock(POSIXLock&& move)
{
m_fd = std::exchange(move.m_fd, -1);
}
FileSystem::POSIXLock::~POSIXLock()
{
Unlock();
}
void FileSystem::POSIXLock::Unlock()
{
if (m_fd >= 0)
SetLock(m_fd, false);
{
SetLock(m_fd, false, true, nullptr);
m_fd = -1;
}
}
FileSystem::POSIXLock& FileSystem::POSIXLock::operator=(POSIXLock&& move)
{
m_fd = std::exchange(move.m_fd, -1);
return *this;
}
#endif

View File

@ -159,10 +159,19 @@ void DiscardAtomicRenamedFile(AtomicRenamedFile& file);
class POSIXLock
{
public:
POSIXLock(int fd);
POSIXLock(std::FILE* fp);
POSIXLock();
POSIXLock(int fd, bool block = true, Error* error = nullptr);
POSIXLock(std::FILE* fp, bool block = true, Error* error = nullptr);
POSIXLock(POSIXLock&& move);
POSIXLock(const POSIXLock&) = delete;
~POSIXLock();
POSIXLock& operator=(POSIXLock&& move);
POSIXLock& operator=(const POSIXLock&) = delete;
ALWAYS_INLINE bool IsLocked() const { return (m_fd >= 0); }
void Unlock();
private:
int m_fd;
};

View File

@ -81,7 +81,7 @@ struct State
std::vector<RegisteredCallback> callbacks;
std::mutex callbacks_mutex;
Common::Timer::Value start_timestamp = Common::Timer::GetCurrentValue();
Timer::Value start_timestamp = Timer::GetCurrentValue();
FileSystem::ManagedCFilePtr file_handle;
@ -146,8 +146,7 @@ const std::array<const char*, static_cast<size_t>(Log::Channel::MaxCount)>& Log:
float Log::GetCurrentMessageTime()
{
return static_cast<float>(
Common::Timer::ConvertValueToSeconds(Common::Timer::GetCurrentValue() - s_state.start_timestamp));
return static_cast<float>(Timer::ConvertValueToSeconds(Timer::GetCurrentValue() - s_state.start_timestamp));
}
bool Log::AreTimestampsEnabled()
@ -377,7 +376,7 @@ void Log::DebugOutputLogCallback(void* pUserParam, MessageCategory cat, const ch
if (message.empty())
return;
static constexpr int logPriority[static_cast<size_t>(Level::Count)] = {
static constexpr int logPriority[static_cast<size_t>(Level::MaxCount)] = {
ANDROID_LOG_INFO, // None
ANDROID_LOG_ERROR, // Error
ANDROID_LOG_WARN, // Warning

View File

@ -195,7 +195,7 @@ ALWAYS_INLINE static void FastWrite(Channel channel, const char* functionName, L
#define VERBOSE_LOG(...) Log::FastWrite(___LogChannel___, Log::Level::Verbose, __VA_ARGS__)
#define DEV_LOG(...) Log::FastWrite(___LogChannel___, Log::Level::Dev, __VA_ARGS__)
#ifdef _DEBUG
#if defined(_DEBUG) || defined(_DEVEL)
#define DEBUG_LOG(...) Log::FastWrite(___LogChannel___, Log::Level::Debug, __VA_ARGS__)
#define TRACE_LOG(...) Log::FastWrite(___LogChannel___, Log::Level::Trace, __VA_ARGS__)
#else
@ -216,7 +216,7 @@ ALWAYS_INLINE static void FastWrite(Channel channel, const char* functionName, L
#define VERBOSE_COLOR_LOG(colour, ...) Log::FastWrite(___LogChannel___, Log::Level::Verbose, Log::Color::colour, __VA_ARGS__)
#define DEV_COLOR_LOG(colour, ...) Log::FastWrite(___LogChannel___, Log::Level::Dev, Log::Color::colour, __VA_ARGS__)
#ifdef _DEBUG
#if defined(_DEBUG) || defined(_DEVEL)
#define DEBUG_COLOR_LOG(colour, ...) Log::FastWrite(___LogChannel___, Log::Level::Debug, Log::Color::colour, __VA_ARGS__)
#define TRACE_COLOR_LOG(colour, ...) Log::FastWrite(___LogChannel___, Log::Level::Trace, Log::Color::colour,__VA_ARGS__)
#else

View File

@ -3,8 +3,6 @@
#define ENUMERATE_LOG_CHANNELS(X) \
X(Achievements) \
X(AnalogController) \
X(AnalogJoystick) \
X(AudioStream) \
X(AutoUpdaterDialog) \
X(BIOS) \
@ -16,7 +14,7 @@
X(Cheats) \
X(CodeCache) \
X(CompressHelpers) \
X(ControllerBindingWidget) \
X(Controller) \
X(CubebAudioStream) \
X(CueParser) \
X(DInputSource) \
@ -27,17 +25,12 @@
X(FullscreenUI) \
X(GDBProtocol) \
X(GPU) \
X(GPUBackend) \
X(GPUDevice) \
X(GPUDump) \
X(GPUShaderCache) \
X(GPUTextureCache) \
X(GPU_HW) \
X(GPU_SW) \
X(GPU_SW_Rasterizer) \
X(GPU_HW) \
X(GameDatabase) \
X(GameList) \
X(GunCon) \
X(HTTPDownloader) \
X(Host) \
X(ImGuiFullscreen) \
@ -45,19 +38,16 @@
X(Image) \
X(InputManager) \
X(InterruptController) \
X(Justifier) \
X(Log) \
X(MDEC) \
X(MediaCapture) \
X(MemMap) \
X(MemoryCard) \
X(Multitap) \
X(NeGconRumble) \
X(PCDrv) \
X(Pad) \
X(PerfMon) \
X(PlatformMisc) \
X(PlayStationMouse) \
X(PostProcessing) \
X(ProgressCallback) \
X(ReShadeFXShader) \

View File

@ -3,6 +3,7 @@
#include "sha1_digest.h"
#include "assert.h"
#include "string_util.h"
#include <cstring>
@ -162,22 +163,7 @@ void SHA1Digest::Reset()
std::string SHA1Digest::DigestToString(const std::span<const u8, DIGEST_SIZE> digest)
{
std::string ret;
ret.reserve(DIGEST_SIZE * 2);
for (u32 i = 0; i < DIGEST_SIZE; i++)
{
u8 nibble = digest[i] >> 4;
if (nibble >= 0xA)
ret.push_back('A' + (nibble - 0xA));
else
ret.push_back('0' + nibble);
nibble = digest[i] & 0xF;
if (nibble >= 0xA)
ret.push_back('A' + (nibble - 0xA));
else
ret.push_back('0' + nibble);
}
return ret;
return StringUtil::EncodeHex<u8>(digest);
}
std::array<u8, SHA1Digest::DIGEST_SIZE> SHA1Digest::GetDigest(const void* data, size_t len)

View File

@ -0,0 +1,193 @@
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
// Based on https://github.com/B-Con/crypto-algorithms/blob/master/sha256.c
// By Brad Conte (brad AT bradconte.com)
#include "sha256_digest.h"
#include "string_util.h"
#include <cstring>
SHA256Digest::SHA256Digest()
{
Reset();
}
std::string SHA256Digest::DigestToString(const std::span<const u8, DIGEST_SIZE> digest)
{
return StringUtil::EncodeHex<u8>(digest);
}
SHA256Digest::Digest SHA256Digest::GetDigest(const void* data, size_t len)
{
Digest ret;
SHA256Digest digest;
digest.Update(data, len);
digest.Final(ret);
return ret;
}
SHA256Digest::Digest SHA256Digest::GetDigest(std::span<const u8> data)
{
Digest ret;
SHA256Digest digest;
digest.Update(data);
digest.Final(ret);
return ret;
}
#define ROTLEFT(a, b) (((a) << (b)) | ((a) >> (32 - (b))))
#define ROTRIGHT(a, b) (((a) >> (b)) | ((a) << (32 - (b))))
#define CH(x, y, z) (((x) & (y)) ^ (~(x) & (z)))
#define MAJ(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
#define EP0(x) (ROTRIGHT(x, 2) ^ ROTRIGHT(x, 13) ^ ROTRIGHT(x, 22))
#define EP1(x) (ROTRIGHT(x, 6) ^ ROTRIGHT(x, 11) ^ ROTRIGHT(x, 25))
#define SIG0(x) (ROTRIGHT(x, 7) ^ ROTRIGHT(x, 18) ^ ((x) >> 3))
#define SIG1(x) (ROTRIGHT(x, 17) ^ ROTRIGHT(x, 19) ^ ((x) >> 10))
static constexpr std::array<u32, 64> k = {
{0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2}};
void SHA256Digest::TransformBlock()
{
std::array<u32, 64> m;
size_t i = 0;
for (size_t j = 0; i < 16; ++i, j += 4)
m[i] = (m_block[j] << 24) | (m_block[j + 1] << 16) | (m_block[j + 2] << 8) | (m_block[j + 3]);
for (; i < 64; ++i)
m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16];
u32 a = m_state[0];
u32 b = m_state[1];
u32 c = m_state[2];
u32 d = m_state[3];
u32 e = m_state[4];
u32 f = m_state[5];
u32 g = m_state[6];
u32 h = m_state[7];
for (i = 0; i < 64; ++i)
{
u32 t1 = h + EP1(e) + CH(e, f, g) + k[i] + m[i];
u32 t2 = EP0(a) + MAJ(a, b, c);
h = g;
g = f;
f = e;
e = d + t1;
d = c;
c = b;
b = a;
a = t1 + t2;
}
m_state[0] += a;
m_state[1] += b;
m_state[2] += c;
m_state[3] += d;
m_state[4] += e;
m_state[5] += f;
m_state[6] += g;
m_state[7] += h;
}
void SHA256Digest::Reset()
{
m_block_length = 0;
m_bit_length = 0;
m_state[0] = 0x6a09e667;
m_state[1] = 0xbb67ae85;
m_state[2] = 0x3c6ef372;
m_state[3] = 0xa54ff53a;
m_state[4] = 0x510e527f;
m_state[5] = 0x9b05688c;
m_state[6] = 0x1f83d9ab;
m_state[7] = 0x5be0cd19;
}
void SHA256Digest::Update(std::span<const u8> data)
{
const size_t len = data.size();
for (size_t pos = 0; pos < len;)
{
const u32 copy_len = static_cast<u32>(std::min<size_t>(len - pos, BLOCK_SIZE - m_block_length));
std::memcpy(&m_block[m_block_length], &data[pos], copy_len);
m_block_length += copy_len;
pos += copy_len;
if (m_block_length == BLOCK_SIZE)
{
TransformBlock();
m_bit_length += 512;
m_block_length = 0;
}
}
}
void SHA256Digest::Update(const void* data, size_t len)
{
Update(std::span<const u8>(static_cast<const u8*>(data), len));
}
void SHA256Digest::Final(std::span<u8, DIGEST_SIZE> digest)
{
// Pad whatever data is left in the buffer.
if (m_block_length < 56)
{
size_t i = m_block_length;
m_block[i++] = 0x80;
while (i < 56)
m_block[i++] = 0x00;
}
else
{
size_t i = m_block_length;
m_block[i++] = 0x80;
while (i < 64)
m_block[i++] = 0x00;
TransformBlock();
m_block = {};
}
// Append to the padding the total message's length in bits and transform.
m_bit_length += m_block_length * 8;
m_block[63] = static_cast<u8>(m_bit_length);
m_block[62] = static_cast<u8>(m_bit_length >> 8);
m_block[61] = static_cast<u8>(m_bit_length >> 16);
m_block[60] = static_cast<u8>(m_bit_length >> 24);
m_block[59] = static_cast<u8>(m_bit_length >> 32);
m_block[58] = static_cast<u8>(m_bit_length >> 40);
m_block[57] = static_cast<u8>(m_bit_length >> 48);
m_block[56] = static_cast<u8>(m_bit_length >> 56);
TransformBlock();
// Since this implementation uses little endian byte ordering and SHA uses big endian,
// reverse all the bytes when copying the final state to the output hash.
for (size_t i = 0; i < 4; ++i)
{
digest[i] = (m_state[0] >> (24 - i * 8)) & 0x000000ff;
digest[i + 4] = (m_state[1] >> (24 - i * 8)) & 0x000000ff;
digest[i + 8] = (m_state[2] >> (24 - i * 8)) & 0x000000ff;
digest[i + 12] = (m_state[3] >> (24 - i * 8)) & 0x000000ff;
digest[i + 16] = (m_state[4] >> (24 - i * 8)) & 0x000000ff;
digest[i + 20] = (m_state[5] >> (24 - i * 8)) & 0x000000ff;
digest[i + 24] = (m_state[6] >> (24 - i * 8)) & 0x000000ff;
digest[i + 28] = (m_state[7] >> (24 - i * 8)) & 0x000000ff;
}
}
SHA256Digest::Digest SHA256Digest::Final()
{
Digest ret;
Final(ret);
return ret;
}

View File

@ -0,0 +1,43 @@
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
#pragma once
#include "types.h"
#include <array>
#include <span>
#include <string>
class SHA256Digest
{
public:
enum : u32
{
DIGEST_SIZE = 32,
BLOCK_SIZE = 64,
};
using Digest = std::array<u8, DIGEST_SIZE>;
SHA256Digest();
void Update(const void* data, size_t len);
void Update(std::span<const u8> data);
void Final(std::span<u8, DIGEST_SIZE> digest);
Digest Final();
void Reset();
static std::string DigestToString(const std::span<const u8, DIGEST_SIZE> digest);
static Digest GetDigest(const void* data, size_t len);
static Digest GetDigest(std::span<const u8> data);
private:
void TransformBlock();
u64 m_bit_length = 0;
std::array<u32, 8> m_state = {};
u32 m_block_length = 0;
std::array<u8, BLOCK_SIZE> m_block = {};
};

View File

@ -506,6 +506,26 @@ std::wstring SmallStringBase::wstring() const
#endif
std::span<const char> SmallStringBase::cspan() const
{
return std::span<const char>(m_buffer, m_length);
}
std::span<char> SmallStringBase::span()
{
return std::span<char>(m_buffer, m_length);
}
std::span<const u8> SmallStringBase::cbspan() const
{
return std::span<const u8>(reinterpret_cast<const u8*>(m_buffer), m_length);
}
std::span<u8> SmallStringBase::bspan()
{
return std::span<u8>(reinterpret_cast<u8*>(m_buffer), m_length);
}
void SmallStringBase::vformat(fmt::string_view fmt, fmt::format_args args)
{
clear();

View File

@ -12,6 +12,7 @@
#include <cstring>
#include <iterator>
#include <limits>
#include <span>
#include <string>
#include <string_view>
@ -207,10 +208,18 @@ public:
std::wstring wstring() const;
#endif
// span creators
std::span<const char> cspan() const;
std::span<char> span();
std::span<const u8> cbspan() const;
std::span<u8> bspan();
// accessor operators
ALWAYS_INLINE operator const char*() const { return c_str(); }
ALWAYS_INLINE operator char*() { return data(); }
ALWAYS_INLINE operator std::string_view() const { return view(); }
ALWAYS_INLINE operator std::span<const char>() const { return cspan(); }
ALWAYS_INLINE operator std::span<char>() { return span(); }
// comparative operators
ALWAYS_INLINE bool operator==(const char* str) const { return equals(str); }

View File

@ -197,6 +197,107 @@ std::string StringUtil::EncodeHex(const void* data, size_t length)
return ret;
}
size_t StringUtil::EncodeBase64(const std::span<char> dest, const std::span<const u8> data)
{
const size_t expected_length = EncodedBase64Length(data);
Assert(dest.size() <= expected_length);
static constexpr std::array<char, 64> table = {
{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'}};
const size_t dataLength = data.size();
size_t dest_pos = 0;
for (size_t i = 0; i < dataLength;)
{
const size_t bytes_in_sequence = std::min<size_t>(dataLength - i, 3);
switch (bytes_in_sequence)
{
case 1:
dest[dest_pos++] = table[(data[i] >> 2) & 63];
dest[dest_pos++] = table[(data[i] & 3) << 4];
dest[dest_pos++] = '=';
dest[dest_pos++] = '=';
break;
case 2:
dest[dest_pos++] = table[(data[i] >> 2) & 63];
dest[dest_pos++] = table[((data[i] & 3) << 4) | ((data[i + 1] >> 4) & 15)];
dest[dest_pos++] = table[(data[i + 1] & 15) << 2];
dest[dest_pos++] = '=';
break;
case 3:
dest[dest_pos++] = table[(data[i] >> 2) & 63];
dest[dest_pos++] = table[((data[i] & 3) << 4) | ((data[i + 1] >> 4) & 15)];
dest[dest_pos++] = table[((data[i + 1] & 15) << 2) | ((data[i + 2] >> 6) & 3)];
dest[dest_pos++] = table[data[i + 2] & 63];
break;
DefaultCaseIsUnreachable();
}
i += bytes_in_sequence;
}
DebugAssert(dest_pos == expected_length);
return dest_pos;
}
size_t StringUtil::DecodeBase64(const std::span<u8> data, const std::string_view str)
{
static constexpr std::array<u8, 128> table = {
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63, 52, 53, 54, 55,
56, 57, 58, 59, 60, 61, 64, 64, 64, 0, 64, 64, 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64, 64, 26, 27, 28, 29, 30, 31, 32,
33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64};
const size_t str_length = str.length();
if ((str_length % 4) != 0)
return 0;
size_t data_pos = 0;
for (size_t i = 0; i < str_length;)
{
const u8 byte1 = table[str[i++] & 0x7F];
const u8 byte2 = table[str[i++] & 0x7F];
const u8 byte3 = table[str[i++] & 0x7F];
const u8 byte4 = table[str[i++] & 0x7F];
if (byte1 == 64 || byte2 == 64 || byte3 == 64 || byte4 == 64)
break;
data[data_pos++] = (byte1 << 2) | (byte2 >> 4);
if (str[i - 2] != '=')
data[data_pos++] = ((byte2 << 4) | (byte3 >> 2));
if (str[i - 1] != '=')
data[data_pos++] = ((byte3 << 6) | byte4);
}
return data_pos;
}
std::optional<std::vector<u8>> StringUtil::DecodeBase64(const std::string_view str)
{
std::vector<u8> ret;
const size_t len = DecodedBase64Length(str);
ret.resize(len);
if (DecodeBase64(ret, str) != len)
ret = {};
return ret;
}
std::string StringUtil::EncodeBase64(const std::span<u8> data)
{
std::string ret;
ret.resize(EncodedBase64Length(data));
ret.resize(EncodeBase64(ret, data));
return ret;
}
std::string_view StringUtil::StripWhitespace(const std::string_view str)
{
std::string_view::size_type start = 0;

View File

@ -4,6 +4,7 @@
#pragma once
#include "types.h"
#include <array>
#include <charconv>
#include <cstddef>
#include <cstring>
@ -22,9 +23,6 @@
#if !defined(_MSC_VER)
#include <locale>
#include <sstream>
#ifdef __APPLE__
#include <Availability.h>
#endif
#endif
namespace StringUtil {
@ -175,8 +173,6 @@ inline std::optional<T> FromChars(const std::string_view str, std::string_view*
template<typename T, std::enable_if_t<std::is_integral<T>::value, bool> = true>
inline std::string ToChars(T value, int base = 10)
{
// to_chars() requires macOS 10.15+.
#if !defined(__APPLE__) || MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_15
constexpr size_t MAX_SIZE = 32;
char buf[MAX_SIZE];
std::string ret;
@ -186,12 +182,6 @@ inline std::string ToChars(T value, int base = 10)
ret.append(buf, result.ptr - buf);
return ret;
#else
std::ostringstream ss;
ss.imbue(std::locale::classic());
ss << std::setbase(base) << value;
return ss.str();
#endif
}
template<typename T, std::enable_if_t<std::is_floating_point<T>::value, bool> = true>
@ -260,6 +250,54 @@ ALWAYS_INLINE static bool IsHexDigit(T ch)
(ch >= static_cast<T>('0') && ch <= static_cast<T>('9')));
}
/// Returns a byte array from the provided hex string, computed at compile-time.
template<size_t Length>
static constexpr std::array<u8, Length> ParseFixedHexString(const char str[])
{
std::array<u8, Length> h{};
for (int i = 0; str[i] != '\0'; i++)
{
u8 nibble = 0;
char ch = str[i];
if (ch >= '0' && ch <= '9')
nibble = str[i] - '0';
else if (ch >= 'a' && ch <= 'z')
nibble = 0xA + (str[i] - 'a');
else if (ch >= 'A' && ch <= 'Z')
nibble = 0xA + (str[i] - 'A');
h[i / 2] |= nibble << (((i & 1) ^ 1) * 4);
}
return h;
}
/// Encode/decode Base64 buffers.
static constexpr size_t DecodedBase64Length(const std::string_view str)
{
// Should be a multiple of 4.
const size_t str_length = str.length();
if ((str_length % 4) != 0)
return 0;
// Reverse padding.
size_t padding = 0;
if (str.length() >= 2)
{
padding += static_cast<size_t>(str[str_length - 1] == '=');
padding += static_cast<size_t>(str[str_length - 2] == '=');
}
return (str_length / 4) * 3 - padding;
}
static constexpr size_t EncodedBase64Length(const std::span<const u8> data)
{
return ((data.size() + 2) / 3) * 4;
}
size_t DecodeBase64(const std::span<u8> data, const std::string_view str);
size_t EncodeBase64(const std::span<char> dest, const std::span<const u8> data);
std::string EncodeBase64(const std::span<u8> data);
std::optional<std::vector<u8>> DecodeBase64(const std::string_view str);
/// StartsWith/EndsWith variants which aren't case sensitive.
ALWAYS_INLINE static bool StartsWithNoCase(const std::string_view str, const std::string_view prefix)
{

View File

@ -183,7 +183,7 @@ protected:
/// NewSize.
bool isSafeToReferenceAfterResize(const void *Elt, size_t NewSize) {
// Past the end.
if (LLVM_LIKELY(!isReferenceToStorage(Elt)))
if (!isReferenceToStorage(Elt)) [[likely]]
return true;
// Return false if Elt will be destroyed by shrinking.
@ -946,7 +946,7 @@ public:
}
template <typename... ArgTypes> reference emplace_back(ArgTypes &&... Args) {
if (LLVM_UNLIKELY(this->size() >= this->capacity()))
if (this->size() >= this->capacity()) [[unlikely]]
return this->growAndEmplaceBack(std::forward<ArgTypes>(Args)...);
::new ((void *)this->end()) T(std::forward<ArgTypes>(Args)...);

1173
src/common/thirdparty/aes.cpp vendored Normal file

File diff suppressed because it is too large Load Diff

122
src/common/thirdparty/aes.h vendored Normal file
View File

@ -0,0 +1,122 @@
/*********************************************************************
* Filename: aes.h
* Author: Brad Conte (brad AT bradconte.com)
* Copyright:
* Disclaimer: This code is presented "as is" without any guarantees.
* Details: Defines the API for the corresponding AES implementation.
*********************************************************************/
#pragma once
/*************************** HEADER FILES ***************************/
#include <cstddef>
#include <cstdint>
/****************************** MACROS ******************************/
static constexpr uint32_t AES_BLOCK_SIZE = 16; // AES operates on 16 bytes at a time
static constexpr uint32_t AES_KEY_SCHEDULE_SIZE = 60;
/*********************** FUNCTION DECLARATIONS **********************/
///////////////////
// AES
///////////////////
// Key setup must be done before any AES en/de-cryption functions can be used.
void aes_key_setup(const uint8_t key[], // The key, must be 128, 192, or 256 bits
uint32_t w[], // Output key schedule to be used later
int keysize); // Bit length of the key, 128, 192, or 256
void aes_encrypt(const uint8_t in[], // 16 bytes of plaintext
uint8_t out[], // 16 bytes of ciphertext
const uint32_t key[], // From the key setup
int keysize); // Bit length of the key, 128, 192, or 256
void aes_decrypt(const uint8_t in[], // 16 bytes of ciphertext
uint8_t out[], // 16 bytes of plaintext
const uint32_t key[], // From the key setup
int keysize); // Bit length of the key, 128, 192, or 256
///////////////////
// AES - CBC
///////////////////
bool aes_encrypt_cbc(const uint8_t in[], // Plaintext
size_t in_len, // Must be a multiple of AES_BLOCK_SIZE
uint8_t out[], // Ciphertext, same length as plaintext
const uint32_t key[], // From the key setup
int keysize, // Bit length of the key, 128, 192, or 256
const uint8_t iv[]); // IV, must be AES_BLOCK_SIZE bytes long
bool aes_decrypt_cbc(const uint8_t in[], // Ciphertext
size_t in_len, // Must be a multiple of AES_BLOCK_SIZE
uint8_t out[], // Plaintext, same length as ciphertext
const uint32_t key[], // From the key setup
int keysize, // Bit length of the key, 128, 192, or 256
const uint8_t iv[]); // IV, must be AES_BLOCK_SIZE bytes long
#if 0
// Disabled since it's not being used.
// Only output the CBC-MAC of the input.
bool aes_encrypt_cbc_mac(const uint8_t in[], // plaintext
size_t in_len, // Must be a multiple of AES_BLOCK_SIZE
uint8_t out[], // Output MAC
const uint32_t key[], // From the key setup
int keysize, // Bit length of the key, 128, 192, or 256
const uint8_t iv[]); // IV, must be AES_BLOCK_SIZE bytes long
///////////////////
// AES - CTR
///////////////////
void aes_increment_iv(uint8_t iv[], // Must be a multiple of AES_BLOCK_SIZE
int counter_size); // Bytes of the IV used for counting (low end)
void aes_encrypt_ctr(const uint8_t in[], // Plaintext
size_t in_len, // Any byte length
uint8_t out[], // Ciphertext, same length as plaintext
const uint32_t key[], // From the key setup
int keysize, // Bit length of the key, 128, 192, or 256
const uint8_t iv[]); // IV, must be AES_BLOCK_SIZE bytes long
void aes_decrypt_ctr(const uint8_t in[], // Ciphertext
size_t in_len, // Any byte length
uint8_t out[], // Plaintext, same length as ciphertext
const uint32_t key[], // From the key setup
int keysize, // Bit length of the key, 128, 192, or 256
const uint8_t iv[]); // IV, must be AES_BLOCK_SIZE bytes long
///////////////////
// AES - CCM
///////////////////
// Returns True if the input parameters do not violate any constraint.
bool aes_encrypt_ccm(
const uint8_t plaintext[], // IN - Plaintext.
uint32_t plaintext_len, // IN - Plaintext length.
const uint8_t associated_data[], // IN - Associated Data included in authentication, but not encryption.
unsigned short associated_data_len, // IN - Associated Data length in bytes.
const uint8_t nonce[], // IN - The Nonce to be used for encryption.
unsigned short nonce_len, // IN - Nonce length in bytes.
uint8_t ciphertext[], // OUT - Ciphertext, a concatination of the plaintext and the MAC.
uint32_t* ciphertext_len, // OUT - The length of the ciphertext, always plaintext_len + mac_len.
uint32_t mac_len, // IN - The desired length of the MAC, must be 4, 6, 8, 10, 12, 14, or 16.
const uint8_t key[], // IN - The AES key for encryption.
int keysize); // IN - The length of the key in bits. Valid values are 128, 192, 256.
// Returns True if the input parameters do not violate any constraint.
// Use mac_auth to ensure decryption/validation was preformed correctly.
// If authentication does not succeed, the plaintext is zeroed out. To overwride
// this, call with mac_auth = NULL. The proper proceedure is to decrypt with
// authentication enabled (mac_auth != NULL) and make a second call to that
// ignores authentication explicitly if the first call failes.
bool aes_decrypt_ccm(
const uint8_t ciphertext[], // IN - Ciphertext, the concatination of encrypted plaintext and MAC.
uint32_t ciphertext_len, // IN - Ciphertext length in bytes.
const uint8_t assoc[], // IN - The Associated Data, required for authentication.
unsigned short assoc_len, // IN - Associated Data length in bytes.
const uint8_t nonce[], // IN - The Nonce to use for decryption, same one as for encryption.
unsigned short nonce_len, // IN - Nonce length in bytes.
uint8_t plaintext[], // OUT - The plaintext that was decrypted. Will need to be large enough to hold ciphertext_len -
// mac_len.
uint32_t* plaintext_len, // OUT - Length in bytes of the output plaintext, always ciphertext_len - mac_len .
uint32_t mac_len, // IN - The length of the MAC that was calculated.
int* mac_auth, // OUT - TRUE if authentication succeeded, FALSE if it did not. NULL pointer will ignore the
// authentication.
const uint8_t key[], // IN - The AES key for decryption.
int keysize); // IN - The length of the key in BITS. Valid values are 128, 192, 256.
#endif

View File

@ -15,8 +15,6 @@
#include <unistd.h>
#endif
namespace Common {
#ifdef _WIN32
static double s_counter_frequency;
@ -399,5 +397,3 @@ void Timer::NanoSleep(std::uint64_t ns)
nanosleep(&ts, nullptr);
#endif
}
} // namespace Common

View File

@ -4,8 +4,6 @@
#pragma once
#include <cstdint>
namespace Common {
class Timer
{
public:
@ -47,5 +45,3 @@ public:
private:
Value m_tvStartValue;
};
} // namespace Common

View File

@ -81,6 +81,8 @@ add_library(core
imgui_overlays.h
interrupt_controller.cpp
interrupt_controller.h
jogcon.cpp
jogcon.h
justifier.cpp
justifier.h
mdec.cpp
@ -145,7 +147,7 @@ if(CPU_ARCH_X64)
cpu_recompiler_x64.h
)
target_link_libraries(core PRIVATE xbyak)
if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
if(CMAKE_BUILD_TYPE MATCHES "Debug|Devel")
target_link_libraries(core PRIVATE zydis)
endif()
message(STATUS "Building x64 recompiler.")

File diff suppressed because it is too large Load Diff

View File

@ -20,7 +20,7 @@
#include <cmath>
LOG_CHANNEL(AnalogController);
LOG_CHANNEL(Controller);
AnalogController::AnalogController(u32 index) : Controller(index)
{
@ -416,7 +416,7 @@ void AnalogController::UpdateHostVibration()
hvalues[motor] = (state != 0) ? static_cast<float>(strength / 65535.0) : 0.0f;
}
WARNING_LOG("Set small to {}, large to {}", hvalues[SmallMotor], hvalues[LargeMotor]);
DEV_LOG("Set small motor to {}, large motor to {}", hvalues[SmallMotor], hvalues[LargeMotor]);
InputManager::SetPadVibrationIntensity(m_index, hvalues[LargeMotor], hvalues[SmallMotor]);
}
@ -621,7 +621,7 @@ bool AnalogController::Transfer(const u8 data_in, u8* data_out)
m_status_byte = 0x5A;
}
DEV_LOG("0x{:02x}({}) config mode", m_rx_buffer[2], m_configuration_mode ? "enter" : "leave");
DEBUG_LOG("0x{:02x}({}) config mode", m_rx_buffer[2], m_configuration_mode ? "enter" : "leave");
}
}
break;
@ -706,9 +706,9 @@ bool AnalogController::Transfer(const u8 data_in, u8* data_out)
m_rumble_config[index] = data_in;
if (data_in == LargeMotor)
WARNING_LOG("Large mapped to byte index {}", index);
DEBUG_LOG("Large motor mapped to byte index {}", index);
else if (data_in == SmallMotor)
WARNING_LOG("Small mapped to byte index {}", index);
DEBUG_LOG("Small motor mapped to byte index {}", index);
}
else if (m_command_step == 7)
{

View File

@ -16,7 +16,7 @@
#include "IconsPromptFont.h"
#include "fmt/format.h"
LOG_CHANNEL(AnalogJoystick);
LOG_CHANNEL(Controller);
AnalogJoystick::AnalogJoystick(u32 index) : Controller(index)
{

View File

@ -21,21 +21,7 @@ namespace BIOS {
static constexpr ImageInfo::Hash MakeHashFromString(const char str[])
{
ImageInfo::Hash h{};
for (int i = 0; str[i] != '\0'; i++)
{
u8 nibble = 0;
char ch = str[i];
if (ch >= '0' && ch <= '9')
nibble = str[i] - '0';
else if (ch >= 'a' && ch <= 'z')
nibble = 0xA + (str[i] - 'a');
else if (ch >= 'A' && ch <= 'Z')
nibble = 0xA + (str[i] - 'A');
h[i / 2] |= nibble << (((i & 1) ^ 1) * 4);
}
return h;
return StringUtil::ParseFixedHexString<ImageInfo::HASH_SIZE>(str);
}
// clang-format off

View File

@ -941,7 +941,7 @@ void Bus::AddTTYCharacter(char ch)
if (!s_tty_line_buffer.empty())
{
Log::FastWrite(Log::Channel::TTY, Log::Level::Info, "\033[1;34m{}\033[0m", s_tty_line_buffer);
#ifdef _DEBUG
#if defined(_DEBUG) || defined(_DEVEL)
if (CPU::IsTraceEnabled())
CPU::WriteToExecutionLog("TTY: %s\n", s_tty_line_buffer.c_str());
#endif
@ -2299,7 +2299,7 @@ void** Bus::GetMemoryHandlers(bool isolate_cache, bool swap_caches)
if (!isolate_cache)
return g_memory_handlers;
#ifdef _DEBUG
#if defined(_DEBUG) || defined(_DEVEL)
if (swap_caches)
WARNING_LOG("Cache isolated and swapped, icache will be written instead of scratchpad?");
#endif

View File

@ -46,6 +46,7 @@ enum : u32
SECTOR_HEADER_SIZE = CDImage::SECTOR_HEADER_SIZE,
MODE1_HEADER_SIZE = CDImage::MODE1_HEADER_SIZE,
MODE2_HEADER_SIZE = CDImage::MODE2_HEADER_SIZE,
SUBQ_SECTOR_SKEW = 2,
XA_ADPCM_SAMPLES_PER_SECTOR_4BIT = 4032, // 28 words * 8 nibbles per word * 18 chunks
XA_ADPCM_SAMPLES_PER_SECTOR_8BIT = 2016, // 28 words * 4 bytes per word * 18 chunks
XA_RESAMPLE_RING_BUFFER_SIZE = 32,
@ -1610,7 +1611,7 @@ TickCount CDROM::GetTicksForSeek(CDImage::LBA new_lba, bool ignore_speed_change)
1.0f, 72.0f))));
const float seconds = (lba_diff < switch_point) ? 0.05f : 0.1f;
ticks += static_cast<u32>(seconds * static_cast<float>(System::MASTER_CLOCK));
seek_type = (new_lba > current_lba) ? "NT forward" : "NT backward";
seek_type = (new_lba > current_lba) ? "2N forward" : "2N backward";
}
else
{
@ -1625,7 +1626,7 @@ TickCount CDROM::GetTicksForSeek(CDImage::LBA new_lba, bool ignore_speed_change)
(((SLED_VARIABLE_COST * (std::log(static_cast<float>(lba_diff)) / std::log(MAX_SLED_LBA)))) * LOG_WEIGHT) +
((SLED_VARIABLE_COST * (lba_diff / MAX_SLED_LBA)) * (1.0f - LOG_WEIGHT));
ticks += static_cast<u32>(seconds * static_cast<float>(System::MASTER_CLOCK));
seek_type = (new_lba > current_lba) ? "2N/sled forward" : "2N/sled backward";
seek_type = (new_lba > current_lba) ? "sled forward" : "sled backward";
}
if (g_settings.cdrom_seek_speedup > 1)
@ -2101,11 +2102,6 @@ void CDROM::ExecuteCommand(void*, TickCount ticks, TickCount ticks_late)
case Command::Pause:
{
if (IsReadingOrPlaying())
DEV_COLOR_LOG(StrongOrange, "Pause");
else
DEV_COLOR_LOG(StrongRed, "Pause Not Reading");
const TickCount pause_time = GetTicksForPause();
if (IsReading() && s_state.last_subq.IsData())
{
@ -2124,22 +2120,34 @@ void CDROM::ExecuteCommand(void*, TickCount ticks, TickCount ticks_late)
((s_state.drive_state == DriveState::Reading || s_state.drive_state == DriveState::Playing) &&
s_state.secondary_status.seeking))
{
WARNING_LOG("CDROM Pause command while seeking - sending error response");
if (Log::GetLogLevel() >= Log::Level::Dev)
DEV_COLOR_LOG(StrongRed, "Pause Seeking => Error");
else
WARNING_LOG("CDROM Pause command while seeking - sending error response");
SendErrorResponse(STAT_ERROR, ERROR_REASON_NOT_READY);
EndCommand();
return;
}
else
{
// Small window of time when another INT1 could sneak in, don't let it.
ClearAsyncInterrupt();
// Stop reading.
s_state.drive_state = DriveState::Idle;
s_state.drive_event.Deactivate();
s_state.secondary_status.ClearActiveBits();
if (Log::GetLogLevel() >= Log::Level::Dev)
{
const double pause_time_ms =
static_cast<double>(pause_time) / (static_cast<double>(System::MASTER_CLOCK) / 1000.0);
if (IsReadingOrPlaying())
DEV_COLOR_LOG(StrongOrange, "Pause {:.2f}ms", pause_time_ms);
else
DEV_COLOR_LOG(Yellow, "Pause Not Reading {:.2f}ms", pause_time_ms);
}
// Small window of time when another INT1 could sneak in, don't let it.
ClearAsyncInterrupt();
// Stop reading.
s_state.drive_state = DriveState::Idle;
s_state.drive_event.Deactivate();
s_state.secondary_status.ClearActiveBits();
// Reset audio buffer here - control room cutscene audio repeats in Dino Crisis otherwise.
ResetAudioDecoder();
@ -2875,7 +2883,7 @@ void CDROM::UpdateSubQPosition(bool update_logical)
const CDImage::LBA old_offset = s_state.current_subq_lba - tjump_position;
const CDImage::LBA new_offset = (old_offset + sector_diff) % sectors_per_track;
const CDImage::LBA new_subq_lba = tjump_position + new_offset;
#ifdef _DEBUG
#if defined(_DEBUG) || defined(_DEVEL)
DEV_LOG("{} sectors @ {} SPT, old pos {}, hold pos {}, tjump pos {}, new pos {}", sector_diff, sectors_per_track,
LBAToMSFString(s_state.current_subq_lba), LBAToMSFString(hold_position), LBAToMSFString(tjump_position),
LBAToMSFString(new_subq_lba));
@ -2960,10 +2968,13 @@ bool CDROM::CompleteSeek()
if (seek_okay)
{
const CDImage::SubChannelQ& subq = GetSectorSubQ(s_reader.GetLastReadSector(), s_reader.GetSectorSubQ());
s_state.current_lba = s_reader.GetLastReadSector();
if (subq.IsCRCValid())
{
// seek and update sub-q for ReadP command
s_state.last_subq = subq;
s_state.last_subq_needs_update = false;
const auto [seek_mm, seek_ss, seek_ff] = CDImage::Position::FromLBA(s_reader.GetLastReadSector()).ToBCD();
seek_okay = (subq.absolute_minute_bcd == seek_mm && subq.absolute_second_bcd == seek_ss &&
subq.absolute_frame_bcd == seek_ff);
@ -2977,12 +2988,16 @@ bool CDROM::CompleteSeek()
seek_okay = (s_state.last_sector_header.minute == seek_mm && s_state.last_sector_header.second == seek_ss &&
s_state.last_sector_header.frame == seek_ff);
if (seek_okay)
if (seek_okay && !s_state.play_after_seek && !s_state.read_after_seek)
{
// after reading the target, the mech immediately does a 1T reverse
const u32 spt = GetSectorsPerTrack(s_state.current_subq_lba);
SetHoldPosition(s_state.current_subq_lba,
(spt <= s_state.current_subq_lba) ? (s_state.current_subq_lba - spt) : 0);
// This is pretty janky. The mech completes the seek when it "sees" a data header
// 2 sectors before the seek target, so that a subsequent ReadN can complete nearly
// immediately. Therefore when the seek completes, SubQ = Target, Data = Target - 2.
// Hack the SubQ back by 2 frames so that following seeks will read forward. If we
// ever properly handle SubQ versus data positions, this can be removed.
s_state.current_subq_lba =
(s_state.current_lba >= SUBQ_SECTOR_SKEW) ? (s_state.current_lba - SUBQ_SECTOR_SKEW) : 0;
s_state.last_subq_needs_update = true;
}
}
}
@ -3009,8 +3024,6 @@ bool CDROM::CompleteSeek()
}
}
}
s_state.current_lba = s_reader.GetLastReadSector();
}
return seek_okay;
@ -3227,7 +3240,7 @@ void CDROM::DoSectorRead()
// so that multiple sectors could be read in one back, in which case we could just "look ahead" to grab the
// subq, but I haven't got around to it. It'll break libcrypt, but CC doesn't use it. One day I'll get around to
// doing the refactor.... but given this is the only game that relies on it, priorities.
s_reader.GetMedia()->GenerateSubChannelQ(&s_state.last_subq, s_state.current_lba + 2);
s_reader.GetMedia()->GenerateSubChannelQ(&s_state.last_subq, s_state.current_lba + SUBQ_SECTOR_SKEW);
}
}
else

View File

@ -187,7 +187,7 @@ bool CDROMAsyncReader::WaitForReadToComplete()
return m_buffers[m_buffer_front.load()].result;
}
Common::Timer wait_timer;
Timer wait_timer;
DEBUG_LOG("Sector read pending, waiting");
std::unique_lock<std::mutex> lock(m_mutex);
@ -226,7 +226,7 @@ void CDROMAsyncReader::EmptyBuffers()
bool CDROMAsyncReader::ReadSectorIntoBuffer(std::unique_lock<std::mutex>& lock)
{
Common::Timer timer;
Timer timer;
const u32 slot = m_buffer_back.load();
m_buffer_back.store((slot + 1) % static_cast<u32>(m_buffers.size()));
@ -259,7 +259,7 @@ bool CDROMAsyncReader::ReadSectorIntoBuffer(std::unique_lock<std::mutex>& lock)
void CDROMAsyncReader::ReadSectorNonThreaded(CDImage::LBA lba)
{
Common::Timer timer;
Timer timer;
m_buffers.resize(1);
m_seek_error.store(false);

View File

@ -8,6 +8,7 @@
#include "game_database.h"
#include "guncon.h"
#include "host.h"
#include "jogcon.h"
#include "justifier.h"
#include "negcon.h"
#include "negcon_rumble.h"
@ -38,6 +39,7 @@ static const Controller::ControllerInfo* s_controller_info[] = {
&Justifier::INFO,
&DigitalController::INFO_POPN,
&DigitalController::INFO_DDGO,
&JogCon::INFO,
};
const std::array<u32, NUM_CONTROLLER_AND_CARD_PORTS> Controller::PortDisplayOrder = {{0, 2, 3, 4, 1, 5, 6, 7}};
@ -140,6 +142,9 @@ std::unique_ptr<Controller> Controller::Create(ControllerType type, u32 index)
case ControllerType::NeGconRumble:
return NeGconRumble::Create(index);
case ControllerType::JogCon:
return JogCon::Create(index);
case ControllerType::None:
default:
return {};
@ -238,6 +243,12 @@ const char* Controller::GetPortDisplayName(u32 port, u32 slot, bool mtap)
return mtap ? mtap_labels[port][slot] : no_mtap_labels[port];
}
const char* Controller::GetPortDisplayName(u32 index)
{
const auto& [port, slot] = ConvertPadToPortAndSlot(index);
return GetPortDisplayName(port, slot, g_settings.IsMultitapPortEnabled(port));
}
std::string Controller::GetSettingsSection(u32 pad)
{
return fmt::format("Pad{}", pad + 1u);

View File

@ -139,6 +139,7 @@ public:
/// Returns a printable label for a given port.
static const char* GetPortDisplayName(u32 port, u32 slot, bool mtap);
static const char* GetPortDisplayName(u32 index);
/// List of controller indices in the order that they should be displayed.
static const std::array<u32, NUM_CONTROLLER_AND_CARD_PORTS> PortDisplayOrder;

View File

@ -51,6 +51,7 @@
<ClCompile Include="hotkeys.cpp" />
<ClCompile Include="imgui_overlays.cpp" />
<ClCompile Include="interrupt_controller.cpp" />
<ClCompile Include="jogcon.cpp" />
<ClCompile Include="justifier.cpp" />
<ClCompile Include="mdec.cpp" />
<ClCompile Include="memory_card.cpp" />
@ -131,6 +132,7 @@
<ClInclude Include="imgui_overlays.h" />
<ClInclude Include="input_types.h" />
<ClInclude Include="interrupt_controller.h" />
<ClInclude Include="jogcon.h" />
<ClInclude Include="justifier.h" />
<ClInclude Include="mdec.h" />
<ClInclude Include="memory_card.h" />
@ -178,7 +180,7 @@
<ProjectReference Include="..\..\dep\xxhash\xxhash.vcxproj">
<Project>{09553c96-9f39-49bf-8ae6-7acbd07c410c}</Project>
</ProjectReference>
<ProjectReference Include="..\..\dep\zydis\zydis.vcxproj" Condition="'$(Platform)'=='x64' And $(Configuration.Contains('Debug'))">
<ProjectReference Include="..\..\dep\zydis\zydis.vcxproj" Condition="'$(Platform)'=='x64' And ($(Configuration.Contains('Debug')) Or $(Configuration.Contains('Devel')))">
<Project>{c51a346a-86b2-46df-9bb3-d0aa7e5d8699}</Project>
</ProjectReference>
<ProjectReference Include="..\scmversion\scmversion.vcxproj">
@ -198,8 +200,8 @@
<Import Project="core.props" />
<ItemDefinitionGroup>
<ClCompile>
<PreprocessorDefinitions Condition="'$(Platform)'=='x64' And $(Configuration.Contains('Debug'))">ZYDIS_DISABLE_ENCODER;ZYDIS_DISABLE_AVX512;ZYDIS_DISABLE_KNC;ZYDIS_STATIC_BUILD;ZYCORE_STATIC_BUILD;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories Condition="'$(Platform)'=='x64' And $(Configuration.Contains('Debug'))">%(AdditionalIncludeDirectories);$(SolutionDir)dep\zydis\include;$(SolutionDir)dep\zydis\dependencies\zycore\include</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Platform)'=='x64' And ($(Configuration.Contains('Debug')) Or $(Configuration.Contains('Devel')))">ZYDIS_DISABLE_ENCODER;ZYDIS_DISABLE_AVX512;ZYDIS_DISABLE_KNC;ZYDIS_STATIC_BUILD;ZYCORE_STATIC_BUILD;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories Condition="'$(Platform)'=='x64' And ($(Configuration.Contains('Debug')) Or $(Configuration.Contains('Devel')))">%(AdditionalIncludeDirectories);$(SolutionDir)dep\zydis\include;$(SolutionDir)dep\zydis\dependencies\zycore\include</AdditionalIncludeDirectories>
<ObjectFileName>$(IntDir)/%(RelativeDir)/</ObjectFileName>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>

View File

@ -65,6 +65,7 @@
<ClCompile Include="gpu_dump.cpp" />
<ClCompile Include="cdrom_subq_replacement.cpp" />
<ClCompile Include="performance_counters.cpp" />
<ClCompile Include="jogcon.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="types.h" />
@ -139,6 +140,7 @@
<ClInclude Include="cdrom_subq_replacement.h" />
<ClInclude Include="performance_counters.h" />
<ClInclude Include="system_private.h" />
<ClInclude Include="jogcon.h" />
</ItemGroup>
<ItemGroup>
<None Include="gpu_sw_rasterizer.inl" />

View File

@ -154,9 +154,10 @@ static u8* s_free_far_code_ptr = nullptr;
static u32 s_far_code_size = 0;
static u32 s_far_code_used = 0;
#ifdef _DEBUG
#ifdef DUMP_CODE_SIZE_STATS
static u32 s_total_instructions_compiled = 0;
static u32 s_total_host_instructions_emitted = 0;
static u32 s_total_host_code_used_by_instructions = 0;
#endif
} // namespace CPU::CodeCache
@ -691,7 +692,6 @@ void CPU::CodeCache::InvalidateAllRAMBlocks()
void CPU::CodeCache::ClearBlocks()
{
for (u32 i = 0; i < Bus::RAM_8MB_CODE_PAGE_COUNT; i++)
{
PageProtectionInfo& ppi = s_page_protection[i];
@ -1023,7 +1023,7 @@ bool CPU::CodeCache::ReadBlockInstructions(u32 start_pc, BlockInstructionList* i
instructions->back().second.is_last_instruction = true;
#ifdef _DEBUG
#if defined(_DEBUG) || defined(_DEVEL)
SmallString disasm;
DEBUG_LOG("Block at 0x{:08X}", start_pc);
DEBUG_LOG(" Uncached fetch ticks: {}", metadata->uncached_fetch_ticks);
@ -1345,10 +1345,13 @@ void CPU::CodeCache::CompileOrRevalidateBlock(u32 start_pc)
}
// Ensure we're not going to run out of space while compiling this block.
// We could definitely do better here... TODO: far code is no longer needed for newrec
// We could definitely do better here...
const u32 block_size = static_cast<u32>(s_block_instructions.size());
if (GetFreeCodeSpace() < (block_size * Recompiler::MAX_NEAR_HOST_BYTES_PER_INSTRUCTION) ||
GetFreeFarCodeSpace() < (block_size * Recompiler::MAX_FAR_HOST_BYTES_PER_INSTRUCTION))
const u32 free_code_space = GetFreeCodeSpace();
const u32 free_far_code_space = GetFreeFarCodeSpace();
if (free_code_space < (block_size * Recompiler::MAX_NEAR_HOST_BYTES_PER_INSTRUCTION) ||
free_code_space < Recompiler::MIN_CODE_RESERVE_FOR_BLOCK ||
free_far_code_space < Recompiler::MIN_CODE_RESERVE_FOR_BLOCK)
{
ERROR_LOG("Out of code space while compiling {:08X}. Resetting code cache.", start_pc);
CodeCache::Reset();
@ -1540,9 +1543,10 @@ void CPU::CodeCache::CompileASMFunctions()
{
MemMap::BeginCodeWrite();
#ifdef _DEBUG
#ifdef DUMP_CODE_SIZE_STATS
s_total_instructions_compiled = 0;
s_total_host_instructions_emitted = 0;
s_total_host_code_used_by_instructions = 0;
#endif
const u32 asm_size = EmitASMFunctions(GetFreeCodePointer(), GetFreeCodeSpace());
@ -1580,14 +1584,18 @@ bool CPU::CodeCache::CompileBlock(Block* block)
const u32 host_instructions = GetHostInstructionCount(host_code, host_code_size);
s_total_instructions_compiled += block->size;
s_total_host_instructions_emitted += host_instructions;
s_total_host_code_used_by_instructions += host_code_size;
DEV_LOG("0x{:08X}: {}/{}b for {}b ({}i), blowup: {:.2f}x, cache: {:.2f}%/{:.2f}%, ipi: {:.2f}/{:.2f}", block->pc,
host_code_size, host_far_code_size, block->size * 4, block->size,
static_cast<float>(host_code_size) / static_cast<float>(block->size * 4),
(static_cast<float>(s_code_used) / static_cast<float>(s_code_size)) * 100.0f,
(static_cast<float>(s_far_code_used) / static_cast<float>(s_far_code_size)) * 100.0f,
static_cast<float>(host_instructions) / static_cast<float>(block->size),
static_cast<float>(s_total_host_instructions_emitted) / static_cast<float>(s_total_instructions_compiled));
DEV_LOG(
"0x{:08X}: {}/{}b for {}b ({}i), blowup: {:.2f}x, cache: {:.2f}%/{:.2f}%, ipi: {:.2f}/{:.2f}, bpi: {:.2f}/{:.2f}",
block->pc, host_code_size, host_far_code_size, block->size * 4, block->size,
static_cast<float>(host_code_size) / static_cast<float>(block->size * 4),
(static_cast<float>(s_code_used) / static_cast<float>(s_code_size)) * 100.0f,
(static_cast<float>(s_far_code_used) / static_cast<float>(s_far_code_size)) * 100.0f,
static_cast<float>(host_instructions) / static_cast<float>(block->size),
static_cast<float>(s_total_host_instructions_emitted) / static_cast<float>(s_total_instructions_compiled),
static_cast<float>(block->host_code_size) / static_cast<float>(block->size),
static_cast<float>(s_total_host_code_used_by_instructions) / static_cast<float>(s_total_instructions_compiled));
#endif
#if 0

View File

@ -215,7 +215,7 @@ void InterpretUncachedBlock();
void LogCurrentState();
#if defined(_DEBUG) || false
#if defined(_DEBUG) || defined(_DEVEL) || false
// Enable disassembly of host assembly code.
#define ENABLE_HOST_DISASSEMBLY 1
#endif

View File

@ -20,6 +20,7 @@
#include "common/fastjmp.h"
#include "common/file_system.h"
#include "common/log.h"
#include "common/path.h"
#include "fmt/format.h"
@ -48,9 +49,6 @@ static u32 ReadReg(Reg rs);
static void WriteReg(Reg rd, u32 value);
static void WriteRegDelayed(Reg rd, u32 value);
static u32 ReadCop0Reg(Cop0Reg reg);
static void WriteCop0Reg(Cop0Reg reg, u32 value);
static void DispatchCop0Breakpoint();
static bool IsCop0ExecutionBreakpointUnmasked();
static void Cop0ExecutionBreakpointCheck();
@ -147,9 +145,9 @@ void CPU::StopTrace()
void CPU::WriteToExecutionLog(const char* format, ...)
{
if (!s_log_file_opened)
if (!s_log_file_opened) [[unlikely]]
{
s_log_file = FileSystem::OpenCFile("cpu_log.txt", "wb");
s_log_file = FileSystem::OpenCFile(Path::Combine(EmuFolders::DataRoot, "cpu_log.txt").c_str(), "wb");
s_log_file_opened = true;
}
@ -338,7 +336,7 @@ ALWAYS_INLINE_RELEASE void CPU::RaiseException(u32 CAUSE_bits, u32 EPC, u32 vect
g_state.cop0_regs.cause.bits = (g_state.cop0_regs.cause.bits & ~Cop0Registers::CAUSE::EXCEPTION_WRITE_MASK) |
(CAUSE_bits & Cop0Registers::CAUSE::EXCEPTION_WRITE_MASK);
#ifdef _DEBUG
#if defined(_DEBUG) || defined(_DEVEL)
if (g_state.cop0_regs.cause.Excode != Exception::INT && g_state.cop0_regs.cause.Excode != Exception::Syscall &&
g_state.cop0_regs.cause.Excode != Exception::BP)
{
@ -494,122 +492,6 @@ ALWAYS_INLINE_RELEASE void CPU::WriteRegDelayed(Reg rd, u32 value)
g_state.next_load_delay_value = value;
}
ALWAYS_INLINE_RELEASE u32 CPU::ReadCop0Reg(Cop0Reg reg)
{
switch (reg)
{
case Cop0Reg::BPC:
return g_state.cop0_regs.BPC;
case Cop0Reg::BPCM:
return g_state.cop0_regs.BPCM;
case Cop0Reg::BDA:
return g_state.cop0_regs.BDA;
case Cop0Reg::BDAM:
return g_state.cop0_regs.BDAM;
case Cop0Reg::DCIC:
return g_state.cop0_regs.dcic.bits;
case Cop0Reg::JUMPDEST:
return g_state.cop0_regs.TAR;
case Cop0Reg::BadVaddr:
return g_state.cop0_regs.BadVaddr;
case Cop0Reg::SR:
return g_state.cop0_regs.sr.bits;
case Cop0Reg::CAUSE:
return g_state.cop0_regs.cause.bits;
case Cop0Reg::EPC:
return g_state.cop0_regs.EPC;
case Cop0Reg::PRID:
return g_state.cop0_regs.PRID;
default:
return 0;
}
}
ALWAYS_INLINE_RELEASE void CPU::WriteCop0Reg(Cop0Reg reg, u32 value)
{
switch (reg)
{
case Cop0Reg::BPC:
{
g_state.cop0_regs.BPC = value;
DEV_LOG("COP0 BPC <- {:08X}", value);
}
break;
case Cop0Reg::BPCM:
{
g_state.cop0_regs.BPCM = value;
DEV_LOG("COP0 BPCM <- {:08X}", value);
if (UpdateDebugDispatcherFlag())
ExitExecution();
}
break;
case Cop0Reg::BDA:
{
g_state.cop0_regs.BDA = value;
DEV_LOG("COP0 BDA <- {:08X}", value);
}
break;
case Cop0Reg::BDAM:
{
g_state.cop0_regs.BDAM = value;
DEV_LOG("COP0 BDAM <- {:08X}", value);
}
break;
case Cop0Reg::JUMPDEST:
{
WARNING_LOG("Ignoring write to Cop0 JUMPDEST");
}
break;
case Cop0Reg::DCIC:
{
g_state.cop0_regs.dcic.bits =
(g_state.cop0_regs.dcic.bits & ~Cop0Registers::DCIC::WRITE_MASK) | (value & Cop0Registers::DCIC::WRITE_MASK);
DEV_LOG("COP0 DCIC <- {:08X} (now {:08X})", value, g_state.cop0_regs.dcic.bits);
if (UpdateDebugDispatcherFlag())
ExitExecution();
}
break;
case Cop0Reg::SR:
{
g_state.cop0_regs.sr.bits =
(g_state.cop0_regs.sr.bits & ~Cop0Registers::SR::WRITE_MASK) | (value & Cop0Registers::SR::WRITE_MASK);
DEBUG_LOG("COP0 SR <- {:08X} (now {:08X})", value, g_state.cop0_regs.sr.bits);
UpdateMemoryPointers();
CheckForPendingInterrupt();
}
break;
case Cop0Reg::CAUSE:
{
g_state.cop0_regs.cause.bits =
(g_state.cop0_regs.cause.bits & ~Cop0Registers::CAUSE::WRITE_MASK) | (value & Cop0Registers::CAUSE::WRITE_MASK);
DEBUG_LOG("COP0 CAUSE <- {:08X} (now {:08X})", value, g_state.cop0_regs.cause.bits);
CheckForPendingInterrupt();
}
break;
[[unlikely]] default : DEV_LOG("Unknown COP0 reg write {} ({:08X})", static_cast<u8>(reg), value);
break;
}
}
ALWAYS_INLINE_RELEASE bool CPU::IsCop0ExecutionBreakpointUnmasked()
{
static constexpr const u32 code_address_ranges[][2] = {
@ -1775,7 +1657,59 @@ restart_instruction:
{
case CopCommonInstruction::mfcn:
{
const u32 value = ReadCop0Reg(static_cast<Cop0Reg>(inst.r.rd.GetValue()));
u32 value;
switch (static_cast<Cop0Reg>(inst.r.rd.GetValue()))
{
case Cop0Reg::BPC:
value = g_state.cop0_regs.BPC;
break;
case Cop0Reg::BPCM:
value = g_state.cop0_regs.BPCM;
break;
case Cop0Reg::BDA:
value = g_state.cop0_regs.BDA;
break;
case Cop0Reg::BDAM:
value = g_state.cop0_regs.BDAM;
break;
case Cop0Reg::DCIC:
value = g_state.cop0_regs.dcic.bits;
break;
case Cop0Reg::JUMPDEST:
value = g_state.cop0_regs.TAR;
break;
case Cop0Reg::BadVaddr:
value = g_state.cop0_regs.BadVaddr;
break;
case Cop0Reg::SR:
value = g_state.cop0_regs.sr.bits;
break;
case Cop0Reg::CAUSE:
value = g_state.cop0_regs.cause.bits;
break;
case Cop0Reg::EPC:
value = g_state.cop0_regs.EPC;
break;
case Cop0Reg::PRID:
value = g_state.cop0_regs.PRID;
break;
default:
RaiseException(Exception::RI);
return;
}
WriteRegDelayed(inst.r.rt, value);
if constexpr (pgxp_mode == PGXPMode::CPU)
@ -1785,11 +1719,86 @@ restart_instruction:
case CopCommonInstruction::mtcn:
{
const u32 rtVal = ReadReg(inst.r.rt);
WriteCop0Reg(static_cast<Cop0Reg>(inst.r.rd.GetValue()), rtVal);
u32 value = ReadReg(inst.r.rt);
[[maybe_unused]] const u32 orig_value = value;
switch (static_cast<Cop0Reg>(inst.r.rd.GetValue()))
{
case Cop0Reg::BPC:
{
g_state.cop0_regs.BPC = value;
DEV_LOG("COP0 BPC <- {:08X}", value);
}
break;
case Cop0Reg::BPCM:
{
g_state.cop0_regs.BPCM = value;
DEV_LOG("COP0 BPCM <- {:08X}", value);
if (UpdateDebugDispatcherFlag())
ExitExecution();
}
break;
case Cop0Reg::BDA:
{
g_state.cop0_regs.BDA = value;
DEV_LOG("COP0 BDA <- {:08X}", value);
}
break;
case Cop0Reg::BDAM:
{
g_state.cop0_regs.BDAM = value;
DEV_LOG("COP0 BDAM <- {:08X}", value);
}
break;
case Cop0Reg::JUMPDEST:
{
WARNING_LOG("Ignoring write to Cop0 JUMPDEST");
}
break;
case Cop0Reg::DCIC:
{
g_state.cop0_regs.dcic.bits = (g_state.cop0_regs.dcic.bits & ~Cop0Registers::DCIC::WRITE_MASK) |
(value & Cop0Registers::DCIC::WRITE_MASK);
DEV_LOG("COP0 DCIC <- {:08X} (now {:08X})", value, g_state.cop0_regs.dcic.bits);
value = g_state.cop0_regs.dcic.bits;
if (UpdateDebugDispatcherFlag())
ExitExecution();
}
break;
case Cop0Reg::SR:
{
g_state.cop0_regs.sr.bits = (g_state.cop0_regs.sr.bits & ~Cop0Registers::SR::WRITE_MASK) |
(value & Cop0Registers::SR::WRITE_MASK);
DEBUG_LOG("COP0 SR <- {:08X} (now {:08X})", value, g_state.cop0_regs.sr.bits);
value = g_state.cop0_regs.sr.bits;
UpdateMemoryPointers();
CheckForPendingInterrupt();
}
break;
case Cop0Reg::CAUSE:
{
g_state.cop0_regs.cause.bits = (g_state.cop0_regs.cause.bits & ~Cop0Registers::CAUSE::WRITE_MASK) |
(value & Cop0Registers::CAUSE::WRITE_MASK);
DEBUG_LOG("COP0 CAUSE <- {:08X} (now {:08X})", value, g_state.cop0_regs.cause.bits);
value = g_state.cop0_regs.cause.bits;
CheckForPendingInterrupt();
}
break;
[[unlikely]] default:
RaiseException(Exception::RI);
return;
}
if constexpr (pgxp_mode == PGXPMode::CPU)
PGXP::CPU_MTC0(inst, ReadCop0Reg(static_cast<Cop0Reg>(inst.r.rd.GetValue())), rtVal);
PGXP::CPU_MTC0(inst, value, orig_value);
}
break;
@ -1817,7 +1826,7 @@ restart_instruction:
case Cop0Instruction::tlbwr:
case Cop0Instruction::tlbp:
RaiseException(Exception::RI);
break;
return;
default:
[[unlikely]] ERROR_LOG("Unhandled instruction at {:08X}: {:08X}", g_state.current_instruction_pc,
@ -2840,10 +2849,7 @@ ALWAYS_INLINE_RELEASE bool CPU::FetchInstruction()
case 0x07: // KSEG2
default:
{
CPU::RaiseException(Cop0Registers::CAUSE::MakeValueForException(Exception::IBE,
g_state.current_instruction_in_branch_delay_slot,
g_state.current_instruction_was_branch_taken, 0),
address);
CPU::RaiseException(Cop0Registers::CAUSE::MakeValueForException(Exception::IBE, false, false, 0), address);
return false;
}
}

View File

@ -354,7 +354,7 @@ bool CPU::Recompiler::Recompiler::TrySwapDelaySlot(Reg rs, Reg rt, Reg rd)
const Reg opcode_rt = next_instruction->r.rt;
const Reg opcode_rd = next_instruction->r.rd;
#ifdef _DEBUG
#if defined(_DEBUG) || defined(_DEVEL)
TinyString disasm;
DisassembleInstruction(&disasm, m_current_instruction_pc + 4, next_instruction->bits);
#endif
@ -492,7 +492,7 @@ bool CPU::Recompiler::Recompiler::TrySwapDelaySlot(Reg rs, Reg rt, Reg rd)
}
is_safe:
#ifdef _DEBUG
#if defined(_DEBUG) || defined(_DEVEL)
DEBUG_LOG("Swapping delay slot {:08X} {}", m_current_instruction_pc + 4, disasm);
#endif
@ -504,7 +504,7 @@ is_safe:
return true;
is_unsafe:
#ifdef _DEBUG
#if defined(_DEBUG) || defined(_DEVEL)
DEBUG_LOG("NOT swapping delay slot {:08X} {}", m_current_instruction_pc + 4, disasm);
#endif
@ -1178,7 +1178,7 @@ void CPU::Recompiler::Recompiler::AddLoadStoreInfo(void* code_address, u32 code_
void CPU::Recompiler::Recompiler::CompileInstruction()
{
#ifdef _DEBUG
#if defined(_DEBUG) || defined(_DEVEL)
TinyString str;
DisassembleInstruction(&str, m_current_instruction_pc, inst->bits);
DEBUG_LOG("Compiling{} {:08X}: {}", m_current_instruction_branch_delay_slot ? " branch delay slot" : "",

View File

@ -14,7 +14,6 @@
namespace CPU {
// TODO: Get rid of the virtuals... somehow.
class Recompiler
{
public:
@ -26,8 +25,10 @@ public:
#if defined(CPU_ARCH_X64)
// A reasonable "maximum" number of bytes per instruction.
static constexpr u32 MAX_NEAR_HOST_BYTES_PER_INSTRUCTION = 64;
static constexpr u32 MAX_FAR_HOST_BYTES_PER_INSTRUCTION = 128;
// Seems to hover around ~21 bytes without PGXP, and ~26 bytes with.
// Use an upper bound of 32 bytes to be safe.
static constexpr u32 MAX_NEAR_HOST_BYTES_PER_INSTRUCTION = 32;
static constexpr u32 MIN_CODE_RESERVE_FOR_BLOCK = 512;
// Number of host registers.
static constexpr u32 NUM_HOST_REGS = 16;
@ -37,7 +38,7 @@ public:
// A reasonable "maximum" number of bytes per instruction.
static constexpr u32 MAX_NEAR_HOST_BYTES_PER_INSTRUCTION = 64;
static constexpr u32 MAX_FAR_HOST_BYTES_PER_INSTRUCTION = 128;
static constexpr u32 MIN_CODE_RESERVE_FOR_BLOCK = 512;
// Number of host registers.
static constexpr u32 NUM_HOST_REGS = 16;
@ -45,14 +46,16 @@ public:
#elif defined(CPU_ARCH_ARM64)
// A reasonable "maximum" number of bytes per instruction.
// Seems to hover around ~24 bytes without PGXP, and ~40 bytes with.
// Use an upper bound of 48 bytes to be safe.
static constexpr u32 MAX_NEAR_HOST_BYTES_PER_INSTRUCTION = 48;
static constexpr u32 MIN_CODE_RESERVE_FOR_BLOCK = 512;
// Number of host registers.
static constexpr u32 NUM_HOST_REGS = 32;
static constexpr bool HAS_MEMORY_OPERANDS = false;
// A reasonable "maximum" number of bytes per instruction.
static constexpr u32 MAX_NEAR_HOST_BYTES_PER_INSTRUCTION = 64;
static constexpr u32 MAX_FAR_HOST_BYTES_PER_INSTRUCTION = 128;
#elif defined(CPU_ARCH_RISCV64)
// Number of host registers.
@ -61,7 +64,7 @@ public:
// A reasonable "maximum" number of bytes per instruction.
static constexpr u32 MAX_NEAR_HOST_BYTES_PER_INSTRUCTION = 64;
static constexpr u32 MAX_FAR_HOST_BYTES_PER_INSTRUCTION = 128;
static constexpr u32 MIN_CODE_RESERVE_FOR_BLOCK = 512;
#endif

View File

@ -772,7 +772,7 @@ template<DMA::Channel channel>
TickCount DMA::TransferMemoryToDevice(u32 address, u32 increment, u32 word_count)
{
const u32 mask = Bus::g_ram_mask;
#ifdef _DEBUG
#if defined(_DEBUG) || defined(_DEVEL)
if ((address & mask) != address)
DEBUG_LOG("DMA TO {} from masked RAM address 0x{:08X} => 0x{:08X}", channel, address, (address & mask));
#endif
@ -862,7 +862,7 @@ template<DMA::Channel channel>
TickCount DMA::TransferDeviceToMemory(u32 address, u32 increment, u32 word_count)
{
const u32 mask = Bus::g_ram_mask;
#ifdef _DEBUG
#if defined(_DEBUG) || defined(_DEVEL)
if ((address & mask) != address)
DEBUG_LOG("DMA FROM {} to masked RAM address 0x{:08X} => 0x{:08X}", channel, address, (address & mask));
#endif

View File

@ -422,7 +422,7 @@ static std::string s_input_binding_key;
static std::string s_input_binding_display_name;
static std::vector<InputBindingKey> s_input_binding_new_bindings;
static std::vector<std::pair<InputBindingKey, std::pair<float, float>>> s_input_binding_value_ranges;
static Common::Timer s_input_binding_timer;
static Timer s_input_binding_timer;
static bool s_controller_macro_expanded[NUM_CONTROLLER_AND_CARD_PORTS][InputManager::NUM_MACRO_BUTTONS_PER_CONTROLLER] =
{};
@ -1651,7 +1651,7 @@ void FullscreenUI::DrawInputBindingButton(SettingsInterface* bsi, InputBindingIn
if (!visible)
return;
if (oneline)
if (oneline && type != InputBindingInfo::Type::Pointer && type != InputBindingInfo::Type::Device)
InputManager::PrettifyInputBinding(value);
if (show_type)
@ -1677,6 +1677,9 @@ void FullscreenUI::DrawInputBindingButton(SettingsInterface* bsi, InputBindingIn
case InputBindingInfo::Type::Macro:
title.format(ICON_FA_PIZZA_SLICE " {}", display_name);
break;
case InputBindingInfo::Type::Device:
title.format(ICON_FA_GAMEPAD " {}", display_name);
break;
default:
title = display_name;
break;
@ -4323,7 +4326,8 @@ void FullscreenUI::DrawGraphicsSettingsPage()
DrawEnumSetting(bsi, FSUI_ICONSTR(ICON_FA_CROP_ALT, "Crop Mode"),
FSUI_CSTR("Determines how much of the area typically not visible on a consumer TV set to crop/hide."),
"Display", "CropMode", Settings::DEFAULT_DISPLAY_CROP_MODE, &Settings::ParseDisplayCropMode,
&Settings::GetDisplayCropModeName, &Settings::GetDisplayCropModeDisplayName, DisplayCropMode::MaxCount);
&Settings::GetDisplayCropModeName, &Settings::GetDisplayCropModeDisplayName,
DisplayCropMode::MaxCount);
DrawEnumSetting(
bsi, FSUI_ICONSTR(ICON_FA_EXPAND, "Scaling"),
@ -4602,7 +4606,7 @@ void FullscreenUI::DrawGraphicsSettingsPage()
FSUI_CSTR("Dumps textures that have replacements already loaded."), "TextureReplacements", "DumpReplacedTextures",
false, texture_cache_enabled && GetEffectiveBoolSetting(bsi, "TextureReplacements", "DumpTextures", false));
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_FILE_ALT, "Enable VRAM Write Texture Replacement"),
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_FILE_ALT, "Enable VRAM Write Replacement"),
FSUI_CSTR("Enables the replacement of background textures in supported games."),
"TextureReplacements", "EnableVRAMWriteReplacements", false);

View File

@ -163,7 +163,7 @@ void GameDatabase::EnsureLoaded()
if (s_loaded)
return;
Common::Timer timer;
Timer timer;
s_loaded = true;
@ -646,7 +646,7 @@ void GameDatabase::Entry::ApplySettings(Settings& settings, bool display_osd_mes
#else
Host::AddIconOSDWarning("gamedb_force_pgxp_cpu", ICON_EMOJI_WARNING,
"This game requires PGXP CPU mode, which increases system requirements.\n"
" If the game runs too slow, disable PGXP for this game.",
" If the game runs too slow, disable PGXP for this game.",
Host::OSD_WARNING_DURATION);
#endif
}
@ -1417,7 +1417,7 @@ void GameDatabase::EnsureTrackHashesMapLoaded()
bool GameDatabase::LoadTrackHashes()
{
Common::Timer load_timer;
Timer load_timer;
Error error;
std::optional<std::string> gamedb_data(Host::ReadResourceFileToString(DISCDB_YAML_FILENAME, false, &error));

View File

@ -11,6 +11,7 @@
#include "system.h"
#include "util/cd_image.h"
#include "util/elf_file.h"
#include "util/http_downloader.h"
#include "util/image.h"
#include "util/ini_settings_interface.h"
@ -199,6 +200,18 @@ bool GameList::GetExeListEntry(const std::string& path, GameList::Entry* entry)
// Who knows
entry->region = DiscRegion::Other;
}
else if (StringUtil::EndsWithNoCase(filename, ".elf"))
{
ELFFile::Elf32_Ehdr header;
if (std::fread(&header, sizeof(header), 1, fp.get()) != 1 || !ELFFile::IsValidElfHeader(header))
{
WARNING_LOG("{} is not a valid ELF.", path);
return false;
}
// Who knows
entry->region = DiscRegion::Other;
}
else
{
BIOS::PSEXEHeader header;
@ -1690,7 +1703,7 @@ FileSystem::ManagedCFilePtr GameList::OpenMemoryCardTimestampCache(bool for_writ
if (errno != EACCES)
return nullptr;
Common::Timer timer;
Timer timer;
while (timer.GetTimeMilliseconds() <= 100.0f)
{
fp = FileSystem::OpenManagedSharedCFile(filename.c_str(), mode, share_mode, nullptr);

View File

@ -171,7 +171,39 @@ void GPU::UpdateResolutionScale()
std::tuple<u32, u32> GPU::GetFullDisplayResolution() const
{
return std::tie(m_crtc_state.display_width, m_crtc_state.display_height);
u32 width, height;
if (IsDisplayDisabled())
{
width = 0;
height = 0;
}
else
{
s32 xmin, xmax, ymin, ymax;
if (!m_GPUSTAT.pal_mode)
{
xmin = NTSC_HORIZONTAL_ACTIVE_START;
xmax = NTSC_HORIZONTAL_ACTIVE_END;
ymin = NTSC_VERTICAL_ACTIVE_START;
ymax = NTSC_VERTICAL_ACTIVE_END;
}
else
{
xmin = PAL_HORIZONTAL_ACTIVE_START;
xmax = PAL_HORIZONTAL_ACTIVE_END;
ymin = PAL_VERTICAL_ACTIVE_START;
ymax = PAL_VERTICAL_ACTIVE_END;
}
width = static_cast<u32>(std::max<s32>(std::clamp<s32>(m_crtc_state.regs.X2, xmin, xmax) -
std::clamp<s32>(m_crtc_state.regs.X1, xmin, xmax),
0) /
m_crtc_state.dot_clock_divider);
height = static_cast<u32>(std::max<s32>(
std::clamp<s32>(m_crtc_state.regs.Y2, ymin, ymax) - std::clamp<s32>(m_crtc_state.regs.Y1, ymin, ymax), 0));
}
return std::tie(width, height);
}
void GPU::Reset(bool clear_vram)
@ -629,7 +661,9 @@ float GPU::ComputeDisplayAspectRatio() const
float GPU::ComputeSourceAspectRatio() const
{
const float source_aspect_ratio =
static_cast<float>(m_crtc_state.display_width) / static_cast<float>(m_crtc_state.display_height);
(g_settings.debugging.show_vram ?
(static_cast<float>(VRAM_WIDTH) / static_cast<float>(VRAM_HEIGHT)) :
static_cast<float>(m_crtc_state.display_width) / static_cast<float>(m_crtc_state.display_height));
// Correction is applied to the GTE for stretch to fit, that way it fills the window.
const float source_aspect_ratio_correction =
@ -643,7 +677,8 @@ float GPU::ComputeAspectRatioCorrection() const
const CRTCState& cs = m_crtc_state;
float relative_width = static_cast<float>(cs.horizontal_visible_end - cs.horizontal_visible_start);
float relative_height = static_cast<float>(cs.vertical_visible_end - cs.vertical_visible_start);
if (relative_width <= 0 || relative_height <= 0 || g_settings.display_aspect_ratio == DisplayAspectRatio::PAR1_1 ||
if (relative_width <= 0 || relative_height <= 0 || g_settings.debugging.show_vram ||
g_settings.display_aspect_ratio == DisplayAspectRatio::PAR1_1 ||
g_settings.display_crop_mode == DisplayCropMode::OverscanUncorrected ||
g_settings.display_crop_mode == DisplayCropMode::BordersUncorrected)
{
@ -1550,32 +1585,31 @@ void GPU::HandleGetGPUInfoCommand(u32 value)
case 0x02: // Get Texture Window
{
DEBUG_LOG("Get texture window");
m_GPUREAD_latch = m_draw_mode.texture_window_value;
DEBUG_LOG("Get texture window => 0x{:08X}", m_GPUREAD_latch);
}
break;
case 0x03: // Get Draw Area Top Left
{
DEBUG_LOG("Get drawing area top left");
m_GPUREAD_latch =
((m_drawing_area.left & UINT32_C(0b1111111111)) | ((m_drawing_area.top & UINT32_C(0b1111111111)) << 10));
m_GPUREAD_latch = (m_drawing_area.left | (m_drawing_area.top << 10));
DEBUG_LOG("Get drawing area top left: ({}, {}) => 0x{:08X}", m_drawing_area.left, m_drawing_area.top,
m_GPUREAD_latch);
}
break;
case 0x04: // Get Draw Area Bottom Right
{
DEBUG_LOG("Get drawing area bottom right");
m_GPUREAD_latch =
((m_drawing_area.right & UINT32_C(0b1111111111)) | ((m_drawing_area.bottom & UINT32_C(0b1111111111)) << 10));
m_GPUREAD_latch = (m_drawing_area.right | (m_drawing_area.bottom << 10));
DEBUG_LOG("Get drawing area bottom right: ({}, {}) => 0x{:08X}", m_drawing_area.bottom, m_drawing_area.right,
m_GPUREAD_latch);
}
break;
case 0x05: // Get Drawing Offset
{
DEBUG_LOG("Get drawing offset");
m_GPUREAD_latch =
((m_drawing_offset.x & INT32_C(0b11111111111)) | ((m_drawing_offset.y & INT32_C(0b11111111111)) << 11));
m_GPUREAD_latch = (m_drawing_offset.x & 0x7FF) | ((m_drawing_offset.y & 0x7FF) << 11);
DEBUG_LOG("Get drawing offset: ({}, {}) => 0x{:08X}", m_drawing_offset.x, m_drawing_offset.y, m_GPUREAD_latch);
}
break;

View File

@ -9,7 +9,7 @@
#include "common/log.h"
#include "common/timer.h"
LOG_CHANNEL(GPUBackend);
LOG_CHANNEL(GPU);
std::unique_ptr<GPUBackend> g_gpu_backend;
@ -217,7 +217,7 @@ void GPUBackend::Sync(bool allow_sleep)
void GPUBackend::RunGPULoop()
{
static constexpr double SPIN_TIME_NS = 1 * 1000000;
Common::Timer::Value last_command_time = 0;
Timer::Value last_command_time = 0;
for (;;)
{
@ -225,8 +225,8 @@ void GPUBackend::RunGPULoop()
u32 read_ptr = m_command_fifo_read_ptr.load();
if (read_ptr == write_ptr)
{
const Common::Timer::Value current_time = Common::Timer::GetCurrentValue();
if (Common::Timer::ConvertValueToNanoseconds(current_time - last_command_time) < SPIN_TIME_NS)
const Timer::Value current_time = Timer::GetCurrentValue();
if (Timer::ConvertValueToNanoseconds(current_time - last_command_time) < SPIN_TIME_NS)
continue;
std::unique_lock<std::mutex> lock(m_sync_mutex);
@ -273,7 +273,7 @@ void GPUBackend::RunGPULoop()
}
}
last_command_time = allow_sleep ? 0 : Common::Timer::GetCurrentValue();
last_command_time = allow_sleep ? 0 : Timer::GetCurrentValue();
m_command_fifo_read_ptr.store(read_ptr);
}
}

View File

@ -25,6 +25,7 @@ public:
virtual ~GPUBackend();
ALWAYS_INLINE const Threading::Thread* GetThread() const { return m_use_gpu_thread ? &m_gpu_thread : nullptr; }
ALWAYS_INLINE bool IsUsingThread() const { return m_use_gpu_thread; }
virtual bool Initialize(bool use_thread);
virtual void Reset();

View File

@ -267,7 +267,7 @@ bool GPU::HandleSetDrawingAreaBottomRightCommand()
const u32 right = param & DRAWING_AREA_COORD_MASK;
const u32 bottom = (param >> 10) & DRAWING_AREA_COORD_MASK;
DEBUG_LOG("Set drawing area bottom-right: ({}, {})", m_drawing_area.right, m_drawing_area.bottom);
DEBUG_LOG("Set drawing area bottom-right: ({}, {})", right, bottom);
if (m_drawing_area.right != right || m_drawing_area.bottom != bottom)
{
FlushRender();
@ -288,7 +288,7 @@ bool GPU::HandleSetDrawingOffsetCommand()
const u32 param = FifoPop() & 0x00FFFFFFu;
const s32 x = SignExtendN<11, s32>(param & 0x7FFu);
const s32 y = SignExtendN<11, s32>((param >> 11) & 0x7FFu);
DEBUG_LOG("Set drawing offset ({}, {})", m_drawing_offset.x, m_drawing_offset.y);
DEBUG_LOG("Set drawing offset ({}, {})", x, y);
if (m_drawing_offset.x != x || m_drawing_offset.y != y)
{
FlushRender();

View File

@ -320,7 +320,7 @@ std::unique_ptr<GPUDump::Player> GPUDump::Player::Open(std::string path, Error*
{
std::unique_ptr<Player> ret;
Common::Timer timer;
Timer timer;
std::optional<DynamicHeapArray<u8>> data;
if (StringUtil::EndsWithNoCase(path, ".psxgpu.zst") || StringUtil::EndsWithNoCase(path, ".psxgpu.xz"))
@ -507,7 +507,7 @@ bool GPUDump::Player::FindFrameStarts(Error* error)
return false;
}
#ifdef _DEBUG
#if defined(_DEBUG) || defined(_DEVEL)
for (size_t i = 0; i < m_frame_offsets.size(); i++)
DEBUG_LOG("Frame {} starts at offset {}", i, m_frame_offsets[i]);
#endif

View File

@ -42,7 +42,7 @@ static constexpr GPUTexture::Format VRAM_DS_FORMAT = GPUTexture::Format::D16;
static constexpr GPUTexture::Format VRAM_DS_DEPTH_FORMAT = GPUTexture::Format::D32F;
static constexpr GPUTexture::Format VRAM_DS_COLOR_FORMAT = GPUTexture::Format::R32F;
#ifdef _DEBUG
#if defined(_DEBUG) || defined(_DEVEL)
static u32 s_draw_number = 0;
@ -152,8 +152,8 @@ class ShaderCompileProgressTracker
{
public:
ShaderCompileProgressTracker(std::string title, u32 total)
: m_title(std::move(title)), m_min_time(Common::Timer::ConvertSecondsToValue(1.0)),
m_update_interval(Common::Timer::ConvertSecondsToValue(0.1)), m_start_time(Common::Timer::GetCurrentValue()),
: m_title(std::move(title)), m_min_time(Timer::ConvertSecondsToValue(1.0)),
m_update_interval(Timer::ConvertSecondsToValue(0.1)), m_start_time(Timer::GetCurrentValue()),
m_last_update_time(0), m_progress(0), m_total(total)
{
}
@ -161,14 +161,14 @@ public:
double GetElapsedMilliseconds() const
{
return Common::Timer::ConvertValueToMilliseconds(Common::Timer::GetCurrentValue() - m_start_time);
return Timer::ConvertValueToMilliseconds(Timer::GetCurrentValue() - m_start_time);
}
void Increment(u32 progress = 1)
{
m_progress += progress;
const u64 tv = Common::Timer::GetCurrentValue();
const u64 tv = Timer::GetCurrentValue();
if ((tv - m_start_time) >= m_min_time && (tv - m_last_update_time) >= m_update_interval)
{
Host::DisplayLoadingScreen(m_title.c_str(), 0, static_cast<int>(m_total), static_cast<int>(m_progress));
@ -178,10 +178,10 @@ public:
private:
std::string m_title;
Common::Timer::Value m_min_time;
Common::Timer::Value m_update_interval;
Common::Timer::Value m_start_time;
Common::Timer::Value m_last_update_time;
Timer::Value m_min_time;
Timer::Value m_update_interval;
Timer::Value m_start_time;
Timer::Value m_last_update_time;
u32 m_progress;
u32 m_total;
};
@ -189,7 +189,7 @@ private:
GPU_HW::GPU_HW() : GPU()
{
#ifdef _DEBUG
#if defined(_DEBUG) || defined(_DEVEL)
s_draw_number = 0;
#endif
}
@ -1612,7 +1612,7 @@ bool GPU_HW::CompilePipelines(Error* error)
bool GPU_HW::CompileResolutionDependentPipelines(Error* error)
{
Common::Timer timer;
Timer timer;
m_vram_readback_pipeline.reset();
for (std::unique_ptr<GPUPipeline>& p : m_vram_extract_pipeline)
@ -3199,7 +3199,8 @@ void GPU_HW::FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color)
GL_SCOPE_FMT("FillVRAM({},{} => {},{} ({}x{}) with 0x{:08X}", x, y, x + width, y + height, width, height, color);
DeactivateROV();
if (m_sw_renderer)
const bool handle_with_tc = (m_use_texture_cache && !IsInterlacedRenderingEnabled());
if (m_sw_renderer && !handle_with_tc)
{
GPUBackendFillVRAMCommand* cmd = m_sw_renderer->NewFillVRAMCommand();
FillBackendCommandParameters(cmd);
@ -3216,7 +3217,7 @@ void GPU_HW::FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color)
const GSVector4i bounds = GetVRAMTransferBounds(x, y, width, height);
// If TC is enabled, we have to update local memory.
if (m_use_texture_cache && !IsInterlacedRenderingEnabled())
if (handle_with_tc)
{
AddWrittenRectangle(bounds);
GPU_SW_Rasterizer::FillVRAM(x, y, width, height, color, false, 0);
@ -3328,7 +3329,7 @@ void GPU_HW::UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* data, b
DebugAssert(bounds.right <= static_cast<s32>(VRAM_WIDTH) && bounds.bottom <= static_cast<s32>(VRAM_HEIGHT));
AddWrittenRectangle(bounds);
if (m_sw_renderer)
if (m_sw_renderer && m_sw_renderer->IsUsingThread())
{
const u32 num_words = width * height;
GPUBackendUpdateVRAMCommand* cmd = m_sw_renderer->NewUpdateVRAMCommand(num_words);
@ -3785,7 +3786,7 @@ void GPU_HW::FlushRender()
if (index_count == 0)
return;
#ifdef _DEBUG
#if defined(_DEBUG) || defined(_DEVEL)
GL_SCOPE_FMT("Hardware Draw {}: {}", ++s_draw_number, m_current_draw_rect);
#endif

View File

@ -37,7 +37,7 @@
#include <numeric>
#include <unordered_set>
LOG_CHANNEL(GPUTextureCache);
LOG_CHANNEL(GPU_HW);
#include "common/ryml_helpers.h"
@ -242,6 +242,7 @@ static bool ShouldTrackVRAMWrites();
static bool IsDumpingVRAMWriteTextures();
static void UpdateVRAMTrackingState();
static void SetHashCacheTextureFormat();
static bool CompilePipelines();
static void DestroyPipelines();
@ -280,11 +281,14 @@ static void RemoveVRAMWrite(VRAMWrite* entry);
static void DumpTexturesFromVRAMWrite(VRAMWrite* entry);
static void DumpTextureFromPage(const Source* src);
static void DecodeTexture(GPUTextureMode mode, const u16* page_ptr, const u16* palette, u32* dest, u32 dest_stride,
u32 width, u32 height);
static void DecodeTexture4(const u16* page, const u16* palette, u32 width, u32 height, u32* dest, u32 dest_stride);
static void DecodeTexture8(const u16* page, const u16* palette, u32 width, u32 height, u32* dest, u32 dest_stride);
static void DecodeTexture16(const u16* page, u32 width, u32 height, u32* dest, u32 dest_stride);
static void DecodeTexture(GPUTextureMode mode, const u16* page_ptr, const u16* palette, u8* dest, u32 dest_stride,
u32 width, u32 height, GPUTexture::Format dest_format);
template<GPUTexture::Format dest_format>
static void DecodeTexture4(const u16* page, const u16* palette, u32 width, u32 height, u8* dest, u32 dest_stride);
template<GPUTexture::Format dest_format>
static void DecodeTexture8(const u16* page, const u16* palette, u32 width, u32 height, u8* dest, u32 dest_stride);
template<GPUTexture::Format dest_format>
static void DecodeTexture16(const u16* page, u32 width, u32 height, u8* dest, u32 dest_stride);
static void DecodeTexture(u8 page, GPUTexturePaletteReg palette, GPUTextureMode mode, GPUTexture* texture);
static std::optional<TextureReplacementType> GetTextureReplacementTypeFromFileTitle(const std::string_view file_title);
@ -512,6 +516,7 @@ struct GPUTextureCacheState
VRAMWrite* last_vram_write = nullptr;
bool track_vram_writes = false;
GPUTexture::Format hash_cache_texture_format = GPUTexture::Format::Unknown;
HashCache hash_cache;
/// List of candidates for purging when the hash cache gets too large.
@ -568,6 +573,7 @@ bool GPUTextureCache::IsDumpingVRAMWriteTextures()
bool GPUTextureCache::Initialize()
{
SetHashCacheTextureFormat();
LoadLocalConfiguration(false, false);
UpdateVRAMTrackingState();
if (!CompilePipelines())
@ -770,6 +776,17 @@ void GPUTextureCache::Shutdown()
s_state.game_id = {};
}
void GPUTextureCache::SetHashCacheTextureFormat()
{
// Prefer 16-bit texture formats where possible.
if (g_gpu_device->SupportsTextureFormat(GPUTexture::Format::RGB5A1))
s_state.hash_cache_texture_format = GPUTexture::Format::RGB5A1;
else
s_state.hash_cache_texture_format = GPUTexture::Format::RGBA8;
INFO_LOG("Using {} format for hash cache entries.", GPUTexture::GetFormatName(s_state.hash_cache_texture_format));
}
bool GPUTextureCache::CompilePipelines()
{
if (!g_settings.texture_replacements.enable_texture_replacements)
@ -1063,29 +1080,116 @@ ALWAYS_INLINE_RELEASE static const u16* VRAMPalettePointer(GPUTexturePaletteReg
return &g_vram[VRAM_WIDTH * palette.GetYBase() + palette.GetXBase()];
}
// TODO: Vectorize these with gather.
void GPUTextureCache::DecodeTexture4(const u16* page, const u16* palette, u32 width, u32 height, u32* dest,
template<GPUTexture::Format format>
ALWAYS_INLINE static void WriteDecodedTexel(u8*& dest, u16 c16)
{
if constexpr (format == GPUTexture::Format::RGBA8)
{
const u32 c32 = VRAMRGBA5551ToRGBA8888(c16);
std::memcpy(std::assume_aligned<sizeof(c32)>(dest), &c32, sizeof(c32));
dest += sizeof(c32);
}
else if constexpr (format == GPUTexture::Format::RGB5A1)
{
const u16 repacked = (c16 & 0x83E0) | ((c16 >> 10) & 0x1F) | ((c16 & 0x1F) << 10);
std::memcpy(std::assume_aligned<sizeof(repacked)>(dest), &repacked, sizeof(repacked));
dest += sizeof(repacked);
}
}
#ifdef CPU_ARCH_SIMD
ALWAYS_INLINE static GSVector4i VRAM5BitTo8Bit(GSVector4i val)
{
return val.mul32l(GSVector4i::cxpr(527)).add32(GSVector4i::cxpr(23)).srl32<6>();
}
ALWAYS_INLINE static GSVector4i VRAMRGB5A1ToRGBA8888(GSVector4i val)
{
static constexpr GSVector4i cmask = GSVector4i::cxpr(0x1F);
const GSVector4i r = VRAM5BitTo8Bit(val & cmask);
const GSVector4i g = VRAM5BitTo8Bit((val.srl32<5>() & cmask));
const GSVector4i b = VRAM5BitTo8Bit((val.srl32<10>() & cmask));
const GSVector4i a = val.srl32<15>().sll32<31>().sra32<7>();
return r | g.sll32<8>() | b.sll32<16>() | b.sll32<24>() | a;
}
template<GPUTexture::Format format>
ALWAYS_INLINE static void WriteDecodedTexels(u8*& dest, GSVector4i c16)
{
if constexpr (format == GPUTexture::Format::RGBA8)
{
const GSVector4i low = VRAMRGB5A1ToRGBA8888(c16.upl16());
const GSVector4i high = VRAMRGB5A1ToRGBA8888(c16.uph16());
GSVector4i::store<false>(dest, low);
dest += sizeof(GSVector4i);
GSVector4i::store<false>(dest, high);
dest += sizeof(GSVector4i);
}
else if constexpr (format == GPUTexture::Format::RGB5A1)
{
static constexpr GSVector4i cmask = GSVector4i::cxpr16(0x1F);
const GSVector4i repacked =
(c16 & GSVector4i::cxpr16(static_cast<s16>(0x83E0))) | (c16.srl16<10>() & cmask) | (c16 & cmask).sll16<10>();
GSVector4i::store<false>(dest, repacked);
dest += sizeof(GSVector4i);
}
}
#endif
template<GPUTexture::Format format>
void GPUTextureCache::DecodeTexture4(const u16* page, const u16* palette, u32 width, u32 height, u8* dest,
u32 dest_stride)
{
if ((width % 4u) == 0)
{
const u32 vram_width = width / 4;
[[maybe_unused]] constexpr u32 vram_pixels_per_vec = 2;
[[maybe_unused]] const u32 aligned_vram_width = Common::AlignDownPow2(vram_width, vram_pixels_per_vec);
for (u32 y = 0; y < height; y++)
{
const u16* page_ptr = page;
u32* dest_ptr = dest;
u8* dest_ptr = dest;
u32 x = 0;
for (u32 x = 0; x < vram_width; x++)
#ifdef CPU_ARCH_SIMD
for (; x < aligned_vram_width; x += vram_pixels_per_vec)
{
// No variable shift without AVX, kinda pointless to vectorize the extract...
alignas(VECTOR_ALIGNMENT) u16 c16[vram_pixels_per_vec * 4];
u32 pp = *(page_ptr++);
c16[0] = palette[pp & 0x0F];
c16[1] = palette[(pp >> 4) & 0x0F];
c16[2] = palette[(pp >> 8) & 0x0F];
c16[3] = palette[pp >> 12];
pp = *(page_ptr++);
c16[4] = palette[pp & 0x0F];
c16[5] = palette[(pp >> 4) & 0x0F];
c16[6] = palette[(pp >> 8) & 0x0F];
c16[7] = palette[pp >> 12];
WriteDecodedTexels<format>(dest_ptr, GSVector4i::load<true>(c16));
}
#endif
for (; x < vram_width; x++)
{
const u32 pp = *(page_ptr++);
*(dest_ptr++) = VRAMRGBA5551ToRGBA8888(palette[pp & 0x0F]);
*(dest_ptr++) = VRAMRGBA5551ToRGBA8888(palette[(pp >> 4) & 0x0F]);
*(dest_ptr++) = VRAMRGBA5551ToRGBA8888(palette[(pp >> 8) & 0x0F]);
*(dest_ptr++) = VRAMRGBA5551ToRGBA8888(palette[pp >> 12]);
WriteDecodedTexel<format>(dest_ptr, palette[pp & 0x0F]);
WriteDecodedTexel<format>(dest_ptr, palette[(pp >> 4) & 0x0F]);
WriteDecodedTexel<format>(dest_ptr, palette[(pp >> 8) & 0x0F]);
WriteDecodedTexel<format>(dest_ptr, palette[pp >> 12]);
}
page += VRAM_WIDTH;
dest = reinterpret_cast<u32*>(reinterpret_cast<u8*>(dest) + dest_stride);
dest += dest_stride;
}
}
else
@ -1093,7 +1197,7 @@ void GPUTextureCache::DecodeTexture4(const u16* page, const u16* palette, u32 wi
for (u32 y = 0; y < height; y++)
{
const u16* page_ptr = page;
u32* dest_ptr = dest;
u8* dest_ptr = dest;
u32 offs = 0;
u16 texel = 0;
@ -1102,37 +1206,64 @@ void GPUTextureCache::DecodeTexture4(const u16* page, const u16* palette, u32 wi
if (offs == 0)
texel = *(page_ptr++);
*(dest_ptr++) = VRAMRGBA5551ToRGBA8888(palette[texel & 0x0F]);
WriteDecodedTexel<format>(dest_ptr, palette[texel & 0x0F]);
texel >>= 4;
offs = (offs + 1) % 4;
}
page += VRAM_WIDTH;
dest = reinterpret_cast<u32*>(reinterpret_cast<u8*>(dest) + dest_stride);
dest += dest_stride;
}
}
}
void GPUTextureCache::DecodeTexture8(const u16* page, const u16* palette, u32 width, u32 height, u32* dest,
template<GPUTexture::Format format>
void GPUTextureCache::DecodeTexture8(const u16* page, const u16* palette, u32 width, u32 height, u8* dest,
u32 dest_stride)
{
if ((width % 2u) == 0)
{
const u32 vram_width = width / 2;
[[maybe_unused]] constexpr u32 vram_pixels_per_vec = 4;
[[maybe_unused]] const u32 aligned_vram_width = Common::AlignDownPow2(vram_width, vram_pixels_per_vec);
for (u32 y = 0; y < height; y++)
{
const u16* page_ptr = page;
u32* dest_ptr = dest;
u8* dest_ptr = dest;
u32 x = 0;
for (u32 x = 0; x < vram_width; x++)
#ifdef CPU_ARCH_SIMD
for (; x < aligned_vram_width; x += vram_pixels_per_vec)
{
// No variable shift without AVX, kinda pointless to vectorize the extract...
alignas(VECTOR_ALIGNMENT) u16 c16[vram_pixels_per_vec * 2];
u32 pp = *(page_ptr++);
c16[0] = palette[pp & 0xFF];
c16[1] = palette[(pp >> 8) & 0xFF];
pp = *(page_ptr++);
c16[2] = palette[pp & 0xFF];
c16[3] = palette[(pp >> 8) & 0xFF];
pp = *(page_ptr++);
c16[4] = palette[pp & 0xFF];
c16[5] = palette[(pp >> 8) & 0xFF];
pp = *(page_ptr++);
c16[6] = palette[pp & 0xFF];
c16[7] = palette[(pp >> 8) & 0xFF];
WriteDecodedTexels<format>(dest_ptr, GSVector4i::load<true>(c16));
}
#endif
for (; x < vram_width; x++)
{
const u32 pp = *(page_ptr++);
*(dest_ptr++) = VRAMRGBA5551ToRGBA8888(palette[pp & 0xFF]);
*(dest_ptr++) = VRAMRGBA5551ToRGBA8888(palette[pp >> 8]);
WriteDecodedTexel<format>(dest_ptr, palette[pp & 0xFF]);
WriteDecodedTexel<format>(dest_ptr, palette[pp >> 8]);
}
page += VRAM_WIDTH;
dest = reinterpret_cast<u32*>(reinterpret_cast<u8*>(dest) + dest_stride);
dest += dest_stride;
}
}
else
@ -1140,7 +1271,7 @@ void GPUTextureCache::DecodeTexture8(const u16* page, const u16* palette, u32 wi
for (u32 y = 0; y < height; y++)
{
const u16* page_ptr = page;
u32* dest_ptr = dest;
u8* dest_ptr = dest;
u32 offs = 0;
u16 texel = 0;
@ -1149,70 +1280,110 @@ void GPUTextureCache::DecodeTexture8(const u16* page, const u16* palette, u32 wi
if (offs == 0)
texel = *(page_ptr++);
*(dest_ptr++) = VRAMRGBA5551ToRGBA8888(palette[texel & 0xFF]);
WriteDecodedTexel<format>(dest_ptr, palette[texel & 0xFF]);
texel >>= 8;
offs ^= 1;
}
page += VRAM_WIDTH;
dest = reinterpret_cast<u32*>(reinterpret_cast<u8*>(dest) + dest_stride);
dest += dest_stride;
}
}
}
void GPUTextureCache::DecodeTexture16(const u16* page, u32 width, u32 height, u32* dest, u32 dest_stride)
template<GPUTexture::Format format>
void GPUTextureCache::DecodeTexture16(const u16* page, u32 width, u32 height, u8* dest, u32 dest_stride)
{
[[maybe_unused]] constexpr u32 pixels_per_vec = 8;
[[maybe_unused]] const u32 aligned_width = Common::AlignDownPow2(width, pixels_per_vec);
for (u32 y = 0; y < height; y++)
{
const u16* page_ptr = page;
u32* dest_ptr = dest;
u8* dest_ptr = dest;
u32 x = 0;
for (u32 x = 0; x < width; x++)
*(dest_ptr++) = VRAMRGBA5551ToRGBA8888(*(page_ptr++));
#ifdef CPU_ARCH_SIMD
for (; x < aligned_width; x += pixels_per_vec)
{
WriteDecodedTexels<format>(dest_ptr, GSVector4i::load<false>(page_ptr));
page_ptr += pixels_per_vec;
}
#endif
for (; x < width; x++)
WriteDecodedTexel<format>(dest_ptr, *(page_ptr++));
page += VRAM_WIDTH;
dest = reinterpret_cast<u32*>(reinterpret_cast<u8*>(dest) + dest_stride);
dest += dest_stride;
}
}
void GPUTextureCache::DecodeTexture(GPUTextureMode mode, const u16* page_ptr, const u16* palette, u32* dest,
u32 dest_stride, u32 width, u32 height)
void GPUTextureCache::DecodeTexture(GPUTextureMode mode, const u16* page_ptr, const u16* palette, u8* dest,
u32 dest_stride, u32 width, u32 height, GPUTexture::Format dest_format)
{
switch (mode)
if (dest_format == GPUTexture::Format::RGBA8)
{
case GPUTextureMode::Palette4Bit:
DecodeTexture4(page_ptr, palette, width, height, dest, dest_stride);
break;
case GPUTextureMode::Palette8Bit:
DecodeTexture8(page_ptr, palette, width, height, dest, dest_stride);
break;
case GPUTextureMode::Direct16Bit:
case GPUTextureMode::Reserved_Direct16Bit:
DecodeTexture16(page_ptr, width, height, dest, dest_stride);
break;
switch (mode)
{
case GPUTextureMode::Palette4Bit:
DecodeTexture4<GPUTexture::Format::RGBA8>(page_ptr, palette, width, height, dest, dest_stride);
break;
case GPUTextureMode::Palette8Bit:
DecodeTexture8<GPUTexture::Format::RGBA8>(page_ptr, palette, width, height, dest, dest_stride);
break;
case GPUTextureMode::Direct16Bit:
case GPUTextureMode::Reserved_Direct16Bit:
DecodeTexture16<GPUTexture::Format::RGBA8>(page_ptr, width, height, dest, dest_stride);
break;
DefaultCaseIsUnreachable()
DefaultCaseIsUnreachable()
}
}
else if (dest_format == GPUTexture::Format::RGB5A1)
{
switch (mode)
{
case GPUTextureMode::Palette4Bit:
DecodeTexture4<GPUTexture::Format::RGB5A1>(page_ptr, palette, width, height, dest, dest_stride);
break;
case GPUTextureMode::Palette8Bit:
DecodeTexture8<GPUTexture::Format::RGB5A1>(page_ptr, palette, width, height, dest, dest_stride);
break;
case GPUTextureMode::Direct16Bit:
case GPUTextureMode::Reserved_Direct16Bit:
DecodeTexture16<GPUTexture::Format::RGB5A1>(page_ptr, width, height, dest, dest_stride);
break;
DefaultCaseIsUnreachable()
}
}
else
{
Panic("Unsupported texture format.");
}
}
void GPUTextureCache::DecodeTexture(u8 page, GPUTexturePaletteReg palette, GPUTextureMode mode, GPUTexture* texture)
{
alignas(16) static u32 s_temp_buffer[TEXTURE_PAGE_WIDTH * TEXTURE_PAGE_HEIGHT];
alignas(16) static u8 s_temp_buffer[TEXTURE_PAGE_WIDTH * TEXTURE_PAGE_HEIGHT * sizeof(u32)];
u32* tex_map;
const u32 ps = texture->GetPixelSize();
u8* tex_map;
u32 tex_stride;
const bool mapped =
texture->Map(reinterpret_cast<void**>(&tex_map), &tex_stride, 0, 0, TEXTURE_PAGE_WIDTH, TEXTURE_PAGE_HEIGHT);
if (!mapped)
{
tex_map = s_temp_buffer;
tex_stride = sizeof(u32) * TEXTURE_PAGE_WIDTH;
tex_stride = Common::AlignUpPow2(ps * TEXTURE_PAGE_WIDTH, 4);
}
const u16* page_ptr = VRAMPagePointer(page);
const u16* palette_ptr = TextureModeHasPalette(mode) ? VRAMPalettePointer(palette) : nullptr;
DecodeTexture(mode, page_ptr, palette_ptr, tex_map, tex_stride, TEXTURE_PAGE_WIDTH, TEXTURE_PAGE_HEIGHT);
DecodeTexture(mode, page_ptr, palette_ptr, tex_map, tex_stride, TEXTURE_PAGE_WIDTH, TEXTURE_PAGE_HEIGHT,
texture->GetFormat());
if (mapped)
texture->Unmap();
@ -1242,7 +1413,7 @@ const GPUTextureCache::Source* GPUTextureCache::LookupSource(SourceKey key, cons
const GPUTextureCache::Source* GPUTextureCache::ReturnSource(Source* source, const GSVector4i uv_rect,
PaletteRecordFlags flags)
{
#ifdef _DEBUG
#if defined(_DEBUG) || defined(_DEVEL)
// GL_INS_FMT("Tex hash: {:016X}", source->texture_hash);
// GL_INS_FMT("Palette hash: {:016X}", source->palette_hash);
if (!uv_rect.eq(INVALID_RECT))
@ -1300,7 +1471,7 @@ bool GPUTextureCache::IsRectDrawn(const GSVector4i rect)
bool GPUTextureCache::AreSourcePagesDrawn(SourceKey key, const GSVector4i rect)
{
// NOTE: This doesn't handle VRAM wrapping. But neither does the caller. YOLO?
#ifdef _DEBUG
#if defined(_DEBUG) || defined(_DEVEL)
{
for (u32 offset = 0; offset < TexturePageCountForMode(key.mode); offset++)
{
@ -1358,7 +1529,7 @@ void GPUTextureCache::Invalidate()
}
// should all be null
#ifdef _DEBUG
#if defined(_DEBUG) || defined(_DEVEL)
for (u32 i = 0; i < NUM_VRAM_PAGES; i++)
DebugAssert(!s_state.pages[i].sources.head && !s_state.pages[i].sources.tail);
DebugAssert(!s_state.last_vram_write);
@ -1787,7 +1958,7 @@ void GPUTextureCache::RemoveVRAMWrite(VRAMWrite* entry)
LoopRectPagesWithEarlyExit(entry->write_rect, [&entry, &other_write](u32 pn) {
PageEntry& pg = s_state.pages[pn];
ListIterateWithEarlyExit(pg.writes, [&entry, &other_write](VRAMWrite* cur) {
if (cur->hash != entry->hash)
if (cur == entry || cur->hash != entry->hash)
return true;
other_write = cur;
@ -2064,7 +2235,7 @@ GPUTextureCache::HashCacheEntry* GPUTextureCache::LookupHashCache(SourceKey key,
entry.sources = {};
entry.texture =
g_gpu_device->FetchTexture(TEXTURE_PAGE_WIDTH, TEXTURE_PAGE_HEIGHT, 1, 1, 1, GPUTexture::Type::Texture,
GPUTexture::Format::RGBA8, GPUTexture::Flags::None);
s_state.hash_cache_texture_format, GPUTexture::Flags::None);
if (!entry.texture)
{
ERROR_LOG("Failed to create texture.");
@ -2616,8 +2787,8 @@ void GPUTextureCache::DumpTexture(TextureReplacementType type, u32 offset_x, u32
DEV_LOG("Dumping VRAM write {:016X} [{}x{}] at {}", src_hash, width, height, rect);
Image image(width, height, ImageFormat::RGBA8);
GPUTextureCache::DecodeTexture(mode, &g_vram[rect.top * VRAM_WIDTH + rect.left], palette_data,
reinterpret_cast<u32*>(image.GetPixels()), image.GetPitch(), width, height);
GPUTextureCache::DecodeTexture(mode, &g_vram[rect.top * VRAM_WIDTH + rect.left], palette_data, image.GetPixels(),
image.GetPitch(), width, height, GPUTexture::Format::RGBA8);
// TODO: Vectorize this.
u32* image_pixels = reinterpret_cast<u32*>(image.GetPixels());
@ -3100,7 +3271,7 @@ void GPUTextureCache::PreloadReplacementTextures()
{
static constexpr float UPDATE_INTERVAL = 1.0f;
Common::Timer last_update_time;
Timer last_update_time;
u32 num_textures_loaded = 0;
const size_t total_textures = s_state.vram_replacements.size() + s_state.vram_write_texture_replacements.size() +
s_state.texture_page_texture_replacements.size();

View File

@ -16,7 +16,7 @@
#include <algorithm>
LOG_CHANNEL(GPU_SW);
LOG_CHANNEL(GPU);
GPU_SW::GPU_SW() = default;
@ -41,10 +41,10 @@ bool GPU_SW::Initialize(Error* error)
if (!GPU::Initialize(error) || !m_backend.Initialize(g_settings.gpu_use_thread))
return false;
static constexpr const std::array formats_for_16bit = {GPUTexture::Format::RGB565, GPUTexture::Format::RGBA5551,
static constexpr const std::array formats_for_16bit = {GPUTexture::Format::RGB565, GPUTexture::Format::RGB5A1,
GPUTexture::Format::RGBA8, GPUTexture::Format::BGRA8};
static constexpr const std::array formats_for_24bit = {GPUTexture::Format::RGBA8, GPUTexture::Format::BGRA8,
GPUTexture::Format::RGB565, GPUTexture::Format::RGBA5551};
GPUTexture::Format::RGB565, GPUTexture::Format::RGB5A1};
for (const GPUTexture::Format format : formats_for_16bit)
{
if (g_gpu_device->SupportsTextureFormat(format))
@ -115,7 +115,7 @@ template<GPUTexture::Format out_format, typename out_type>
static out_type VRAM16ToOutput(u16 value);
template<>
ALWAYS_INLINE u16 VRAM16ToOutput<GPUTexture::Format::RGBA5551, u16>(u16 value)
ALWAYS_INLINE u16 VRAM16ToOutput<GPUTexture::Format::RGB5A1, u16>(u16 value)
{
return (value & 0x3E0) | ((value >> 10) & 0x1F) | ((value & 0x1F) << 10);
}
@ -148,7 +148,7 @@ ALWAYS_INLINE u32 VRAM16ToOutput<GPUTexture::Format::BGRA8, u32>(u16 value)
}
template<>
ALWAYS_INLINE void CopyOutRow16<GPUTexture::Format::RGBA5551, u16>(const u16* src_ptr, u16* dst_ptr, u32 width)
ALWAYS_INLINE void CopyOutRow16<GPUTexture::Format::RGB5A1, u16>(const u16* src_ptr, u16* dst_ptr, u32 width)
{
u32 col = 0;
@ -167,7 +167,7 @@ ALWAYS_INLINE void CopyOutRow16<GPUTexture::Format::RGBA5551, u16>(const u16* sr
}
for (; col < width; col++)
*(dst_ptr++) = VRAM16ToOutput<GPUTexture::Format::RGBA5551, u16>(*(src_ptr++));
*(dst_ptr++) = VRAM16ToOutput<GPUTexture::Format::RGB5A1, u16>(*(src_ptr++));
}
template<>
@ -317,7 +317,7 @@ ALWAYS_INLINE_RELEASE bool GPU_SW::CopyOut24Bit(u32 src_x, u32 src_y, u32 skip_x
src_row_ptr += 3;
}
}
else if constexpr (display_format == GPUTexture::Format::RGBA5551)
else if constexpr (display_format == GPUTexture::Format::RGB5A1)
{
const u8* src_row_ptr = src_ptr;
u16* dst_row_ptr = reinterpret_cast<u16*>(dst_ptr);
@ -362,7 +362,7 @@ ALWAYS_INLINE_RELEASE bool GPU_SW::CopyOut24Bit(u32 src_x, u32 src_y, u32 skip_x
{
*(dst_row_ptr++) = ((rgb >> 3) & 0x1F) | (((rgb >> 10) << 5) & 0x7E0) | (((rgb >> 19) << 11) & 0x3E0000);
}
else if constexpr (display_format == GPUTexture::Format::RGBA5551)
else if constexpr (display_format == GPUTexture::Format::RGB5A1)
{
*(dst_row_ptr++) = ((rgb >> 3) & 0x1F) | (((rgb >> 11) << 5) & 0x3E0) | (((rgb >> 19) << 10) & 0x1F0000);
}
@ -389,8 +389,8 @@ bool GPU_SW::CopyOut(u32 src_x, u32 src_y, u32 skip_x, u32 width, u32 height, u3
switch (m_16bit_display_format)
{
case GPUTexture::Format::RGBA5551:
return CopyOut15Bit<GPUTexture::Format::RGBA5551>(src_x, src_y, width, height, line_skip);
case GPUTexture::Format::RGB5A1:
return CopyOut15Bit<GPUTexture::Format::RGB5A1>(src_x, src_y, width, height, line_skip);
case GPUTexture::Format::RGB565:
return CopyOut15Bit<GPUTexture::Format::RGB565>(src_x, src_y, width, height, line_skip);
@ -409,8 +409,8 @@ bool GPU_SW::CopyOut(u32 src_x, u32 src_y, u32 skip_x, u32 width, u32 height, u3
{
switch (m_24bit_display_format)
{
case GPUTexture::Format::RGBA5551:
return CopyOut24Bit<GPUTexture::Format::RGBA5551>(src_x, src_y, skip_x, width, height, line_skip);
case GPUTexture::Format::RGB5A1:
return CopyOut24Bit<GPUTexture::Format::RGB5A1>(src_x, src_y, skip_x, width, height, line_skip);
case GPUTexture::Format::RGB565:
return CopyOut24Bit<GPUTexture::Format::RGB565>(src_x, src_y, skip_x, width, height, line_skip);

View File

@ -10,7 +10,7 @@
#include "common/log.h"
#include "common/string_util.h"
LOG_CHANNEL(GPU_SW_Rasterizer);
LOG_CHANNEL(GPU_SW);
namespace GPU_SW_Rasterizer {
constinit const DitherLUT g_dither_lut = []() constexpr {

View File

@ -1639,8 +1639,6 @@ static void FillVRAMImpl(u32 x, u32 y, u32 width, u32 height, u32 color, bool in
static void WriteVRAMImpl(u32 x, u32 y, u32 width, u32 height, const void* data, bool set_mask, bool check_mask)
{
// TODO: Vector implementation
// Fast path when the copy is not oversized.
if ((x + width) <= VRAM_WIDTH && (y + height) <= VRAM_HEIGHT && !set_mask && !check_mask)
{
@ -1661,10 +1659,49 @@ static void WriteVRAMImpl(u32 x, u32 y, u32 width, u32 height, const void* data,
const u16 mask_and = check_mask ? 0x8000u : 0x0000u;
const u16 mask_or = set_mask ? 0x8000u : 0x0000u;
#ifdef USE_VECTOR
constexpr u32 write_pixels_per_vec = sizeof(GSVectorNi) / sizeof(u16);
const u32 aligned_width = Common::AlignDownPow2(std::min(width, VRAM_WIDTH - x), write_pixels_per_vec);
const GSVectorNi mask_or_vec = GSVectorNi::cxpr16(mask_or);
const GSVectorNi mask_and_vec = GSVectorNi::cxpr16(mask_and);
#endif
for (u32 row = 0; row < height;)
{
u16* dst_row_ptr = &g_vram[((y + row++) % VRAM_HEIGHT) * VRAM_WIDTH];
for (u32 col = 0; col < width;)
u32 col = 0;
#ifdef USE_VECTOR
// This doesn't do wraparound.
if (mask_and != 0)
{
for (; col < aligned_width; col += write_pixels_per_vec)
{
const GSVectorNi src = GSVectorNi::load<false>(src_ptr);
src_ptr += write_pixels_per_vec;
GSVectorNi dst = GSVectorNi::load<false>(&dst_row_ptr[x + col]);
const GSVectorNi mask = (dst & mask_and_vec).sra16<15>();
dst = (dst & mask) | src.andnot(mask) | mask_or_vec;
GSVectorNi::store<false>(&dst_row_ptr[x + col], dst);
}
}
else
{
for (; col < aligned_width; col += write_pixels_per_vec)
{
const GSVectorNi src = GSVectorNi::load<false>(src_ptr);
src_ptr += write_pixels_per_vec;
GSVectorNi::store<false>(&dst_row_ptr[x + col], src | mask_or_vec);
}
}
#endif
for (; col < width;)
{
// TODO: Handle unaligned reads...
u16* pixel_ptr = &dst_row_ptr[(x + col++) % VRAM_WIDTH];
@ -1678,8 +1715,6 @@ static void WriteVRAMImpl(u32 x, u32 y, u32 width, u32 height, const void* data,
static void CopyVRAMImpl(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32 height, bool set_mask,
bool check_mask)
{
// TODO: Vector implementation.
// Break up oversized copies. This behavior has not been verified on console.
if ((src_x + width) > VRAM_WIDTH || (dst_x + width) > VRAM_WIDTH)
{
@ -1698,8 +1733,8 @@ static void CopyVRAMImpl(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width,
{
const u32 columns_to_copy =
std::min<u32>(remaining_columns, std::min<u32>(VRAM_WIDTH - current_src_x, VRAM_WIDTH - current_dst_x));
CopyVRAM(current_src_x, current_src_y, current_dst_x, current_dst_y, columns_to_copy, rows_to_copy, set_mask,
check_mask);
CopyVRAMImpl(current_src_x, current_src_y, current_dst_x, current_dst_y, columns_to_copy, rows_to_copy,
set_mask, check_mask);
current_src_x = (current_src_x + columns_to_copy) % VRAM_WIDTH;
current_dst_x = (current_dst_x + columns_to_copy) % VRAM_WIDTH;
remaining_columns -= columns_to_copy;
@ -1735,12 +1770,47 @@ static void CopyVRAMImpl(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width,
}
else
{
#ifdef USE_VECTOR
constexpr u32 copy_pixels_per_vec = sizeof(GSVectorNi) / sizeof(u16);
const u32 aligned_width = Common::AlignDownPow2(
std::min(width, std::min<u32>(VRAM_WIDTH - src_x, VRAM_WIDTH - dst_x)), copy_pixels_per_vec);
const GSVectorNi mask_or_vec = GSVectorNi::cxpr16(mask_or);
const GSVectorNi mask_and_vec = GSVectorNi::cxpr16(mask_and);
#endif
for (u32 row = 0; row < height; row++)
{
const u16* src_row_ptr = &g_vram[((src_y + row) % VRAM_HEIGHT) * VRAM_WIDTH];
u16* dst_row_ptr = &g_vram[((dst_y + row) % VRAM_HEIGHT) * VRAM_WIDTH];
for (u32 col = 0; col < width; col++)
u32 col = 0;
#ifdef USE_VECTOR
// This doesn't do wraparound.
if (mask_and != 0)
{
for (; col < aligned_width; col += copy_pixels_per_vec)
{
const GSVectorNi src = GSVectorNi::load<false>(&src_row_ptr[src_x + col]);
GSVectorNi dst = GSVectorNi::load<false>(&dst_row_ptr[dst_x + col]);
const GSVectorNi mask = (dst & mask_and_vec).sra16<15>();
dst = (dst & mask) | src.andnot(mask) | mask_or_vec;
GSVectorNi::store<false>(&dst_row_ptr[dst_x + col], dst);
}
}
else
{
for (; col < aligned_width; col += copy_pixels_per_vec)
{
const GSVectorNi src = GSVectorNi::load<false>(&src_row_ptr[src_x + col]);
GSVectorNi::store<false>(&dst_row_ptr[dst_x + col], src | mask_or_vec);
}
}
#endif
for (; col < width; col++)
{
const u16 src_pixel = src_row_ptr[(src_x + col) % VRAM_WIDTH];
u16* dst_pixel_ptr = &dst_row_ptr[(dst_x + col) % VRAM_WIDTH];

View File

@ -11,6 +11,7 @@
#include "util/state_wrapper.h"
#include "common/assert.h"
#include "common/log.h"
#include "common/path.h"
#include "common/string_util.h"
@ -18,10 +19,7 @@
#include <array>
#ifdef _DEBUG
#include "common/log.h"
LOG_CHANNEL(GunCon);
#endif
LOG_CHANNEL(Controller);
static constexpr std::array<u8, static_cast<size_t>(GunCon::Binding::ButtonCount)> s_button_indices = {{13, 3, 14}};
@ -264,13 +262,9 @@ std::unique_ptr<GunCon> GunCon::Create(u32 index)
static const Controller::ControllerBindingInfo s_binding_info[] = {
#define BUTTON(name, display_name, icon_name, binding, genb) \
{ \
name, display_name, icon_name, static_cast<u32>(binding), InputBindingInfo::Type::Button, genb \
}
{name, display_name, icon_name, static_cast<u32>(binding), InputBindingInfo::Type::Button, genb}
#define HALFAXIS(name, display_name, icon_name, binding, genb) \
{ \
name, display_name, icon_name, static_cast<u32>(binding), InputBindingInfo::Type::HalfAxis, genb \
}
{name, display_name, icon_name, static_cast<u32>(binding), InputBindingInfo::Type::HalfAxis, genb}
// clang-format off
{"Pointer", TRANSLATE_NOOP("GunCon", "Pointer/Aiming"), ICON_PF_MOUSE, static_cast<u32>(GunCon::Binding::ButtonCount), InputBindingInfo::Type::Pointer, GenericInputBinding::Unknown},

View File

@ -28,7 +28,7 @@ public:
private:
void Redraw(bool force);
Common::Timer m_open_time;
Timer m_open_time;
float m_open_delay = 1.0f;
int m_last_progress_percent = -1;
};

View File

@ -17,6 +17,7 @@ struct InputBindingInfo
Motor,
Pointer, // Absolute pointer, does not receive any events, but is queryable.
RelativePointer, // Receive relative mouse movement events, bind_index is offset by the axis.
Device, // Used for special-purpose device selection, e.g. force feedback.
Macro,
};

View File

@ -51,7 +51,7 @@ void InterruptController::SetLineState(IRQ irq, bool state)
if (s_interrupt_line_state == prev_state)
return;
#ifdef _DEBUG
#if defined(_DEBUG) || defined(_DEVEL)
if (!(prev_state & bit) && state)
DEBUG_LOG("{} IRQ triggered", s_irq_names[static_cast<size_t>(irq)]);
else if ((prev_state & bit) && !state)
@ -84,7 +84,7 @@ void InterruptController::WriteRegister(u32 offset, u32 value)
{
case 0x00: // I_STATUS
{
#ifdef _DEBUG
#if defined(_DEBUG) || defined(_DEVEL)
const u32 cleared_bits = (s_interrupt_status_register & ~value);
for (u32 i = 0; i < static_cast<u32>(IRQ::MaxCount); i++)
{

638
src/core/jogcon.cpp Normal file
View File

@ -0,0 +1,638 @@
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
#include "jogcon.h"
#include "host.h"
#include "system.h"
#include "util/imgui_manager.h"
#include "util/input_manager.h"
#include "util/state_wrapper.h"
#include "common/assert.h"
#include "common/bitutils.h"
#include "common/error.h"
#include "common/log.h"
#include "IconsEmoji.h"
#include "IconsPromptFont.h"
#include "fmt/format.h"
LOG_CHANNEL(Controller);
JogCon::JogCon(u32 index) : Controller(index)
{
}
JogCon::~JogCon() = default;
ControllerType JogCon::GetType() const
{
return ControllerType::JogCon;
}
void JogCon::Reset()
{
// Reset starts in jogcon mode?
m_jogcon_mode = true;
ResetTransferState();
ResetMotorConfig();
}
bool JogCon::DoState(StateWrapper& sw, bool apply_input_state)
{
if (!Controller::DoState(sw, apply_input_state))
return false;
u16 button_state = m_button_state;
s8 steering_state = m_steering_state;
sw.Do(&button_state);
sw.Do(&steering_state);
if (apply_input_state)
{
m_button_state = button_state;
m_steering_state = steering_state;
}
sw.Do(&m_command);
sw.Do(&m_command_step);
sw.Do(&m_status_byte);
sw.Do(&m_last_steering_state);
sw.Do(&m_last_motor_command);
sw.Do(&m_steering_hold_position);
sw.Do(&m_steering_hold_strength);
sw.Do(&m_configuration_mode);
bool jogcon_mode = m_jogcon_mode;
sw.Do(&jogcon_mode);
if (jogcon_mode != m_jogcon_mode)
SetJogConMode(jogcon_mode, true);
sw.Do(&m_rx_buffer);
sw.Do(&m_tx_buffer);
sw.Do(&m_rumble_config);
return true;
}
float JogCon::GetBindState(u32 index) const
{
if (index >= static_cast<u32>(Button::MaxCount))
{
const u32 sub_index = index - static_cast<u32>(Button::MaxCount);
if (sub_index >= static_cast<u32>(m_half_axis_state.size()))
return 0.0f;
return static_cast<float>(m_half_axis_state[sub_index]) * (1.0f / 255.0f);
}
else if (index < static_cast<u32>(Button::Mode))
{
return static_cast<float>(((m_button_state >> index) & 1u) ^ 1u);
}
else
{
return 0.0f;
}
}
void JogCon::SetBindState(u32 index, float value)
{
if (index == static_cast<u32>(Button::Mode))
{
// analog toggle
if (value >= m_button_deadzone)
{
if (m_command == Command::Idle)
SetJogConMode(!m_jogcon_mode, true);
else
m_mode_toggle_queued = true;
}
return;
}
else if (index >= static_cast<u32>(Button::MaxCount))
{
const u32 sub_index = index - static_cast<u32>(Button::MaxCount);
if (sub_index >= static_cast<u32>(m_half_axis_state.size()))
return;
const u8 u8_value = static_cast<u8>(
std::clamp(((value < m_analog_deadzone) ? 0.0f : value) * m_analog_sensitivity * 255.0f, 0.0f, 255.0f));
if (u8_value == m_half_axis_state[sub_index])
return;
m_half_axis_state[sub_index] = u8_value;
System::SetRunaheadReplayFlag();
m_steering_state =
(m_half_axis_state[static_cast<u32>(HalfAxis::SteeringRight)] != 0) ?
static_cast<s8>((m_half_axis_state[static_cast<u32>(HalfAxis::SteeringRight)] / 2)) :
-static_cast<s8>((static_cast<u32>(m_half_axis_state[static_cast<u32>(HalfAxis::SteeringLeft)]) + 1) / 2);
}
const u16 bit = u16(1) << static_cast<u8>(index);
if (value >= m_button_deadzone)
{
if (m_button_state & bit)
System::SetRunaheadReplayFlag();
m_button_state &= ~(bit);
}
else
{
if (!(m_button_state & bit))
System::SetRunaheadReplayFlag();
m_button_state |= bit;
}
}
u32 JogCon::GetButtonStateBits() const
{
return m_button_state ^ 0xFFFF;
}
void JogCon::ResetTransferState()
{
if (m_mode_toggle_queued)
{
SetJogConMode(!m_jogcon_mode, true);
m_mode_toggle_queued = false;
}
m_command = Command::Idle;
m_command_step = 0;
}
u32 JogCon::GetInputOverlayIconColor() const
{
return m_jogcon_mode ? 0xFF2534F0u : 0xFFCCCCCCu;
}
void JogCon::SetJogConMode(bool enabled, bool show_message)
{
if (m_jogcon_mode == enabled)
return;
m_jogcon_mode = enabled;
m_configuration_mode = enabled && m_configuration_mode;
INFO_LOG("Controller {} switched to {} mode.", m_index + 1u, m_jogcon_mode ? "JogCon" : "Digital");
if (show_message)
{
Host::AddIconOSDMessage(
fmt::format("Controller{}JogConMode", m_index), ICON_PF_GAMEPAD_ALT,
m_jogcon_mode ? fmt::format(TRANSLATE_FS("Controller", "Controller {} switched to JogCon mode."), m_index + 1u) :
fmt::format(TRANSLATE_FS("Controller", "Controller {} switched to Digital mode."), m_index + 1u));
}
}
u8 JogCon::GetIDByte() const
{
return Truncate8((GetModeID() << 4) | GetResponseNumHalfwords());
}
u8 JogCon::GetModeID() const
{
if (m_configuration_mode)
return 0xF;
else if (m_jogcon_mode)
return 0xE;
else
return 0x4;
}
u8 JogCon::GetResponseNumHalfwords() const
{
return m_jogcon_mode ? 3 : 1;
}
void JogCon::SetMotorState(u8 value)
{
const u8 command = (value >> 4);
const u8 strength = (value & 0x0F);
DEV_LOG("0x{:02X} command=0x{:X} force={}", value, command, strength);
switch (command)
{
case MOTOR_COMMAND_STOP:
{
m_steering_hold_strength = 0;
SetMotorDirection(MOTOR_COMMAND_STOP, 0);
}
break;
case MOTOR_COMMAND_RIGHT:
case MOTOR_COMMAND_LEFT:
{
m_steering_hold_strength = 0;
SetMotorDirection(command, strength);
}
break;
case MOTOR_COMMAND_HOLD:
case MOTOR_COMMAND_DROP_REVOLUTIONS_AND_HOLD:
{
DEV_LOG("Hold wheel in position {} with {} strength.", m_steering_hold_position, strength);
m_steering_hold_strength = strength;
UpdateSteeringHold();
if (command == MOTOR_COMMAND_DROP_REVOLUTIONS_AND_HOLD)
ERROR_LOG("JogCon Drop revolutions and hold command is not handled.");
}
break;
case MOTOR_COMMAND_DROP_REVOLUTIONS:
{
ERROR_LOG("JogCon drop revolutions command is not handled.");
}
break;
case MOTOR_COMMAND_NEW_HOLD:
{
ERROR_LOG("JogCon new hold position {}", m_steering_state);
m_steering_hold_position = m_steering_state;
}
break;
default:
{
ERROR_LOG("Unknown JogCon command 0x{:X}", command);
}
break;
}
m_last_motor_command = command;
}
void JogCon::SetMotorDirection(u8 direction_command, u8 strength)
{
if (direction_command == MOTOR_COMMAND_STOP || strength == 0)
{
DEV_LOG("Stop motor");
if (m_force_feedback_device)
m_force_feedback_device->DisableForce(ForceFeedbackDevice::Effect::Constant);
InputManager::SetPadVibrationIntensity(m_index, 0.0f, 0.0f);
return;
}
DEV_LOG("Turn wheel {} with {} strength", (direction_command == MOTOR_COMMAND_LEFT) ? "LEFT" : "RIGHT", strength);
const float f_strength = (static_cast<float>(strength) / 15.0f);
if (m_force_feedback_device)
{
// 0->15 => -32768..32767, direction is flipped because it's indicating where the force is coming _from_.
const s32 ffb_value =
static_cast<s32>(f_strength * ((direction_command == MOTOR_COMMAND_LEFT) ? 32767.0f : -32768.0f));
m_force_feedback_device->SetConstantForce(ffb_value);
}
InputManager::SetPadVibrationIntensity(m_index, f_strength, 0.0f);
}
void JogCon::UpdateSteeringHold()
{
if (m_steering_hold_strength > 0)
{
const u8 direction_command =
(std::abs(static_cast<int>(m_steering_state) - static_cast<int>(m_steering_hold_position)) <
m_steering_hold_deadzone) ?
MOTOR_COMMAND_STOP :
((m_steering_state < m_steering_hold_position) ? MOTOR_COMMAND_RIGHT : MOTOR_COMMAND_LEFT);
DEV_LOG("Hold strength {} pos {} hold {} dir {}", m_steering_hold_strength, m_steering_state,
m_steering_hold_position, direction_command);
SetMotorDirection(direction_command, m_steering_hold_strength);
}
}
void JogCon::ResetMotorConfig()
{
m_rumble_config.fill(0xFF);
SetMotorState(0);
}
void JogCon::Poll()
{
m_tx_buffer[2] = Truncate8(m_button_state);
m_tx_buffer[3] = Truncate8(m_button_state >> 8);
m_tx_buffer[4] = Truncate8(m_steering_state);
m_tx_buffer[5] = Truncate8(m_steering_state >> 8); // 0xFF if negative, otherwise 0x00
u8 rotation_state = 0;
if (m_steering_state > m_last_steering_state)
rotation_state = 1;
else if (m_steering_state < m_last_steering_state)
rotation_state = 2;
m_tx_buffer[6] = rotation_state | (m_last_motor_command << 4);
m_last_steering_state = m_steering_state;
UpdateSteeringHold();
}
bool JogCon::Transfer(const u8 data_in, u8* data_out)
{
bool ack;
m_rx_buffer[m_command_step] = data_in;
switch (m_command)
{
case Command::Idle:
{
*data_out = 0xFF;
if (data_in == 0x01)
{
DEBUG_LOG("ACK controller access");
m_command = Command::Ready;
m_tx_buffer.fill(0);
m_rx_buffer.fill(0);
return true;
}
return false;
}
break;
case Command::Ready:
{
Assert(m_command_step == 0);
if (data_in == 0x42)
{
m_response_length = (GetResponseNumHalfwords() + 1) * 2;
m_command = Command::ReadPad;
m_tx_buffer = {GetIDByte(), m_status_byte, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
Poll();
}
else if (m_jogcon_mode && data_in == 0x43)
{
m_response_length = (GetResponseNumHalfwords() + 1) * 2;
m_command = Command::SetMode;
m_tx_buffer = {GetIDByte(), m_status_byte, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
Poll();
}
else if (m_configuration_mode && data_in == 0x45)
{
m_response_length = (GetResponseNumHalfwords() + 1) * 2;
m_command = Command::GetAnalogMode;
m_tx_buffer = {GetIDByte(), m_status_byte, 0x01, 0x02, BoolToUInt8(m_jogcon_mode), 0x01, 0x01, 0x00};
}
else if (m_configuration_mode && data_in == 0x46)
{
m_response_length = (GetResponseNumHalfwords() + 1) * 2;
m_command = Command::Command46;
m_tx_buffer = {GetIDByte(), m_status_byte, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
}
else if (m_configuration_mode && data_in == 0x47)
{
m_response_length = (GetResponseNumHalfwords() + 1) * 2;
m_command = Command::Command47;
m_tx_buffer = {GetIDByte(), m_status_byte, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00};
}
else if (m_configuration_mode && data_in == 0x4C)
{
m_response_length = (GetResponseNumHalfwords() + 1) * 2;
m_command = Command::Command4C;
m_tx_buffer = {GetIDByte(), m_status_byte, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
}
else if (m_configuration_mode && data_in == 0x4D)
{
m_response_length = (GetResponseNumHalfwords() + 1) * 2;
m_command = Command::GetSetRumble;
m_tx_buffer = {GetIDByte(), m_status_byte, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
}
else
{
ERROR_LOG("Unimplemented command 0x{:02X}", data_in);
*data_out = 0xFF;
return false;
}
}
break;
case Command::ReadPad:
{
if (m_command_step >= 2 && m_command_step < 7 && m_rumble_config[m_command_step - 2] == 0x00)
SetMotorState(data_in);
}
break;
case Command::GetAnalogMode:
{
// just send the byte, nothing special to do here
}
break;
case Command::SetMode:
{
m_configuration_mode = (m_rx_buffer[2] == 1 && m_jogcon_mode);
if (m_configuration_mode)
m_status_byte = 0x5A;
DEV_LOG("0x{:02x}({}) config mode", m_rx_buffer[2], m_configuration_mode ? "enter" : "leave");
}
break;
case Command::GetSetRumble:
{
if (m_command_step >= 2 && m_command_step < 7)
{
const u8 index = m_command_step - 2;
if (index >= 0)
{
m_tx_buffer[m_command_step] = m_rumble_config[index];
m_rumble_config[index] = data_in;
if (data_in == 0x00)
WARNING_LOG("Motor mapped to byte index {}", index);
}
}
else
{
// reset motor value if we're no longer mapping it
if (std::find(m_rumble_config.begin(), m_rumble_config.end(), 0) == m_rumble_config.end())
SetMotorState(0);
}
}
break;
case Command::Command46:
{
if (m_command_step == 2)
{
if (data_in == 0x00)
{
m_tx_buffer[4] = 0x01;
m_tx_buffer[5] = 0x02;
m_tx_buffer[6] = 0x00;
m_tx_buffer[7] = 0x0A;
}
else if (data_in == 0x01)
{
m_tx_buffer[4] = 0x01;
m_tx_buffer[5] = 0x01;
m_tx_buffer[6] = 0x01;
m_tx_buffer[7] = 0x14;
}
}
}
break;
case Command::Command47:
{
if (m_command_step == 2 && data_in != 0x00)
{
m_tx_buffer[4] = 0x00;
m_tx_buffer[5] = 0x00;
m_tx_buffer[6] = 0x00;
m_tx_buffer[7] = 0x00;
}
}
break;
case Command::Command4C:
{
if (m_command_step == 2)
{
if (data_in == 0x00)
m_tx_buffer[5] = 0x04;
else if (data_in == 0x01)
m_tx_buffer[4] = 0x03;
}
}
break;
DefaultCaseIsUnreachable();
}
*data_out = m_tx_buffer[m_command_step];
m_command_step = (m_command_step + 1) % m_response_length;
ack = (m_command_step != 0);
if (m_command_step == 0)
{
m_command = Command::Idle;
DEBUG_LOG("Rx: {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x}", m_rx_buffer[0], m_rx_buffer[1],
m_rx_buffer[2], m_rx_buffer[3], m_rx_buffer[4], m_rx_buffer[5], m_rx_buffer[6], m_rx_buffer[7]);
DEBUG_LOG("Tx: {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x}", m_tx_buffer[0], m_tx_buffer[1],
m_tx_buffer[2], m_tx_buffer[3], m_tx_buffer[4], m_tx_buffer[5], m_tx_buffer[6], m_tx_buffer[7]);
}
return ack;
}
void JogCon::LoadSettings(const SettingsInterface& si, const char* section, bool initial)
{
Controller::LoadSettings(si, section, initial);
m_analog_deadzone = std::clamp(si.GetFloatValue(section, "AnalogDeadzone", DEFAULT_STICK_DEADZONE), 0.0f, 1.0f);
m_analog_sensitivity =
std::clamp(si.GetFloatValue(section, "AnalogSensitivity", DEFAULT_STICK_SENSITIVITY), 0.01f, 3.0f);
m_button_deadzone = std::clamp(si.GetFloatValue(section, "ButtonDeadzone", DEFAULT_BUTTON_DEADZONE), 0.01f, 1.0f);
m_steering_hold_deadzone = static_cast<s8>(std::ceil(
std::clamp(si.GetFloatValue(section, "SteeringHoldDeadzone", DEFAULT_STEERING_HOLD_DEADZONE), 0.0f, 1.0f) *
127.0f));
std::string force_feedback_device_name = si.GetStringValue(section, "ForceFeedbackDevice");
if (m_force_feedback_device_name != force_feedback_device_name)
{
m_force_feedback_device_name = std::move(force_feedback_device_name);
m_force_feedback_device.reset();
if (!m_force_feedback_device_name.empty())
{
Error error;
m_force_feedback_device = InputManager::CreateForceFeedbackDevice(m_force_feedback_device_name, &error);
if (!m_force_feedback_device)
{
ERROR_LOG("Failed to create force feedback device: {}", error.GetDescription());
if (initial)
{
Host::AddIconOSDWarning(
fmt::format("NoFFDevice{}", m_index), ICON_EMOJI_WARNING,
fmt::format(TRANSLATE_FS("JogCon", "Failed to create force feedback device for Port {}:\n{}"),
Controller::GetPortDisplayName(m_index), error.GetDescription()),
Host::OSD_WARNING_DURATION);
}
}
}
}
}
std::unique_ptr<JogCon> JogCon::Create(u32 index)
{
return std::make_unique<JogCon>(index);
}
static const Controller::ControllerBindingInfo s_binding_info[] = {
#define BUTTON(name, display_name, icon_name, button, genb) \
{name, display_name, icon_name, static_cast<u32>(button), InputBindingInfo::Type::Button, genb}
#define AXIS(name, display_name, icon_name, halfaxis, genb) \
{name, \
display_name, \
icon_name, \
static_cast<u32>(JogCon::Button::MaxCount) + static_cast<u32>(halfaxis), \
InputBindingInfo::Type::HalfAxis, \
genb}
// clang-format off
BUTTON("Up", TRANSLATE_NOOP("JogCon", "D-Pad Up"), ICON_PF_DPAD_UP, JogCon::Button::Up, GenericInputBinding::DPadUp),
BUTTON("Right", TRANSLATE_NOOP("JogCon", "D-Pad Right"), ICON_PF_DPAD_RIGHT, JogCon::Button::Right, GenericInputBinding::DPadRight),
BUTTON("Down", TRANSLATE_NOOP("JogCon", "D-Pad Down"), ICON_PF_DPAD_DOWN, JogCon::Button::Down, GenericInputBinding::DPadDown),
BUTTON("Left", TRANSLATE_NOOP("JogCon", "D-Pad Left"), ICON_PF_DPAD_LEFT, JogCon::Button::Left, GenericInputBinding::DPadLeft),
BUTTON("Triangle", TRANSLATE_NOOP("JogCon", "Triangle"), ICON_PF_BUTTON_TRIANGLE, JogCon::Button::Triangle, GenericInputBinding::Triangle),
BUTTON("Circle", TRANSLATE_NOOP("JogCon", "Circle"), ICON_PF_BUTTON_CIRCLE, JogCon::Button::Circle, GenericInputBinding::Circle),
BUTTON("Cross", TRANSLATE_NOOP("JogCon", "Cross"), ICON_PF_BUTTON_CROSS, JogCon::Button::Cross, GenericInputBinding::Cross),
BUTTON("Square", TRANSLATE_NOOP("JogCon", "Square"), ICON_PF_BUTTON_SQUARE, JogCon::Button::Square, GenericInputBinding::Square),
BUTTON("Select", TRANSLATE_NOOP("JogCon", "Select"), ICON_PF_SELECT_SHARE, JogCon::Button::Select, GenericInputBinding::Select),
BUTTON("Start", TRANSLATE_NOOP("JogCon", "Start"), ICON_PF_START, JogCon::Button::Start, GenericInputBinding::Start),
BUTTON("L1", TRANSLATE_NOOP("JogCon", "L1"), ICON_PF_LEFT_SHOULDER_L1, JogCon::Button::L1, GenericInputBinding::L1),
BUTTON("R1", TRANSLATE_NOOP("JogCon", "R1"), ICON_PF_RIGHT_SHOULDER_R1, JogCon::Button::R1, GenericInputBinding::R1),
BUTTON("L2", TRANSLATE_NOOP("JogCon", "L2"), ICON_PF_LEFT_TRIGGER_L2, JogCon::Button::L2, GenericInputBinding::L2),
BUTTON("R2", TRANSLATE_NOOP("JogCon", "R2"), ICON_PF_RIGHT_TRIGGER_R2, JogCon::Button::R2, GenericInputBinding::R2),
BUTTON("Mode", TRANSLATE_NOOP("JogCon", "Mode"), ICON_PF_ANALOG_LEFT_RIGHT, JogCon::Button::Mode, GenericInputBinding::System),
AXIS("SteeringLeft", TRANSLATE_NOOP("JogCon", "Steering Left"), ICON_PF_ANALOG_LEFT, JogCon::HalfAxis::SteeringLeft, GenericInputBinding::LeftStickLeft),
AXIS("SteeringRight", TRANSLATE_NOOP("JogCon", "Steering Right"), ICON_PF_ANALOG_RIGHT, JogCon::HalfAxis::SteeringRight, GenericInputBinding::LeftStickRight),
// clang-format on
{"ForceFeedbackDevice", TRANSLATE_NOOP("JogCon", "Force Feedback Device"), nullptr,
static_cast<u32>(JogCon::Button::MaxCount) + static_cast<u32>(JogCon::HalfAxis::MaxCount),
InputBindingInfo::Type::Device, GenericInputBinding::Unknown},
#undef BUTTON
#undef AXIS
};
static const SettingInfo s_settings[] = {
{SettingInfo::Type::Float, "AnalogDeadzone", TRANSLATE_NOOP("JogCon", "Analog Deadzone"),
TRANSLATE_NOOP("JogCon",
"Sets the analog stick deadzone, i.e. the fraction of the stick movement which will be ignored."),
"0.00f", "0.00f", "1.00f", "0.01f", "%.0f%%", nullptr, 100.0f},
{SettingInfo::Type::Float, "AnalogSensitivity", TRANSLATE_NOOP("JogCon", "Analog Sensitivity"),
TRANSLATE_NOOP("JogCon", "Sets the analog stick axis scaling factor. A value between 130% and 140% is recommended "
"when using recent controllers, e.g. DualShock 4, Xbox One Controller."),
"1.33f", "0.01f", "2.00f", "0.01f", "%.0f%%", nullptr, 100.0f},
{SettingInfo::Type::Float, "ButtonDeadzone", TRANSLATE_NOOP("JogCon", "Button/Trigger Deadzone"),
TRANSLATE_NOOP(
"JogCon",
"Sets the deadzone for activating buttons/triggers, i.e. the fraction of the trigger which will be ignored."),
"0.25", "0.01", "1.00", "0.01", "%.0f%%", nullptr, 100.0f},
{SettingInfo::Type::Float, "SteeringHoldDeadzone", TRANSLATE_NOOP("JogCon", "Steering Hold Deadzone"),
TRANSLATE_NOOP(
"JogCon", "Sets the deadzone for holding the wheel at the set position, i.e. when it will not trigger an effect."),
"0.03", "0.01", "1.00", "0.01", "%.0f%%", nullptr, 100.0f},
};
const Controller::ControllerInfo JogCon::INFO = {
ControllerType::JogCon, "JogCon", TRANSLATE_NOOP("ControllerType", "JogCon"), ICON_PF_STEERING_WHEEL,
s_binding_info, s_settings, Controller::VibrationCapabilities::SingleMotor};

150
src/core/jogcon.h Normal file
View File

@ -0,0 +1,150 @@
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
#pragma once
#include "controller.h"
#include <memory>
class ForceFeedbackDevice;
class JogCon final : public Controller
{
public:
enum class Button : u8
{
Select = 0,
L3 = 1,
R3 = 2,
Start = 3,
Up = 4,
Right = 5,
Down = 6,
Left = 7,
L2 = 8,
R2 = 9,
L1 = 10,
R1 = 11,
Triangle = 12,
Circle = 13,
Cross = 14,
Square = 15,
Mode = 16,
MaxCount
};
enum class HalfAxis : u8
{
SteeringLeft,
SteeringRight,
MaxCount,
};
static const Controller::ControllerInfo INFO;
JogCon(u32 index);
~JogCon() override;
static std::unique_ptr<JogCon> Create(u32 index);
ControllerType GetType() const override;
void Reset() override;
bool DoState(StateWrapper& sw, bool apply_input_state) override;
float GetBindState(u32 index) const override;
void SetBindState(u32 index, float value) override;
u32 GetButtonStateBits() const override;
u32 GetInputOverlayIconColor() const override;
void ResetTransferState() override;
bool Transfer(const u8 data_in, u8* data_out) override;
void LoadSettings(const SettingsInterface& si, const char* section, bool initial) override;
private:
enum class Command : u8
{
Idle,
Ready,
ReadPad,
SetMode,
GetAnalogMode,
GetSetRumble,
Command46,
Command47,
Command4C,
};
enum : u8
{
LargeMotor = 0,
SmallMotor = 1
};
enum : u8
{
MOTOR_COMMAND_STOP = 0x0,
MOTOR_COMMAND_RIGHT = 0x1,
MOTOR_COMMAND_LEFT = 0x2,
MOTOR_COMMAND_HOLD = 0x3,
MOTOR_COMMAND_DROP_REVOLUTIONS = 0x8,
MOTOR_COMMAND_DROP_REVOLUTIONS_AND_HOLD = 0xB,
MOTOR_COMMAND_NEW_HOLD = 0xC,
};
static constexpr float DEFAULT_STEERING_HOLD_DEADZONE = 0.03f;
u8 GetIDByte() const;
u8 GetModeID() const;
// Get number of response halfwords (excluding the initial controller info halfword)
u8 GetResponseNumHalfwords() const;
void Poll();
void UpdateSteeringHold();
void SetMotorState(u8 value);
void SetMotorDirection(u8 direction_command, u8 strength);
void ResetMotorConfig();
void SetJogConMode(bool enabled, bool show_message);
// buttons are active low
u16 m_button_state = UINT16_C(0xFFFF);
s8 m_steering_state = 0;
// both directions of axis state, merged to m_steering_state
std::array<u8, static_cast<u32>(HalfAxis::MaxCount)> m_half_axis_state{};
Command m_command = Command::Idle;
u8 m_command_step = 0;
u8 m_response_length = 0;
u8 m_status_byte = 0x5A;
s8 m_last_steering_state = 0;
u8 m_last_motor_command = 0;
s8 m_steering_hold_position = 0;
u8 m_steering_hold_strength = 0;
bool m_configuration_mode = false;
bool m_jogcon_mode = false;
bool m_mode_toggle_queued = false;
std::array<u8, 6> m_rumble_config{};
// Transmit and receive buffers, not including the first Hi-Z/ack response byte
static constexpr u32 MAX_RESPONSE_LENGTH = 8;
std::array<u8, MAX_RESPONSE_LENGTH> m_rx_buffer;
std::array<u8, MAX_RESPONSE_LENGTH> m_tx_buffer;
s8 m_steering_hold_deadzone = 0;
float m_analog_deadzone = 0.0f;
float m_analog_sensitivity = 1.33f;
float m_button_deadzone = 0.0f;
std::string m_force_feedback_device_name;
std::unique_ptr<ForceFeedbackDevice> m_force_feedback_device;
};

View File

@ -19,7 +19,7 @@
#include "IconsPromptFont.h"
#include <array>
LOG_CHANNEL(Justifier);
LOG_CHANNEL(Controller);
// #define CHECK_TIMING 1
#ifdef CHECK_TIMING

View File

@ -88,7 +88,7 @@ void MemoryCard::ResetTransferState()
bool MemoryCard::Transfer(const u8 data_in, u8* data_out)
{
bool ack = false;
#ifdef _DEBUG
#if defined(_DEBUG) || defined(_DEVEL)
const State old_state = m_state;
#endif

View File

@ -23,7 +23,7 @@
#include <cmath>
LOG_CHANNEL(NeGconRumble);
LOG_CHANNEL(Controller);
// Mapping of Button to index of corresponding bit in m_button_state
static constexpr std::array<u8, static_cast<size_t>(NeGconRumble::Button::Count)> s_button_indices = {3, 4, 5, 6,

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