Merge branch 'master' into jtg/libavdevice-camera-driver

This commit is contained in:
Jesse Talavera 2024-11-30 16:37:54 -05:00
commit 9c82e9304b
1035 changed files with 284355 additions and 103554 deletions

View File

@ -9,6 +9,9 @@ on:
permissions:
contents: read
env:
ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true
jobs:
build:
runs-on: ubuntu-latest
@ -17,7 +20,7 @@ jobs:
options: --user root
steps:
- uses: actions/checkout@v3
- uses: taiki-e/checkout-action@v1
- name: Compile Salamander
run: |
@ -31,9 +34,3 @@ jobs:
- name: Get short SHA
id: slug
run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)"
- uses: actions/upload-artifact@v3
with:
name: RA-3DS-dummy-${{ steps.slug.outputs.sha8 }}
path: |
retroarch_3ds.cia

View File

@ -1,34 +1,39 @@
name: CI Android
on:
push:
pull_request:
repository_dispatch:
types: [run_build]
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Compile RA
run: |
cd pkg/android/phoenix
./gradlew assembleDebug
find . -iname "*.apk" -exec ls -l "{}" \;
- name: Get short SHA
id: slug
run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)"
- uses: actions/upload-artifact@v3
with:
name: retroarch-android-${{ steps.slug.outputs.sha8 }}
path: |
pkg/android/phoenix/build/outputs/apk/normal/debug/phoenix-normal-debug.apk
pkg/android/phoenix/build/outputs/apk/aarch64/debug/phoenix-aarch64-debug.apk
name: CI Android
on:
push:
pull_request:
workflow_dispatch:
repository_dispatch:
types: [run_build]
permissions:
contents: read
env:
ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Compile RA
run: |
cd pkg/android/phoenix
./gradlew assembleDebug
find . -iname "*.apk" -exec ls -l "{}" \;
- name: Get short SHA
id: slug
run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)"
- uses: actions/upload-artifact@v3
with:
name: retroarch-android-${{ steps.slug.outputs.sha8 }}
path: |
pkg/android/phoenix/build/outputs/apk/normal/debug/phoenix-normal-debug.apk
pkg/android/phoenix/build/outputs/apk/aarch64/debug/phoenix-aarch64-debug.apk

View File

@ -9,16 +9,19 @@ on:
permissions:
contents: read
env:
ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true
jobs:
build:
runs-on: ubuntu-latest
container:
container:
image: git.libretro.com:5050/libretro-infrastructure/libretro-djgpp-build-container:latest
options: --user root
steps:
- uses: actions/checkout@v3
- name: Compile RA
run: |
make -f Makefile.dos -j$(getconf _NPROCESSORS_ONLN) clean
@ -27,7 +30,7 @@ jobs:
- name: Get short SHA
id: slug
run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)"
- uses: actions/upload-artifact@v3
with:
name: RA-DOS-dummy-${{ steps.slug.outputs.sha8 }}

View File

@ -9,16 +9,19 @@ on:
permissions:
contents: read
env:
ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true
jobs:
build:
runs-on: ubuntu-latest
container:
container:
image: git.libretro.com:5050/libretro-infrastructure/libretro-build-emscripten:latest
options: --user root
steps:
- uses: actions/checkout@v3
- uses: taiki-e/checkout-action@v1
- name: Compile RA
run: |
emmake make -f Makefile.emscripten -j$(getconf _NPROCESSORS_ONLN) clean
@ -27,9 +30,4 @@ jobs:
- name: Get short SHA
id: slug
run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)"
- uses: actions/upload-artifact@v3
with:
name: RA-Emscripten-dummy-${{ steps.slug.outputs.sha8 }}
path: |
retroarch.js

View File

@ -9,16 +9,19 @@ on:
permissions:
contents: read
env:
ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true
jobs:
build:
runs-on: ubuntu-latest
container:
container:
image: git.libretro.com:5050/libretro-infrastructure/libretro-build-devkitpro:latest
options: --user root
steps:
- uses: actions/checkout@v3
- uses: taiki-e/checkout-action@v1
- name: Compile RA
run: |
make -f Makefile.ngc -j$(getconf _NPROCESSORS_ONLN) clean
@ -26,9 +29,4 @@ jobs:
- name: Get short SHA
id: slug
run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)"
- uses: actions/upload-artifact@v3
with:
name: RA-GameCube-dummy-${{ steps.slug.outputs.sha8 }}
path: |
retroarch_ngc.dol

37
.github/workflows/Linux.yml vendored Normal file
View File

@ -0,0 +1,37 @@
name: CI Linux (i686)
on:
push:
pull_request:
repository_dispatch:
types: [run_build]
permissions:
contents: read
env:
ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true
jobs:
build:
runs-on: ubuntu-latest
container:
image: git.libretro.com:5050/libretro-infrastructure/libretro-build-i386-ubuntu:xenial-gcc9
options: --user root
steps:
- name: Check Out Repo
uses: taiki-e/checkout-action@v1
- name: Configure Build
run: |
./configure --disable-qt --enable-xdelta
- name: Compile RA
run: |
make -j$(getconf _NPROCESSORS_ONLN) clean
make -j$(getconf _NPROCESSORS_ONLN)
- name: Get short SHA
id: slug
run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)"

View File

@ -9,63 +9,50 @@ on:
permissions:
contents: read
env:
ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true
# These jobs run smoke tests to ensure that MSVC-specific builds work properly.
jobs:
uwp:
msvc:
runs-on: windows-2022
strategy:
matrix:
version: [UWP, 2019, 2022]
configuration: [Debug, Release]
platform: [x64]
exclude:
- version: UWP
configuration: Debug
include:
- configuration: Release
platform: x64
- configuration: ReleaseANGLE
platform: x64
steps:
- uses: actions/checkout@v3
- name: Add msbuild to PATH
uses: microsoft/setup-msbuild@v1.1
- name: Compile RA
working-directory: "${{github.workspace}}/pkg/msvc-uwp"
run: |
msbuild -p:"Configuration=${{matrix.configuration}}" -p:"Platform=${{matrix.platform}}" .\RetroArch-msvcUWP.sln
- name: Get short SHA
id: slug
shell: powershell
run: echo "::set-output name=sha8::$('${{github.sha}}'.Substring(0,8))"
- uses: actions/upload-artifact@v3
with:
name: retroarch-UWP-${{matrix.configuration}}-${{matrix.platform}}-${{ steps.slug.outputs.sha8 }}
path: pkg/msvc-uwp/AppPackages/RetroArch-msvcUWP
msvc-2019:
runs-on: windows-2022
strategy:
matrix:
include:
- configuration: Release
- version: UWP
configuration: ReleaseAngle
platform: x64
# Qt and Cg builds are excluded for now
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Add msbuild to PATH
uses: microsoft/setup-msbuild@v1.1
uses: microsoft/setup-msbuild@v1
- name: Compile RA
working-directory: "${{github.workspace}}/pkg/msvc"
working-directory: "${{github.workspace}}/pkg/msvc${{ matrix.version == 'UWP' && '-uwp' || ''}}"
run: |
msbuild -p:"Configuration=${{matrix.configuration}}" -p:"Platform=${{matrix.platform}}" .\RetroArch-msvc2019.sln
msbuild -p:"Configuration=${{matrix.configuration}}" -p:"Platform=${{matrix.platform}}" .\RetroArch-msvc${{matrix.version}}.sln
- name: Get short SHA
id: slug
shell: powershell
run: echo "::set-output name=sha8::$('${{github.sha}}'.Substring(0,8))"
run: echo "sha8=$('${{github.sha}}'.Substring(0,8))" >> $env:GITHUB_OUTPUT
# https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/
- uses: actions/upload-artifact@v3
- uses: actions/upload-artifact@v4
with:
name: retroarch-msvc2019-${{matrix.configuration}}-${{matrix.platform}}-${{ steps.slug.outputs.sha8 }}
path: pkg/msvc/${{matrix.platform}}/${{matrix.configuration}}/RetroArch-msvc2019.exe
name: retroarch-${{matrix.version}}-${{matrix.configuration}}-${{matrix.platform}}-${{ steps.slug.outputs.sha8 }}
path: |
${{ matrix.version != 'UWP' }}:
pkg/msvc/${{matrix.platform}}/${{matrix.configuration}}/RetroArch-msvc${{matrix.version}}.exe
${{ matrix.version == 'UWP' }}:
pkg/msvc-uwp/AppPackages/RetroArch-msvcUWP

View File

@ -7,6 +7,9 @@ on:
permissions:
contents: read
env:
ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true
jobs:
build:
runs-on: macos-latest

View File

@ -9,16 +9,19 @@ on:
permissions:
contents: read
env:
ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true
jobs:
build:
runs-on: ubuntu-latest
container:
container:
image: git.libretro.com:5050/libretro-infrastructure/libretro-build-dingux:latest
options: --user root
steps:
- uses: actions/checkout@v3
- name: Compile RA
run: |
make -j$(getconf _NPROCESSORS_ONLN) -f Makefile.miyoo clean
@ -27,7 +30,7 @@ jobs:
- name: Get short SHA
id: slug
run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)"
- uses: actions/upload-artifact@v3
with:
name: retroarch_miyoo_arm32${{ steps.slug.outputs.sha8 }}

View File

@ -9,21 +9,24 @@ on:
permissions:
contents: read
env:
ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true
jobs:
build:
runs-on: ubuntu-latest
container:
container:
image: git.libretro.com:5050/libretro-infrastructure/libretro-build-ps2:latest
options: --user root
steps:
- uses: actions/checkout@v3
- name: Compile Salamander
run: |
make -f Makefile.ps2.salamander -j$(getconf _NPROCESSORS_ONLN) clean
make -f Makefile.ps2.salamander -j$(getconf _NPROCESSORS_ONLN) release
- name: Compile RA
run: |
make -f Makefile.ps2 -j$(getconf _NPROCESSORS_ONLN) clean
@ -32,10 +35,10 @@ jobs:
- name: Get short SHA
id: slug
run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)"
- uses: actions/upload-artifact@v3
with:
name: RA-PS2-dummy-${{ steps.slug.outputs.sha8 }}
path: |
raboot.elf
retroarchps2.elf
retroarchps2.elf

View File

@ -9,10 +9,13 @@ on:
permissions:
contents: read
env:
ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true
jobs:
build:
runs-on: ubuntu-latest
container:
container:
image: git.libretro.com:5050/libretro-infrastructure/libretro-build-orbis:latest
options: --user root
@ -24,7 +27,7 @@ jobs:
apk add ncurses-dev make bash python2
apk add libintl icu-dev wget
wget https://dot.net/v1/dotnet-install.sh && chmod 755 dotnet-install.sh && ./dotnet-install.sh -c 3.0 --install-dir ~/cli
- name: Compile RA
run: |
export PATH=~/cli:$PATH # .net cli
@ -33,7 +36,7 @@ jobs:
- name: Get short SHA
id: slug
run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)"
- uses: actions/upload-artifact@v3
with:
name: bin-${{ steps.slug.outputs.sha8 }}

View File

@ -9,16 +9,19 @@ on:
permissions:
contents: read
env:
ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true
jobs:
build:
runs-on: ubuntu-latest
container:
container:
image: git.libretro.com:5050/libretro-infrastructure/libretro-build-psp:latest
options: --user root
steps:
- uses: actions/checkout@v3
- name: Compile bootstrap
run: |
cd bootstrap/psp1/kernel_functions_prx
@ -29,7 +32,7 @@ jobs:
run: |
make -f Makefile.psp1.salamander -j$(getconf _NPROCESSORS_ONLN) clean
make -f Makefile.psp1.salamander -j$(getconf _NPROCESSORS_ONLN)
- name: Compile RA
run: |
make -f Makefile.psp1 -j$(getconf _NPROCESSORS_ONLN) clean
@ -38,7 +41,7 @@ jobs:
- name: Get short SHA
id: slug
run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)"
- uses: actions/upload-artifact@v3
with:
name: RA-PSP-dummy-${{ steps.slug.outputs.sha8 }}

View File

@ -9,21 +9,24 @@ on:
permissions:
contents: read
env:
ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true
jobs:
build:
runs-on: ubuntu-latest
container:
container:
image: git.libretro.com:5050/libretro-infrastructure/libretro-build-vita:latest
options: --user root
steps:
- uses: actions/checkout@v3
- name: Compile Salamander
run: |
make -f Makefile.vita.salamander -j$(getconf _NPROCESSORS_ONLN) clean
make -f Makefile.vita.salamander -j$(getconf _NPROCESSORS_ONLN)
- name: Compile RA
run: |
make -f Makefile.vita -j$(getconf _NPROCESSORS_ONLN) clean
@ -31,7 +34,7 @@ jobs:
- name: Get short SHA
id: slug
run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)"
- uses: actions/upload-artifact@v3
with:
name: RA-PSVita-dummy-${{ steps.slug.outputs.sha8 }}

View File

@ -9,16 +9,19 @@ on:
permissions:
contents: read
env:
ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true
jobs:
build:
runs-on: ubuntu-latest
container:
container:
image: git.libretro.com:5050/libretro-infrastructure/libretro-build-dingux:odbeta
options: --user root
steps:
- uses: actions/checkout@v3
- name: Compile RA
run: |
make -j$(getconf _NPROCESSORS_ONLN) -f Makefile.rs90 clean
@ -27,7 +30,7 @@ jobs:
- name: Get short SHA
id: slug
run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)"
- uses: actions/upload-artifact@v3
with:
name: retroarch_rs90_mips32${{ steps.slug.outputs.sha8 }}

View File

@ -9,16 +9,19 @@ on:
permissions:
contents: read
env:
ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true
jobs:
build:
runs-on: ubuntu-latest
container:
container:
image: git.libretro.com:5050/libretro-infrastructure/libretro-build-dingux:odbeta
options: --user root
steps:
- uses: actions/checkout@v3
- name: Compile RA
run: |
make -j$(getconf _NPROCESSORS_ONLN) -f Makefile.retrofw clean
@ -27,7 +30,7 @@ jobs:
- name: Get short SHA
id: slug
run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)"
- uses: actions/upload-artifact@v3
with:
name: retroarch_retrofw_mips32${{ steps.slug.outputs.sha8 }}

52
.github/workflows/SourceRelease.yml vendored Normal file
View File

@ -0,0 +1,52 @@
name: CI Generate Source Only Tarball
# Trigger whenever a release and/or is created
on:
release:
types:
- created
push:
tags:
- "v*.*"
env:
ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true
jobs:
build:
name: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: archive
id: archive
run: |
VERSION=${GITHUB_REF##*/}
test -z "$VERSION" && VERSION=${{ github.event.release.tag_name }}
VERSION=$(printf "%s\n" "$VERSION" | sed 's/^v//')
PKGNAME="retroarch-sourceonly-$VERSION"
mkdir -p /tmp/$PKGNAME
mv * /tmp/$PKGNAME
mv /tmp/$PKGNAME .
rm -rf $PKGNAME/pkg || true
rm -rf $PKGNAME/wii/libogc || true
rm -rf $PKGNAME/deps/glslang/glslang/Test || true
rm -rf $PKGNAME/deps/SPIRV-Cross/reference || true
rm -rf $PKGNAME/gfx/include/userland || true
find $PKGNAME/ -type f -name '*.a' -delete || true
find $PKGNAME/ -type f -name '*.lib' -delete || true
find $PKGNAME/ -type f -name '*.dylib' -delete || true
find $PKGNAME/ -type f -name '*.so.*' -delete || true
find $PKGNAME/ -type f -name '*.dll' -delete || true
TARBALL=$PKGNAME.tar.xz
tar cJf $TARBALL $PKGNAME
echo "tarball=$TARBALL" >> $GITHUB_OUTPUT
- name: upload tarball
uses: softprops/action-gh-release@v2
with:
files: ${{ steps.archive.outputs.tarball }}

View File

@ -9,16 +9,19 @@ on:
permissions:
contents: read
env:
ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true
jobs:
build:
runs-on: ubuntu-latest
container:
container:
image: git.libretro.com:5050/libretro-infrastructure/libretro-build-libnx-devkitpro:latest
options: --user root
steps:
- uses: actions/checkout@v3
- name: Compile RA
run: |
make -f Makefile.libnx -j$(getconf _NPROCESSORS_ONLN) clean
@ -26,7 +29,7 @@ jobs:
- name: Get short SHA
id: slug
run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)"
- uses: actions/upload-artifact@v3
with:
name: RA-libnx-dummy-${{ steps.slug.outputs.sha8 }}

View File

@ -9,21 +9,24 @@ on:
permissions:
contents: read
env:
ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true
jobs:
build:
runs-on: ubuntu-latest
container:
container:
image: git.libretro.com:5050/libretro-infrastructure/libretro-build-devkitpro:latest
options: --user root
steps:
- uses: actions/checkout@v3
- uses: taiki-e/checkout-action@v1
- name: Compile Salamander
run: |
make -f Makefile.wii.salamander -j$(getconf _NPROCESSORS_ONLN) clean
make -f Makefile.wii.salamander -j$(getconf _NPROCESSORS_ONLN) EXTERNAL_LIBOGC=1 GX_PTHREAD_LEGACY=0
- name: Compile RA
run: |
make -f Makefile.wii -j$(getconf _NPROCESSORS_ONLN) clean
@ -31,9 +34,4 @@ jobs:
- name: Get short SHA
id: slug
run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)"
- uses: actions/upload-artifact@v3
with:
name: RA-Wii-dummy-${{ steps.slug.outputs.sha8 }}
path: |
retroarch_wii.dol

View File

@ -9,31 +9,28 @@ on:
permissions:
contents: read
env:
ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true
jobs:
build:
runs-on: ubuntu-latest
container:
container:
image: git.libretro.com:5050/libretro-infrastructure/libretro-build-wiiu:latest
options: --user root
steps:
- uses: actions/checkout@v3
- uses: taiki-e/checkout-action@v1
- name: Compile Salamander
run: |
make -f Makefile.wiiu -j$(getconf _NPROCESSORS_ONLN) SALAMANDER_BUILD=1 clean
make -f Makefile.wiiu -j$(getconf _NPROCESSORS_ONLN) SALAMANDER_BUILD=1
make -f Makefile.wiiu -j$(getconf _NPROCESSORS_ONLN) SALAMANDER_BUILD=1 V=1
- name: Compile RA
run: |
make -f Makefile.wiiu -j$(getconf _NPROCESSORS_ONLN) clean
make -f Makefile.wiiu -j$(getconf _NPROCESSORS_ONLN) HAVE_STATIC_DUMMY=1
make -f Makefile.wiiu -j$(getconf _NPROCESSORS_ONLN) HAVE_STATIC_DUMMY=1 V=1
- name: Get short SHA
id: slug
run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)"
- uses: actions/upload-artifact@v3
with:
name: RA-WiiU-dummy-${{ steps.slug.outputs.sha8 }}
path: |
retroarch.rpx

View File

@ -9,16 +9,19 @@ on:
permissions:
contents: read
env:
ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true
jobs:
build:
runs-on: ubuntu-latest
container:
container:
image: git.libretro.com:5050/libretro-infrastructure/libretro-build-mxe-win32-cross:gcc10
options: --user root
steps:
- uses: actions/checkout@v3
- uses: taiki-e/checkout-action@v1
- name: Compile RA
run: |
export MOC=/usr/lib/mxe/usr/i686-w64-mingw32.shared/qt5/bin/moc
@ -29,9 +32,3 @@ jobs:
- name: Get short SHA
id: slug
run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)"
- uses: actions/upload-artifact@v3
with:
name: retroarch${{ steps.slug.outputs.sha8 }}
path: |
retroarch.exe

View File

@ -9,16 +9,19 @@ on:
permissions:
contents: read
env:
ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true
jobs:
build:
runs-on: ubuntu-latest
container:
container:
image: git.libretro.com:5050/libretro-infrastructure/libretro-build-mxe-win64-cross:gcc10
options: --user root
steps:
- uses: actions/checkout@v3
- uses: taiki-e/checkout-action@v1
- name: Compile RA
run: |
export MOC=/usr/lib/mxe/usr/x86_64-w64-mingw32.shared/qt5/bin/moc
@ -29,9 +32,3 @@ jobs:
- name: Get short SHA
id: slug
run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)"
- uses: actions/upload-artifact@v3
with:
name: retroarch${{ steps.slug.outputs.sha8 }}
path: |
retroarch.exe

View File

@ -16,12 +16,12 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Setup Java JDK
uses: actions/setup-java@v3
uses: actions/setup-java@v4
with:
java-version: 18
distribution: zulu
- name: Setup Python
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: '3.10'
- name: Checkout

View File

@ -18,12 +18,12 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Setup Java JDK
uses: actions/setup-java@v3
uses: actions/setup-java@v4
with:
java-version: 18
distribution: zulu
- name: Setup Python
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: '3.10'
- name: Checkout

View File

@ -13,6 +13,9 @@ on:
permissions:
contents: read
env:
ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true
jobs:
linux-c89: # Smoketest build using most restrictive compiler and default options
runs-on: ubuntu-latest

55
.github/workflows/webOS.yml vendored Normal file
View File

@ -0,0 +1,55 @@
name: CI webOS
on:
push:
pull_request:
repository_dispatch:
types: [run_build]
permissions:
contents: read
env:
ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Check Out Repo
uses: actions/checkout@v4
- name: Download ares-cli-rs
uses: robinraju/release-downloader@v1.11
with:
repository: "webosbrew/ares-cli-rs"
latest: true
fileName: "ares-package_*.deb"
out-file-path: "temp"
- name: Update packages
run: sudo apt-get -yq update
- name: Install webOS CLI
run: sudo apt-get -yq install ./temp/*.deb
- name: Download webOS NDK
uses: robinraju/release-downloader@v1.11
with:
repository: "openlgtv/buildroot-nc4"
latest: true
fileName: "arm-webos-linux-gnueabi_sdk-buildroot.tar.gz"
out-file-path: "/tmp"
- name: Extract webOS NDK
shell: bash
working-directory: /tmp
run: |
tar xzf arm-webos-linux-gnueabi_sdk-buildroot.tar.gz
./arm-webos-linux-gnueabi_sdk-buildroot/relocate-sdk.sh
- name: Compile RA
run: |
. /tmp/arm-webos-linux-gnueabi_sdk-buildroot/environment-setup
make -f Makefile.webos ADD_SDL2_LIB=1 -j$(getconf _NPROCESSORS_ONLN)

16
.gitignore vendored
View File

@ -14,6 +14,7 @@
*.swp
*.cache
*.gcda
*.lcbk
*.gcno
.tmp
.tmp.c
@ -96,6 +97,10 @@ database
overlays
playlists
states
cheats
thumbnails
docs/html
system
shaders/shaders_cg
shaders/shaders_glsl
shaders/shaders_slang
@ -134,6 +139,7 @@ wiiu/wut/elf2rpl/elf2rpl
# CLion
/cmake-build-debug/
.run
# Android
/pkg/android/phoenix/obj/
@ -154,6 +160,7 @@ wiiu/wut/elf2rpl/elf2rpl
/media/shaders_cg/
/media/libretrodb/
compile_commands.json
pkg/apple/iOS/build/
pkg/apple/build/
ui/drivers/qt/moc_*
@ -206,6 +213,10 @@ retroarch_switch.nso
*_irx.c
# Wayland
gfx/common/wayland/fractional-scale-v1.c
gfx/common/wayland/fractional-scale-v1.h
gfx/common/wayland/viewporter.c
gfx/common/wayland/viewporter.h
gfx/common/wayland/idle-inhibit-unstable-v1.c
gfx/common/wayland/idle-inhibit-unstable-v1.h
gfx/common/wayland/xdg-shell-unstable-v6.c
@ -237,4 +248,7 @@ param.sfo
/deps/SPIRV-Cross/out/build/x64-Debug
# Visual Studio Code
.vscode/
.vscode/
# Clazy
*.clazy.yaml

View File

@ -348,7 +348,8 @@ build-retroarch-linux-i686:
- xcodebuild -exportArchive -archivePath ${XCARCHIVE_PATH}.xcarchive -exportPath . -exportOptionsPlist pkg/apple/OSX/ExportOptions.plist
- ditto -c -k --sequesterRsrc --keepParent RetroArch.app ${XCPROJECT_NAME}.zip
- mkdir .retroarch-repo
- "cp -r ./* .retroarch-repo"
- "cp -R ./* .retroarch-repo"
- echo '#define GIT_VERSION ' $(git rev-parse --short HEAD) > .retroarch-repo/.git_version.h
- "mv .retroarch-repo/ retroarch-repo/"
# Mac OS Universal, Metal
@ -402,6 +403,7 @@ build-retroarch-ios-arm64:
- xcodebuild -project pkg/apple/${XCPROJECT_NAME}.xcodeproj -destination ${XCDESTINATION} -config Release -scheme "${XCSCHEME}" -xcconfig pkg/apple/iOS/${XCCONFIG} build
- mkdir .retroarch-repo
- "cp -r ./* .retroarch-repo"
- echo '#define GIT_VERSION ' $(git rev-parse --short HEAD) > .retroarch-repo/.git_version.h
- "mv .retroarch-repo/ retroarch-repo/"
build-retroarch-ios9:
@ -418,6 +420,7 @@ build-retroarch-ios9:
- xcodebuild -project pkg/apple/${XCPROJECT_NAME}.xcodeproj -config Release -scheme "${XCSCHEME}" -xcconfig pkg/apple/iOS/GitLabCI.xcconfig build
- mkdir .retroarch-repo
- "cp -r ./* .retroarch-repo"
- echo '#define GIT_VERSION ' $(git rev-parse --short HEAD) > .retroarch-repo/.git_version.h
- "mv .retroarch-repo/ retroarch-repo/"
build-retroarch-tvos-arm64:

View File

@ -1,11 +1,310 @@
# Future
- AUDIO: Fix audio handling in case of RARCH_NETPLAY_CTL_USE_CORE_PACKET_INTERFACE
- APPLE: Hide threaded video setting
- CHEEVOS: Add rarity and points to achievement unlock widget
- CHEEVOS: Add rank to leaderboard submission notification
- CHEEVOS: Update to rcheevos 11.5
- CHEEVOS: Update to rcheevos 11.6
- CHEEVOS: Show rcheevos game image in Discord rich presence
- CHEEVOS: Use translated strings for achievement messages
- CLOUDSYNC: Allow saves and configs to be synced optionally
- CLOUDSYNC: Add iCloud cloud sync driver
- CLOUDSYNC: Speed up by upload/download in parallel
- CLOUDSYNC: Allow thumbnails and system dir to be synced optionally
- CLOUDSYNC: Enable CloudSync on Android (non-SSL)
- CRT/SWITCHRES: Update switchres to 2.2.1
- GENERAL: Support for mbedtls v3
- GENERAL: Automatic Frame Delay refactor
- GENERAL: Remove Frame Rest, obsoleted by Frame Delay refactor
- GENERAL: Wrap around auto increment save state indexes when amount of states is limited
- GENERAL: Enable CHD hashing for Switch and DOS
- GENERAL: Enable auto save state when new content is loaded
- GENERAL: Improve Preemptive Frames when pointing device is used
- HAIKU: Restore Haiku build
- INPUT: Allow to select a preferred/reserved device for each player
- INPUT: Enable Caps, Num, Scroll Lock modifiers on multiple platforms
- INPUT: Autoconfig extension with alternative name/vid/pid
- INPUT/HID: Fix crash on macOS when disconnecting the controller a second time
- INPUT/Remaps: Sort and apply remaps based on the specific connected controller
- INPUT/UDEV: Enable mouse buttons 4 and 5
- INPUT/WAYLAND: Enable horizontal scroll and mouse buttons 4 and 5
- INPUT/X11: Enable mouse buttons 4 and 5
- iOS: Enable vibration by default
- iOS: Better handling of physical mice/magic keyboard trackpad
- iOS: Mouse grab fixes
- iOS: Fix mouse cursor movement when button is held down
- iOS: Fix microphone support request and entitlement
- iOS: Enable compilation back to iOS 12
- iOS/TVOS: Add Opera to App Store build
- iOS/TVOS: Bring NEON defines in line with ARM64
- iOS/TVOS: Flush save files on backgrounding
- LIBRETRO: Support RETRO_ENVIRONMENT_GET_FILE_BROWSER_START_DIRECTORY
- FFMPEG: Fix crash when playing back a file with 96 kHz audio
- MACOS: New display server, including support for ProMotion 120Hz V-Sync
- MACOS: Create App Store build
- MIDI: Fix long messages (SysEx) in WinMM driver
- MIDI: Fix lingering notes on close in Alsa driver
- MENU: Support local thumbnails in other image formats than png (jpg/jpeg, bmp, tga)
- MENU: Delete also savestate thumbnails when savestates are garbage collected
- MENU: Option to disable analog stick menu navigation
- MENU: Fix pause toggle to not clear fast forward state
- MENU: Fix search playlist index in XMB/Ozone
- MENU: Fix renamed entry display
- MENU/GLUI: Make Show Sublabels options effective
- MENU/GLUI: Icon fixes
- MENU/XMB: Allow playlist icons to be individually customized, by looking for images in Named_Logos
- MENU/OZONE: Add Selenium theme for Ozone
- MENU/OZONE: Touchscreen improvements
- NETPLAY: Add East Asian relay server
- PS2: Fix several broken cores depending on pthread
- RECORDING: New WAV recording driver (audio only)
- REMOTE RETROPAD: Add gyro/acceleration/light sensor test screen
- REPLAY: Replay format extended to support external tools
- TVOS: Support bluetooth keyboards on tvOS
- TVOS: Fixes to run correctly on TVOS13
- TVOS: Better handling of Siri remote
- VIDEO: Show and use exact refresh rate (3 decimals) and interlace/doublestrike where available
- VIDEO: Allow setting viewport bias to offset viewport horizontally/vertically
- VIDEO: Support viewport bias also with integer overscale and custom aspect ratios
- VIDEO: Use shader path from CLI for shader cycling
- VIDEO: Pixel perfect integer scaling improvements: axis options, smart mode
- VIDEO/D3D: Fix GPU screenshots
- VIDEO/KMS: Force fullscreen when KMS is used
- VIDEO/OpenGLES: Improve version directive granularity
- VIDEO/SHADERS: Fix memory leak when shader parameter step is 0.0
- VIDEO/SLANG: Support optional includes
- VIDEO/VULKAN: Fix Vulkan window freezes when swapchain becomes suboptimal
- VIDEO/VULKAN: Prefer IMMEDIATE mode without vsync
- VIDEO/X11: Support inhibit of Xss screensaver
- WAYLAND: Fix segfault when relative pointer is not supported
- WAYLAND: Use reverse DNS name for desktop file and icon
- WAYLAND: Commit viewport resizes for more responsive display when resizing window
- WINDOWS: Fix restart if path to executable contains non-ASCII symbols
# 1.19.1
- (WASAPI) Only write when running and fix deadlock
# 1.19.0
- AI: Revert AI translation to previous version (fix for translation not working with HW rendered cores)
- APPLE: Try to use system preferred language
- APPLE: Correctly register for filetypes uniquely
- APPLE/MFI: improved Switch Online controller support through MFi
- AUDIO: Bring back audio toggling on menu toggle
- CHEEVOS: Build a default RetroAchievements memory map when no RetroAchievements game is loaded
- CHEEVOS: Update to rcheevos 11.3
- CHEEVOS: fix hardcore acting as if it's enabled when it isn't
- CLANG: Fix clang error incompatible-pointer-types-discards-qualifiers
- CLOUDSYNC/LINUX: Enable Cloud Sync by default on Linux builds with network (#16456)
- CLOUDSYNC/WEBOS: Enable Cloud Sync by default on Linux builds with network (#16456)
- CORE: Set compute fps stats logging to debug level
- EMSCRIPTEN: Added M2000 to core selection dropdown
- FFMPEG: Add compatibility with FFMPEG 7.0
- GLSLANG: Remove unneeded ENABLE_HLSL code from glslang
- GENERAL: Memory leak: Dynamic allocation from msg_hash_get_help_us_enum was not freed.
- INPUT/KEYBOARD: Add support for multimedia keys - Extended RETROK_ values with 18 new items, commonly found on
"multimedia" keyboards. Mapping added for SDL, X11, Wayland, dinput, winraw keymaps.
- INPUT/MFI: Pressure sensitive left/right triggers
- INPUT/MFI: Fix Start + L1/L2/R2 combinations
- INPUT/MFI: Support strong and weak rumble
- INTL: Fetch translations from Crowdin
- INTL: Add Galician and Norwegian to list of languages
- LAKKA: Display reboot/shutdown message also when not saving config on exit
- LAKKA: Provide update URL and target name at buildtime
- LIBRETRO: Add a debug message for the SET_ROTATION callback
- macOS: Default Accessibility on if VoiceOver is on
- iOS: default audio sync on again, also more mfi logging
- iOS: Fix Import Content
- iOS: Fix ios-arm64 nightly build crash
- iOS: Import content from iCloud
- iOS: Fix #16485 crash on startup
- iOS: Display app icon in app icon picker in materialui
- iOS/tvOS: Various QoL improvements
- iOS/tvOS: Fix a couple more path name mangling bugs
- iOS/tvOS: Better way of packaging Frameworks
- iOS/tvOS: define PACKAGE_VERSION to be App Store MARKETING_VERSION
- iOS/tvOS: Fix keyboard handling for app store builds
- iOS/tvOS: Fix escaping the sandbox for jailbroken devices
- iOS/tvOS: default accessibility on if voice over is enabled
- iOS/tvOS: better way of reporting available memory
- macOS/iOS/tvOS: enable text-to-speech using AVSpeechSynthesizer.
- tvOS: Fix scaling for 720p
- MENU: New function in Quick Menu: Add to Playlist
- MENU/XMB: New theme: FlatUX, designed to merge FlatUI and Retroactive themes into a single, unified design
- NETWORKING/RETROPAD CORE: Fix socket close method
- PIXMAN: Update pixman-private.h - patch to fix build issue with musl
- PLAYLIST: Cleanup 'Add to Playlist' (#16495)
- SCANNING: Fix for scanning PSP ISOs (and probably few others)
- SAVES: Fix core config saving
- SAVES: Fix save new config name when core loaded
- SAVESTATES: Increase save state chunk size for all platforms - Even a class 6 or class 10 SD card can handle reads and writes on the order of MB/s, which means a 4KB chunk size is just wasting time in syscalls. This could maybe be fixed with a buffering reader but I don't feel comfortable tweaking libretro-common's VFS to handle that. Instead, I thought it would be good to both remove an ifdef and increase the chunk size to 128KB. For cores with small states this will should make state saving virtually instantaneous, and for cores with large states it should be a 32x speedup.
- VIDEO: Fix crash when using threaded video - for Mesa 23.2 and later
- VIDEO/GL: Fix reinitialization of the threaded gl drivers
- VIDEO/VULKAN: Add support for A2R10G10B10 HDR format
- VIDEO/VULKAN: Implement HDR readback - screenshot support
- WAYLAND: Ignore configure events during splash (fix not remembering window size)
- WAYLAND: Use frontend signal handler to quit (fix quit by window close)
- WAYLAND: Commit viewport resizes (window resize is more responsive)
- UWP: Align MESA to alpha-2-resfix - Remove wrong resolution special handling for OPENGL
- UWP: 4K fix: align MESA reading of ClientRect to retroarch procedure, this fixes max resolution being set to 1080p. As reading must be done inside an UI thread and is in fact an async operation which might delay frame generation, the reading itself is doen once and cached, give that changing resolution while the app is running is an unlikely corner-case use
- WINDOWS: Windows mouse ungrab must release the mouse instead of confine it to the current desktop (#16488)
- WINDOWS: Fix numlock/pause key release events
# 1.18.0
- AI: Fix narrator language when AI translation and menu languages are different
- DISK CONTROL: Add option to disable initial disk change
- DISK CONTROL: Visibility option for disk control notifications
- DRM: Fix mode vrefresh calculation. When using an interlaced/doublescan mode, the vertical refresh rate is mis-calculated.
- EMSCRIPTEN: Fix mouse Y parameter translation in rwebinput
- INPUT: Fix input state combos including R3 and false triggers of RETROK_UNKNOWN
- INPUT: Add a new turbo mode, "Classic (Toggle)"
- INPUT: Fix bind hold when axis does not rest at 0
- INPUT: Limit axis threshold setting to sensible values
- INPUT: Add Overlay Mouse, Lightgun, and Pointer
- INPUT/ANDROID: Fix mouse grab behavior on Android
- INPUT/LINUXRAW: Fix device name and hotplug reconnect
- IOS: Minor iOS JIT availability information
- IOS/TVOS: Pause application on applicationWillResignActive
- LIBRETRO: Add Doxygen-styled comments to parts of the libretro API
- LUA: Update Lua to version 5.3.6
- MENU: Add sublabels for input bind common entries
- MENU: Don't load history and favorites if size is 0
- MENU: Don't disable fast forward when entering menu
- MENU: Widget position, size, color, icon adjustments
- MENU: Fix savestate slots in Qt UI
- MENU: Reorder and reduce depth of User Interface menu
- MENU/OZONE: Fix sidebar wraparound, visibility after config load, crash after playlist delete
- MENU/OZONE: Fix sidebar and sublabel animations
- OSX/MACOS: Fix crash on non-Metal build
- OSX/MACOS: Add portable.txt as flag for portable install
- REMOTE RETROPAD: add display for analog axes, indication of inputs already pressed
- SAVES: Allow combining saves in content dir with save sorting
- SHADER: Added rolling scan line simulation based on the shader subframe feature. This is implemented with a scrolling scissor rect rather than in the shader itself as this is more efficient although may not work for every shader pass - we may need an option to exclude certain passes. The implementation simply divides the screen up by the number of sub frames and then moves the scissor rect down over the screen over the number of sub frames
- TVOS: Force asset re-extraction when cache is deleted
- TVOS: Add history and favorites to Top Shelf
- TVOS: Fix crash when history item does not have a label
- UWP: Enable HAVE_ACCESSIBILITY for UWP builds
- UWP: Allow UWP build to work with a modified version of Mesa Gallium D3D12
- VIDEO: Add subframe shader support for Vulkan/GLcore/DX10-11-12, enabling shaders to run at higher framerate than the content
- VIDEO: Fix restoring fullscreen/windowed setting when unloading override
- VIDEO/VULKAN: Fix HDR with Vulkan after reinit
- VIDEO/VULKAN: Remove the use of oldSwapchain
- VIDEO/GL2: Fix OpenGL ES version detection
- WEBDAV: Fixed SEGFAULT in WebDav task sync + type changes
- WEBOS: Fix build, add core location on webosbrew.org
- WIN32: Fix Alt+Enter not working when menubar is disabled
# 1.17.0
- ACCESSIBILITY/TTS: fix target language and missing espeak handling on Linux
- AI: AI service reworked: performance increase, automatic translation, configurable subtitle placement, and more
- APPLE: Fix WebDAV crash with digest auth (Cloud Sync)
- APPLE: Cloud sync fixes - ignore .DS_Store files and re-sync on app foreground
- APPLE: Don't re-create default directories
- APPLE: Show Git information correctly
- AUDIO/SYNC: Handle Hz skew adjustment for high refresh rates better (BFI, swap interval)
- AUDIO/MIXER: Separate ffmpeg/mpv and audiomixer conditionals
- AUDIO/WASAPI: Reworked shared buffer operation for more flexibility, fixed exclusive mode last buffer looping when entering menu
- CONFIG/OVERRIDES: Fix setting savefile_directory in override file
- CONFIG: Force fixed locale for numbers
- CHEEVOS: Upgrade to rcheevos 11.0
- CHEEVOS: Use rc_client for state management
- CHEEVOS: Don't track disc changes when achievements are disabled
- CHEEVOS: Reinitialize rewind buffer after loading game with achievements
- CHEEVOS: Inform user when server is unreachable
- CHEEVOS: Fix crash on first load of game with achievements with threaded video
- EMSCRIPTEN: Increase chunk size for reads/writes
- EMSCRIPTEN: Modularize the JavaScript and clean up the web build
- EMSCRIPTEN: Prefix core name with libretro_ for exports
- EMSCRIPTEN: replace dashes with underscores in corenames (fix for vitaquake cores)
- EMSCRIPTEN: Use ZipFS for web player asset bundle
- EMSCRIPTEN: Change default audio rate to 44100
- IOS: Fix widget on IOS17
- IOS: Exit instead of crash on some errors
- IOS: Fix ios-vulkan-ppsspp
- IOS: Enable HDR support on IOS
- IOS: Add option to disable respecting silent mode
- IOS: Allow ignoring safe area (fullscreen over notch)
- IOS: Default to not enabling keyboard gamepad
- IOS: Fix XRGB8888 in GL driver
- IOS: Allow changing the app icon
- IOS: Add HAVE_ACCESSIBILITY to iOS builds
- IOS/TVOS: Create GL context as GLES3 to fix some rendering performance problems
- INPUT: Fix ghost input when setting RETROK_UNKNOWN
- INPUT: Default 'Bind Hold' to 0 to prevent problems with controllers not resting at null state
- INPUT: Add a setting to allow turbo d-pad directions
- INPUT: Don't save mouse buttons to autoconfig
- INPUT/MENU: Add option for merging 'Hotkey Enable' device types
- INPUT/mFI: disable secondary_joypad to prevent issues with controllers detected both as HID and mFI
- INPUT/UDEV: Change event detection to polling in udev_joypad
- INPUT/WAYLAND: Use unaccelerated pointer motion to prevent mouse dead zone
- LAKKA: Add new menu options for Switch (overclock, CEC, BT ERTM)
- LIBRETRO: Add environment command to get playlist path
- LIBRETRO/NETPACKET:
Switch environment call number from 76 to 78 (retire 76 as it was never used by any core)
Simplify broadcasts by removing the option to send to all but one client, use an explicit RETRO_NETPACKET_BROADCAST constant instead
Separate explicit flushing and querying of incoming packet into two operations
Enable a core to specify a protocol version string which can get used instead of core version to determine compatibility between two players
Log and notify a separate message when there is a content crc mismatch while using this interface to convey it being less severe
- MENU: Fix menu analog stick navigation (1.16.0.1)
- MENU: Add option to find thumbnail images by playlist rom filename (1.16.0.2)
- MENU: Don't process menu events while input is being flushed (1.16.0.2)
- MENU: Prevent proceeding to next bind when single binding (1.16.0.3)
- MENU: Fix touchscreen menu false positives in case of overlap
- MENU: Sort playlists ignoring extension (Playstation 2 should come after Playstation)
- MENU: Treat System Volume Information folder as hidden on all platforms
- MENU: Add Belarusian language option
- MENU: Fix savestate thumbnail behavior when navigating back to playlist while content is still running
- MENU: Fix word wrapped widget length
- MENU: Add help text to controller drivers
- MENU: Fix quit on content close option
- MENU: Fix thumbnails in History for content loaded through Load Content
- MENU: Flexible thumbnail matching (ROM name - database name - short name)
- MENU: Remove legacy thumbnail pack downloader
- MENU/GLUI: Icon corrections
- MENU/OZONE: Thumbnail related fixes (missing thumbnail bar, fullscreen thumbnail flashing, sidebar focus)
- MENU/RGUI: Fix text scaling in 16:9
- MENU/XMB: Background images take precedence over color themes, default image opacity set the same as color theme opacity
- MENU/XMB: Fix segmentation fault when background image is missing
- MENU/XMB: Several corrections and cleanups
- MENU/XMB: Layout/thumbnail fixes - Thumbnail layout adjustments, Header title improvements, Handheld layout adjustments
- NETWORKING/NETPLAY: Add support for joining MITM servers from command line
- NETWORKING/NETPACKET: Interface connection flow improvements
- OSX: Fix mouse support for MelonDS DS on OSX
- OSX: Option to create a portable build
- PATCHES: Add support for XDelta-formatted patches.
- PATCHES: Fix patching for cores that support contentless mode
- PS2: Fix for no sound
- PS2: Fix 0-byte logs and add memory stats
- PSP: Fix memory leak in audio driver
- RUNLOOP: Frame Rest, experimental sleep feature aiming to lower CPU usage and temperature when using certain CPU hungry vsync modes
- RPI: Fix videocore + switchres compile failure
- SCAN: Do CRC check on PSP/PSP(PSN) content
- TVOS: Enable overlay support
- VIDEO/BFI: Black Frame Insertion added to DirectX10/11/12. BFI Hz range now covers every 60hz multiple under 1000hz. Variable Strobe length via new 'Dark Frames' option, algorithm to auto select 'decent' Dark Frames choice.
- VIDEO/GLSL: Add FinalViewportSize support to GLSL
- VIDEO/GLSL: Change rotation type to int to maximize compatibility
- VIDEO: Use video refresh rate instead of core refresh rate for menu frame limiting
- VIDEO: Limit paused video refresh rate
- VIDEO: Enforce swap interval 1 in menu if vsync is on
- WII: Enable Cheevos for Wii builds
- WIIU: Fix config file and core info reading
- WIIU: Fix "Up" and "Left" directional input for both Analog sticks for GC Adapter
- WIIU: Fix 3 USB controllers (NES/SNES/Retrode)
- WIIU: Fix file descriptor leak
- WIN32: Prefer D3D11 and WASAPI as default video and audio drivers
- WIN32: Fix window size when aspect ratio is < 0
- WIN32: Fix screen resolution always tied to the main monitor
- WAYLAND: Enable fallback for screensaver inhibit via D-Bus
- WAYLAND: Introduce wp_fractional_scale_v1 protocol for proper fractional scaling
- WAYLAND: Update wayland-protocols version to 1.31
# 1.16.0
- 3DS: Update __system_initArgv
- 3DS: Update SquirrelJME 3DS Core information along with icons.
- ANDROID: Rewrite input handling to better support AINPUT_SOURCE_STYLUS
- ANDROID: Prevent the android quick tap mouse click emulation while pressing a button on the on-screen overlay
- AUDIO: Fast-Forward Audio Resampling
- AUDIO: Reinit audio on audio sync toggle
- AUDIO: Count audio samples in stats when rate control is disabled
- AUDIO/PULSEAUDIO: Support device list for PulseAudio
- AUDIO/WASAPI: WASAPI Frame Delay fix + cleanups
- AUDIO/WASAPI/MIDI: Frame Delay correction
@ -22,36 +321,48 @@ require fullpath or not, small and big ZIP files).
- APPLE: Don't include MoltenVK library in Load Core menu list
- APPLE: Enable AltServer JIT for builds installed by Xcode
- APPLE: The default pthread stack size on Apple is too small for detect_ps2_game, so increase it
- APPLE: Introduce Cloud Sync via a WebDAV service on iOS/TVOS/MacOS
- CHEEVOS: Upgrade to rcheevos 10.7
- CHEEVOS: Don't initialize rcheevos memory unless used
- CHEEVOS: Add progress tracker widget
- CHEEVOS: Eliminate leaderboard tracker stutter
- CHEEVOS: Expand leaderboard visibility settings
- CHEEVOS: Collapse trackers with same value definition
- CHEEVOS: prevent frame step when hitting rewind button while paused in hardcore
- CHEEVOS: disallow video_swap_interval and black_frame_insertion in hardcore
- CRT/SWITCHRES: Don't always force core aspect ratio
- CRT/SWITCHRES: Fix aspect ratio for tate games on a horizontal screen
- CRT/SWITCHRES: Add PAL threshold option for automatic refresh rate switch
- CRT/SWITCHRES/KMS: Add KMS modeswitch
- COMMAND: Make cmd interface more useful for replay information
- CONFIG: Allow all systems to check for backslashes (Windows) as last slash in path. Improves portable core logic
- D3D11: Fix memory corruption in d3d11_gfx_init
- D3D12: Enable blending when drawing the menu
- D3D12: Move fence signaling out of d3d12_gfx_sync
- D3D12: Add D3D12 HW_render support
- D3D12/LIBRETRO: Add D3D12 HW_render support
- DOWNLOADS/THUMBNAILS: Prevent directory creation on bogus thumbnail downloads
- EMSCRIPTEN: Fix Emscripten sleep function/macro
- EMSCRIPTEN/RWEBAUDIO: Fix RWebAudioInit race condition
- EMSCRIPTEN/OPENAL: Make openal default audio driver
- FFMPEG: Fix RetroArch fails to restart streaming when video re-inits and instead starts recording
- FRAMESKIP: Use refresh rate instead of core fps for frameskip timing
- INPUT: Combo hold + 'enable_hotkey' correction. Fixed issue with having menu toggle hold combo in different button than 'enable_hotkey', which caused 'enable_hotkey' to also act as menu toggle if held long enough, and simplified and unified duplicate code in start+select holds to a single function.
- INPUT: input_keyboard_event: Don't check hotkey binds when device is RETRO_DEVICE_POINTER
- INPUT: Add input_keymaps_translate_rk_to_ascii() for correct character input to input_keyboard_event
- INPUT: input_overlay_poll: Delay clearing INPUT_OVERLAY_BLOCKED flag until there is no overlay input (Avoids stray input after osk_toggle)
- INPUT: Send keyboard events for modifiers before other keys (for correct modifier+key input if hitboxes overlap)
- INPUT: Remember currently set keyboard mapping bits during same config read, because otherwise customized keybinds can get cleared out of the bits on the next iteration, causing keyboard events to get passed to the core when they should get blocked.
- INPUT/AUTOCONFIG: Reinit after updating autoconf profiles
- INPUT/LINUX/UDEV: Log mouse devices in info level
- INPUT/LINUX/UDEV: First working version of udev driver with touchscreen support and gestures.
- INPUT/WAYLAND: Add wayland to input driver list
- INPUT/MENU: move port X binds into retropad binds submenu and add appropriate help text and sublabels to discourage people from messing around in there unnecessarily
- INPUT/MENU: Add menu icons to 'RetroPad Binds'
- INPUT/MENU/OSK: Allow more keyboard actions with menu osk
- INPUT/REMAP: Remap label fix when no autoconf profile active
- INPUT/REMAP: Add 'Save As' option for remaps and overrides
- INPUT/OVERLAY: Add overlay parameter to control x/y separation in auto-scale mode
- INPUT/OVERLAY: Revive/rewrite Keyboard Overlay and OSK Toggle. Add keyboard overlay preset, keyboard submenu,
- INPUT/OVERLAY: Revive/rewrite Keyboard Overlay and OSK Toggle. Add keyboard overlay preset, keyboard submenu,
and osk_toggle hotkey. Use overlay caching for osk_toggle.
- INPUT/OVERLAY: Overlay Caching. Adds overlay_cache_ptr to keep a disabled overlay in memory when it's expected to be shown again.
Most input_overlay_deinit calls are replaced with input_overlay_unload, which caches the overlay unless initing/deiniting core or disabling overlays.
@ -69,6 +380,7 @@ Loading a cached overlay is done as a swap, intended for osk_toggle.
- IOS: On iOS, stop/start audio on interruptions
- IOS: Add accelerometer and gyroscope sensors to iOS
- IOS: iOS needs to targets 13 due to some keyboard emulation, but tvOS does not
- IOS/TVOS: Rework JIT availability checks
- IOS/TVOS: When updating playlist with detected core path, used resolved core path
- IOS/TVOS: Implement memory queries on iOS/tvOS
- IOS/TVOS: Netplay discovery through bonjour/mdns
@ -78,22 +390,32 @@ Loading a cached overlay is done as a swap, intended for osk_toggle.
- TVOS: Also handle tap events on tvOS
- TVOS: Back up retroarch.cfg to NSUserDefaults on tvOS.
- TVOS: tvOS has its own beautiful screensavers and I would like them
- TVOS: tvOS Siri remote handling
- TVOS: tvOS Siri remote handling
- TVOS: Fix accidental left/right keypresses on tvOS
- TVOS/CONFIG: Avoid a crash if there is no backed up config file on tvOS
It's not really usable as a game controller, but it is good for going
through the menu as a simple LRUD.
This also adds better support for names of mFI controllers, as well as
being able to do the expected tvOS behavior of "backing out" of the app.
- TVOS: AltKit support for tvOS
- INTL: Fix language detection in Canada to English
- LANGEXTRA: Enable language autodetect for all builds with LANGEXTRA
- LIBRETRO: Add new context hardware render enums - enables autodetection of DX12 for PS2 core
- LIBRETRO: Add API to check JIT availability on iOS
- LIBRETRO: Allow RETRO_ENVIRONMENT_SET_MEMORY_MAPS also after core startup. Change the comment in libretro.h about the removed limit and handle the environment call during core runtime in RetroArch.
- LIBRETRO/MICROPHONE: Add new API for microphone support.
- LIBRETRO: Add new API for querying the device's power state.
- LIBRETRO/VFS: Rewrite retro_vfs_file_remove_impl
- LINUX: Input driver fix 8+ joypads. It was reported that controllers beyond 8 worked only partially (analogs yes, but not buttons), and the found fix was also confirmed.
- MIDI: Show MIDI output first
- MENU: Reorganize 'Saving' menu
- MENU: Start directory browsing from current value
- MENU: Fix menu toggle combo hold with same 'enable_hotkey'
- MENU: Add menu scroll home+end actions
- MENU: Move 'systemfiles_in_content_dir' from Saving to Core
- MENU: Menu navigation acceleration adjustments
- MENU: Audio synchronization menu cleanup
- MENU: Menu value label cleanup
- MENU: Show playlist history/favorites icons by default
- MENU: Remove advanced option flag from video rotation + orientation
- MENU: Combine audio resampler menu with audio output menu
@ -108,12 +430,21 @@ being able to do the expected tvOS behavior of "backing out" of the app.
- MENU: Replaced hack fix for focusing the first item after returning from core suggestion "Run" menu after association reset
- MENU: Fixed setting core association in history/favorites after resetting it and running without setting
- MENU: Relocate playlist manager core association options to prevent accidental resets with Start
- MENU: Fraction setting wraparound rounding correction
- MENU: Add more missing sublabels
- MENU: 'Updater Settings' relocation
- MENU: Search box usability improvements
- MENU/RGUI: Implement 'Remember Selection' option
- MENU/RGUI: Fix savestate thumbnail fullscreen cancel action
- MENU/RGUI: Fix and add toggle for playlist thumbnails
- MENU/OZONE: Update Dracula theme
- MENU/OZONE: Return to sidebar from playlist manage quick access
- MENU/OZONE: Sidebar multiline scrolling
- MENU/OZONE: Avoid crash if ozone sidebar_index_size is 0
- MENU/OZONE: Prevent metadata and footer overlap
- MENU/OZONE: Sublabel width tweak
- MENU/OZONE: Mouse hover selection fix
- MENU/XMB: Message/help box adjustments
- MENU/XMB: XMB menu playlist index bugfix
- MENU/XMB: Playlist label limit fixes
- MENU/XMB: Prevent playlist label truncating long items even when right thumbnail is not enabled/visible
@ -121,7 +452,7 @@ being able to do the expected tvOS behavior of "backing out" of the app.
- MENU/XMB: Stop showing playlist entry index outside of playlists
- MENU/XMB: Fix menu focus issue when returning from "Set Core Association" if playlist index is greater than the previous menu
- MENU/EXPLORE: Prevent flashing when browsing fullscreen thumbnails
- MENU/EXPLORE: Match label ticker length behavior with playlists
- MENU/EXPLORE: Match label ticker length behavior with playlists
- MENU/SOUNDS: Fix certain audio drivers from hanging when menu pause is enabled with menu sounds
- MENU/SOUNDS: Fix menu sounds stopping after fullscreen toggle / video reinit
- MENU/QT/WIMP: Cleanup Desktop Menu welcome text
@ -131,7 +462,7 @@ being able to do the expected tvOS behavior of "backing out" of the app.
- MICROPHONE/SDL: Add `sdl2` microphone driver.
- MICROPHONE/WASAPI: Add `wasapi` microphone driver.
- MOBILE: On mobile in portrait mode, don't override custom viewport
- NETWORKING: Enhance netpacket interface
- NETWORKING: Enhance netpacket interface
- NETWORKING/NETPLAY: Enable core host to refuse connecting new players to limit the number of connected players
- NETWORKING/NETPLAY: Enable a core to flush outgoing packets and read incoming packets without waiting for the next frame (can be used for lower latency or blocking reads)
- OPENDINGUX/RG350: Enable networking for RG350
@ -142,6 +473,7 @@ being able to do the expected tvOS behavior of "backing out" of the app.
- OSX/MACOS: Add HAVE_STDIN_CMD support
- OSX/MACOS: fix mouse grab in windowed mode
- OSX/MACOS/IOS/TVOS: Enable SSL in macos/ios/tvos builds
- PLAYLIST: Change default playlist last played time format
- PS3/PSL1GHT: Add overlay support
- RUNLOOP: Don't count frames while paused
- SERENITYOS: Add SerenityOS to the list of supported operating systems
@ -156,12 +488,15 @@ being able to do the expected tvOS behavior of "backing out" of the app.
- VIDEO/SDL2: Use "nearest" scaling in menus
- TASKS: Fix corrupt task progress percentage
- XVIDEO/MENU: Add menu support to xvideo gfx driver, making it usable
- UWP: Fix modifier keys ( shift, ctrl, alt ) as well as F10 not being detected on the UWP platform
- VULKAN: Ignore Fast-Forward Frameskip option
- VULKAN/KHR_DISPLAY: Support screen refresh rate with Vulkan KHR_Display context
- WIN32: Increase maximum window limit
- WIN32/WINDOWSXP/MSVC2010: Fix invisible menu display
- WAYLAND: Remove splash screen
- WAYLAND: Check for pointer before locking it
- WAYLAND: Add mouse grab/lock functionality
- WAYLAND: Get system wayland-protocols path via pkg-config
# 1.15.0
- AI SERVICE: Fix NVDA switching to Powershell on speak
@ -347,7 +682,7 @@ after the current event handler, which then did exactly the same. Fixes issue #1
- STATICALLY LINKED/SALAMANDER: Fix salamander config save on fork for static platforms
- TVOS/VULKAN/MOLTENVK: Vulkan on tvOS
- VIDEO: Allow manual video swap interval forcing. The addition of auto swap interval effectively prevented manual forcing, which is beneficial when the rate is not reported properly. Therefore use the interval in the calculation only when using automatic interval.
- VULKAN: Fix crash when using multiple physical devices and HW core (#14889)
- VULKAN: Fix crash when using multiple physical devices and HW core (#14889)
- VULKAN: Detect if wrong PhysicalDevice is returned.
- VULKAN: Actually query physical device before creating core device.
- VULKAN: Define and implement v2 of context negotiation interface
@ -379,7 +714,7 @@ So this removes the artificial clamping that was being done to desired_swapchain
- CLI: Reformatted --features to require less rows and to be more consistent
- CLI: Added -V shorthand for --version
- CLI: Tab removal + whitespace nits
- CONFIG/MIDI: Prevent MIDI startup error with old configurations
- CONFIG/MIDI: Prevent MIDI startup error with old configurations
- D3D11: Fix when using shaders with TATE mode arcades etc
- D3D12: Fix when using shaders with TATE mode arcades etc
- D3D12: Added support for break on errors (development aid - define DEVICE_DEBUG to use)
@ -436,7 +771,7 @@ menu_explore_get_entry_playlist_index() returns -1 on invalid entries, but the v
- OSX/MACOS: Fixed Cocoa keyboard not allowing to map Analog stick
- PS2: Use the recently created ps2_drivers which makes easier the loading and init of all the drivers: Memory Card, USB, HDD, Audio, Controllers
- PS2: Adds exFat support for USB, and probably solves some unexpected issues when using an HDD driver for booting cores/games.
- SDL GFX: Fix no menu on start/blank screen issue.
- SDL GFX: Fix no menu on start/blank screen issue.
- SRAM: Don't init SRAM saving without content (gets rid of the redundant logging)
# 1.13.0
@ -528,7 +863,7 @@ If there is no thumbnail with title, find the thumbnail image with rom-name. Thi
- MIST/STEAM/STEAMDECK: Don't expose Black Frame Insertion (BFI) if we are running on a Steam Deck
- NETWORKING/WINDOWS: Disable poll support for MSVC 2010 and earlier. WSAPoll is not supported on Windows XP and earlier.
- NETWORKING/WIIU: Fix socket_connect_with_timeout for WIIU
- NETWORKING/WIIU: Fixes RetroAchievements login
- NETWORKING/WIIU: Fixes RetroAchievements login
- NETWORKING/WIIU: Fixes other online updater functionality
- SAVESTATES/NOTIFICATIONS: Add delay to savestate notifications, so that GPU savestate screenshots stay untouched
- SAVESTATES/SCREENSHOTS: Avoid 'video_gpu_screenshot' with savestates. Allow GPU screenshots with savestates only when there is no other way of getting a screenshot.
@ -552,7 +887,7 @@ If there is no thumbnail with title, find the thumbnail image with rom-name. Thi
- 3DS: Only enable internal counter with CONSOLE_LOG defined
- 3DS: Set default bottom font values
- 3DS: Fix CIA installation issues
- 3DS: Support latest libctru
- 3DS: Support latest libctru
- ANDROID: Add HAVE_ACCESSIBILITY
- ANDROID: Gingerbread support
- ANDROID: Touchpads support
@ -629,7 +964,7 @@ prevents it from being overwritten/deleted while the program is still running.
- MENU: Allow changing savestate slots with left/right on save/load
- MENU: Add 'Ago' to playlist last played styles
- MENU: Add proper icons for shader items
- MENU/MATERIALUI: Add icon for 'Download Thumbnails'
- MENU/MATERIALUI: Add icon for 'Download Thumbnails'
- MENU/XMB: Add options for hiding header and horizontal title margin
- MENU/XMB: Dynamic wallpaper fixes
- MENU/XMB: Add Daite XMB Icon Theme
@ -671,7 +1006,7 @@ prevents it from being overwritten/deleted while the program is still running.
- NETWORK/NETPLAY: Special saves directory for client
- NETWORK/NETPLAY: Ensure current content is reloaded before joining a host
- NETWORK/NETPLAY: Fix client info devices index
- NETWORK/NETPLAY: Fix input for some cores when hosting
- NETWORK/NETPLAY: Fix input for some cores when hosting
- NETWORK/NETPLAY: Memory leak fixes
- NETWORK/NETPLAY: Force a core update when starting netplay
- NETWORK/NETPLAY: Fix NAT traversal announce for HAVE_SOCKET_LEGACY platforms

View File

@ -1,120 +1,120 @@
Refer also to this page for more information -
https://docs.libretro.com/development/coding-standards/
Struct ordering
---------------
For POD-types, try to order structs as follows (first to last):
* long double (8 bytes, 16 bytes [64bit x86], 12 bytes [32bit x86])
* double (8 bytes)
* int64_t (8 bytes, 8 bytes [32bit ARM],
4 bytes [32bit x86])
* uint64_t (4 bytes [32bit], 8 bytes [32bit ARM], 8 bytes [64bit])
* pointer (4 bytes [32bit], 8 bytes [64bit] [1])
* intptr_t (4 bytes [32bit], 8 bytes [64bit] [1])
* uintptr_t (4 bytes [32bit], 8 bytes [64bit] [1])
* ptrdiff_t (4 bytes [32bit], 8 bytes [64bit] [1])
* ssize_t (4 bytes [32bit], 8 bytes [64bit])
* size_t (4 bytes [32bit], 8 bytes [64bit])
* jmp_buf (4 bytes)
* long (4 bytes [64bit Win], 8 bytes [64bit non-Win],
4 bytes [32bit])
* int32_t (4 bytes)
* unsigned (4 bytes)
* float (4 bytes)
* int (4 bytes)
* enum (4 bytes)
* int16_t (2 bytes)
* char (1 byte)
* bool (1 byte)
[1] PS3 uses 4 byte pointers despite having a 64bit processor
Struct members should be sorted by alignment. Therefore, structs
should be sorted by the largest type inside them.
For example, take a struct like this:
typedef struct
{
size_t capacity;
bool old_format;
bool compress;
bool fuzzy_archive_match;
bool autofix_paths;
char path[PATH_MAX_LENGTH];
char base_content_directory[PATH_MAX_LENGTH];
} playlist_config_t;
size_t has the biggest alignment here, so 'struct playlist_config_t'
inside a struct should come before or after size_t.
*** BEST PRACTICES ***
* If we have pointers and size variable pairs, it's best to
interleave them to increase the probability they go in the
same cacheline. It also makes the code more readable, that
these two variables are connected.
Example:
struct a
{
char* b;
size_t b_len;
char* c;
size_t c_len;
};
Stack size
----------
You have to assume that stack size is going to be limited in
RetroArch. Some game consoles (and other embedded systems)
might have a default stack size as low as 128Kb or less.
Be conservative with stack size but don't try to put very
small structs on heap either [to avoid memory fragmentation
among other things]. A balancing act here is necessary.
Be mindful that heap allocations are slow compared to stack.
Functions
---------
- Avoid doing small getter/setter functions. We want a function
to justify its function call overhead by doing a significant
body of work. Small one-line getter/setter functions for what
is predominantly C-style structs is not useful, plus it leads
to people thinking this function is more complex than it
actually is, thus obfuscating the sourcecode instead of it
being easier to read.
If you can find examples in the codebase that violate this
guideline, do not hesitate to point them out to us.
Variable declaration
--------------------
For C source files, we have to insist you stick to the following:
- Declare variables either at the start of a function or the start
of a code block, depending on the scope they need.
- Do not do initial for loop declarations. Refer to the bulletpoint above:
either declare them at the start of the function, or at the start
of the code block.
Not doing this would break compilation on platforms where we are compiling
these C source files in C89 compatibility mode. If such issues occur in pull
requests, we have to request that it be fixed.
VLA (Variable Length Array)
---------------------------
Do not use VLAs (Variable Length Array) in C source files. These are not
C89-compliant.
Miscellaneous
-------------
- Brace usage follows "Allman style". The brace associated with a control statement is placed on the following line,
indented to the same level as the control statement.
Statements within the braces are indented to the next level.
- A single statement block must not include brackets (unless the block uses a macro that expands into multiple lines)
- If possible, avoid 'while (true)' and use 'for (;;)' instead
Refer also to this page for more information -
https://docs.libretro.com/development/coding-standards/
Struct ordering
---------------
For POD-types, try to order structs as follows (first to last):
* long double (8 bytes, 16 bytes [64bit x86], 12 bytes [32bit x86])
* double (8 bytes)
* int64_t (8 bytes, 8 bytes [32bit ARM],
4 bytes [32bit x86])
* uint64_t (4 bytes [32bit], 8 bytes [32bit ARM], 8 bytes [64bit])
* pointer (4 bytes [32bit], 8 bytes [64bit] [1])
* intptr_t (4 bytes [32bit], 8 bytes [64bit] [1])
* uintptr_t (4 bytes [32bit], 8 bytes [64bit] [1])
* ptrdiff_t (4 bytes [32bit], 8 bytes [64bit] [1])
* ssize_t (4 bytes [32bit], 8 bytes [64bit])
* size_t (4 bytes [32bit], 8 bytes [64bit])
* jmp_buf (4 bytes)
* long (4 bytes [64bit Win], 8 bytes [64bit non-Win],
4 bytes [32bit])
* int32_t (4 bytes)
* unsigned (4 bytes)
* float (4 bytes)
* int (4 bytes)
* enum (4 bytes)
* int16_t (2 bytes)
* char (1 byte)
* bool (1 byte)
[1] PS3 uses 4 byte pointers despite having a 64bit processor
Struct members should be sorted by alignment. Therefore, structs
should be sorted by the largest type inside them.
For example, take a struct like this:
typedef struct
{
size_t capacity;
bool old_format;
bool compress;
bool fuzzy_archive_match;
bool autofix_paths;
char path[PATH_MAX_LENGTH];
char base_content_directory[DIR_MAX_LENGTH];
} playlist_config_t;
size_t has the biggest alignment here, so 'struct playlist_config_t'
inside a struct should come before or after size_t.
*** BEST PRACTICES ***
* If we have pointers and size variable pairs, it's best to
interleave them to increase the probability they go in the
same cacheline. It also makes the code more readable, that
these two variables are connected.
Example:
struct a
{
char* b;
size_t b_len;
char* c;
size_t c_len;
};
Stack size
----------
You have to assume that stack size is going to be limited in
RetroArch. Some game consoles (and other embedded systems)
might have a default stack size as low as 128Kb or less.
Be conservative with stack size but don't try to put very
small structs on heap either [to avoid memory fragmentation
among other things]. A balancing act here is necessary.
Be mindful that heap allocations are slow compared to stack.
Functions
---------
- Avoid doing small getter/setter functions. We want a function
to justify its function call overhead by doing a significant
body of work. Small one-line getter/setter functions for what
is predominantly C-style structs is not useful, plus it leads
to people thinking this function is more complex than it
actually is, thus obfuscating the sourcecode instead of it
being easier to read.
If you can find examples in the codebase that violate this
guideline, do not hesitate to point them out to us.
Variable declaration
--------------------
For C source files, we have to insist you stick to the following:
- Declare variables either at the start of a function or the start
of a code block, depending on the scope they need.
- Do not do initial for loop declarations. Refer to the bulletpoint above:
either declare them at the start of the function, or at the start
of the code block.
Not doing this would break compilation on platforms where we are compiling
these C source files in C89 compatibility mode. If such issues occur in pull
requests, we have to request that it be fixed.
VLA (Variable Length Array)
---------------------------
Do not use VLAs (Variable Length Array) in C source files. These are not
C89-compliant.
Miscellaneous
-------------
- Brace usage follows "Allman style". The brace associated with a control statement is placed on the following line,
indented to the same level as the control statement.
Statements within the braces are indented to the next level.
- A single statement block must not include brackets (unless the block uses a macro that expands into multiple lines)
- If possible, avoid 'while (true)' and use 'for (;;)' instead

View File

@ -14,25 +14,39 @@ If there are any issues, we are willing to have discussions about it.
## Submitting Bug Reports
Bug reports in _RetroArch_ may fall into one of two categories:
Bug reports for _RetroArch_ may fall into a few categories:
* _RetroArch_ itself, the user interface and API around all of the various cores.
* Individual _Core_, of which interact with _RetroArch_.
* Individual _Core_, that interacts with _RetroArch_.
* Supplementary data provided within _RetroArch_, such as controller autoconfigs, databases,
thumbnails...
* The [documentation set](https://docs.libretro.com/)
When submitting a bug report, ensure that the report is submitted to the correct repository.
For _RetroArch_ itself, it is done by reporting a bug within the
[RetroArch](https://github.com/libretro/RetroArch) repository. For other cores, please use
the search function within the [libretro Organization](https://github.com/libretro) on
GitHub. Issues that are specific to a core and not _RetroArch_ are likely to be closed very
quickly. If an issue is suspected with _RetroArch_, please make sure to test with multiple
cores to be sure that is is not isolated.
* For _RetroArch_ itself, submit an issue to the [RetroArch](https://github.com/libretro/RetroArch)
repository. Please read and fill the issue template.
* For other cores, please use the search function within the [libretro Organization](https://github.com/libretro)
on GitHub. Issues that are specific to a core and not _RetroArch_ are likely to be closed
very quickly. If an issue is suspected with _RetroArch_, please make sure to test with
multiple cores to be sure that is is not isolated.
* For database content, submit an issue to
[libretro-database repo](https://github.com/libretro/libretro-database) or ask in the
_database_ channel on Discord.
* For controller autoconfigs, submit an issue to
[retroarch-joypad-autoconfig repo](https://github.com/libretro/retroarch-joypad-autoconfig)
* For actual thumbnail images, submit an issue to
[libretro-thumbnails](https://github.com/libretro-thumbnails/libretro-thumbnails) repo
or ask in the _database_ channel on Discord.
* For documentation, submit an issue to [libretro-docs](https://github.com/libretro/libretro-docs)
repo or ask in the _documentation_ channel.
* For translations, please see [here](https://docs.libretro.com/development/retroarch/new-translations-crowdin/).
If the issue occurs during runtime, please paste the verbose log output:
* If using the _Pheonix_ interface, the log will be in _File_ -> _Show Log_.
* If using the main interface, enable verbose logging with _Settings_ -> _Logging_ ->
_Logging Verbosity_. Ensure both _Log to File_ and _Timestamp log Files_ is enabled.
* Otherwise, run _RetroArch_ with the verbose (`-v`) flag.
Set frontend log level to _0 (Debug)_.
* Or run _RetroArch_ with the verbose (`-v`) flag and get the log from the console.
If the error happens during compilation and/or building, paste the output of `./configure`
and `make` accordingly. If using an IDE, please paste any of the errors and log output.

469
Doxyfile
View File

@ -1,4 +1,4 @@
# Doxyfile 1.8.14
# Doxyfile 1.9.1
# This file describes the settings to be used by the documentation system
# doxygen (www.doxygen.org) for a project.
@ -17,10 +17,10 @@
# Project related configuration options
#---------------------------------------------------------------------------
# This tag specifies the encoding used for all characters in the config file
# that follow. The default is UTF-8 which is also the encoding used for all text
# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
# built into libc) for the transcoding. See
# This tag specifies the encoding used for all characters in the configuration
# file that follow. The default is UTF-8 which is also the encoding used for all
# text before the first occurrence of this tag. Doxygen uses libiconv (or the
# iconv built into libc) for the transcoding. See
# https://www.gnu.org/software/libiconv/ for the list of possible encodings.
# The default value is: UTF-8.
@ -32,7 +32,7 @@ DOXYFILE_ENCODING = UTF-8
# title of most generated pages and in a few other places.
# The default value is: My Project.
PROJECT_NAME = "RetroArch"
PROJECT_NAME = RetroArch
# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
# could be handy for archiving the generated documentation or if some version
@ -58,7 +58,7 @@ PROJECT_LOGO =
# entered, it will be relative to the location where doxygen was started. If
# left blank the current directory will be used.
OUTPUT_DIRECTORY =
OUTPUT_DIRECTORY = docs
# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
# directories (in 2 levels) under the output directory of each output format and
@ -93,6 +93,14 @@ ALLOW_UNICODE_NAMES = NO
OUTPUT_LANGUAGE = English
# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all
# documentation generated by doxygen is written. Doxygen will use this
# information to generate all generated output in the proper direction.
# Possible values are: None, LTR, RTL and Context.
# The default value is: None.
OUTPUT_TEXT_DIRECTION = None
# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
# descriptions after the members that are listed in the file and class
# documentation (similar to Javadoc). Set to NO to disable this.
@ -187,7 +195,17 @@ SHORT_NAMES = YES
# description.)
# The default value is: NO.
JAVADOC_AUTOBRIEF = NO
JAVADOC_AUTOBRIEF = YES
# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line
# such as
# /***************
# as being the beginning of a Javadoc-style comment "banner". If set to NO, the
# Javadoc-style will behave just like regular comments and it will not be
# interpreted by doxygen.
# The default value is: NO.
JAVADOC_BANNER = NO
# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
# line (until the first dot) of a Qt-style comment as the brief description. If
@ -209,6 +227,14 @@ QT_AUTOBRIEF = NO
MULTILINE_CPP_IS_BRIEF = NO
# By default Python docstrings are displayed as preformatted text and doxygen's
# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the
# doxygen's special commands can be used and the contents of the docstring
# documentation blocks is shown as doxygen documentation.
# The default value is: YES.
PYTHON_DOCSTRING = YES
# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
# documentation from any documented member that it re-implements.
# The default value is: YES.
@ -238,14 +264,12 @@ TAB_SIZE = 4
# "Side Effects:". You can put \n's in the value part of an alias to insert
# newlines (in the resulting output). You can put ^^ in the value part of an
# alias to insert a newline as if a physical newline was in the original file.
# When you need a literal { or } or , in the value part of an alias you have to
# escape them by means of a backslash (\), this can lead to conflicts with the
# commands \{ and \} for these it is advised to use the version @{ and @} or use
# a double escape (\\{ and \\})
ALIASES =
# This tag can be used to specify a number of word-keyword mappings (TCL only).
# A mapping has the form "name=value". For example adding "class=itcl::class"
# will allow you to use the command class in the itcl::class meaning.
TCL_SUBST =
ALIASES = "setby{1}=@par Set by^^The \1."
# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
# only. Doxygen will then generate output that is more tailored for C. For
@ -253,7 +277,7 @@ TCL_SUBST =
# members will be omitted, etc.
# The default value is: NO.
OPTIMIZE_OUTPUT_FOR_C = NO
OPTIMIZE_OUTPUT_FOR_C = YES
# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
# Python sources only. Doxygen will then generate output that is more tailored
@ -275,28 +299,40 @@ OPTIMIZE_FOR_FORTRAN = NO
OPTIMIZE_OUTPUT_VHDL = NO
# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice
# sources only. Doxygen will then generate output that is more tailored for that
# language. For instance, namespaces will be presented as modules, types will be
# separated into more groups, etc.
# The default value is: NO.
OPTIMIZE_OUTPUT_SLICE = NO
# Doxygen selects the parser to use depending on the extension of the files it
# parses. With this tag you can assign which parser to use for a given
# extension. Doxygen has a built-in mapping, but you can override or extend it
# using this tag. The format is ext=language, where ext is a file extension, and
# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
# Fortran. In the later case the parser tries to guess whether the code is fixed
# or free formatted code, this is the default for Fortran type files), VHDL. For
# instance to make doxygen treat .inc files as Fortran files (default is PHP),
# and .f files as C (default is Fortran), use: inc=Fortran f=C.
# language is one of the parsers supported by doxygen: IDL, Java, JavaScript,
# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, VHDL,
# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran:
# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser
# tries to guess whether the code is fixed or free formatted code, this is the
# default for Fortran type files). For instance to make doxygen treat .inc files
# as Fortran files (default is PHP), and .f files as C (default is Fortran),
# use: inc=Fortran f=C.
#
# Note: For files without extension you can use no_extension as a placeholder.
#
# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
# the files are not read by doxygen.
# the files are not read by doxygen. When specifying no_extension you should add
# * to the FILE_PATTERNS.
#
# Note see also the list of default file extension mappings.
EXTENSION_MAPPING =
# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
# according to the Markdown format, which allows for more readable
# documentation. See http://daringfireball.net/projects/markdown/ for details.
# documentation. See https://daringfireball.net/projects/markdown/ for details.
# The output of markdown processing is further processed by doxygen, so you can
# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
# case of backward compatibilities issues.
@ -308,7 +344,7 @@ MARKDOWN_SUPPORT = YES
# to that level are automatically included in the table of contents, even if
# they do not have an id attribute.
# Note: This feature currently applies only to Markdown headings.
# Minimum value: 0, maximum value: 99, default value: 0.
# Minimum value: 0, maximum value: 99, default value: 5.
# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
TOC_INCLUDE_HEADINGS = 0
@ -398,7 +434,7 @@ INLINE_GROUPED_CLASSES = NO
# Man pages) or section (for LaTeX and RTF).
# The default value is: NO.
INLINE_SIMPLE_STRUCTS = NO
INLINE_SIMPLE_STRUCTS = YES
# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
# enum is documented as struct, union, or enum with the name of the typedef. So
@ -424,6 +460,19 @@ TYPEDEF_HIDES_STRUCT = NO
LOOKUP_CACHE_SIZE = 0
# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use
# during processing. When set to 0 doxygen will based this on the number of
# cores available in the system. You can set it explicitly to a value larger
# than 0 to get more control over the balance between CPU load and processing
# speed. At this moment only the input processing can be done using multiple
# threads. Since this is still an experimental feature the default is set to 1,
# which efficively disables parallel processing. Please report any issues you
# encounter. Generating dot graphs in parallel is controlled by the
# DOT_NUM_THREADS setting.
# Minimum value: 0, maximum value: 32, default value: 1.
NUM_PROC_THREADS = 16
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
@ -442,7 +491,13 @@ EXTRACT_ALL = YES
# be included in the documentation.
# The default value is: NO.
EXTRACT_PRIVATE = YES
EXTRACT_PRIVATE = NO
# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual
# methods of a class will be included in the documentation.
# The default value is: NO.
EXTRACT_PRIV_VIRTUAL = NO
# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
# scope will be included in the documentation.
@ -481,6 +536,13 @@ EXTRACT_LOCAL_METHODS = YES
EXTRACT_ANON_NSPACES = NO
# If this flag is set to YES, the name of an unnamed parameter in a declaration
# will be determined by the corresponding definition. By default unnamed
# parameters remain unnamed in the output.
# The default value is: YES.
RESOLVE_UNNAMED_PARAMS = YES
# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
# undocumented members inside documented classes or files. If set to NO these
# members will be included in the various overviews, but no documentation
@ -498,8 +560,8 @@ HIDE_UNDOC_MEMBERS = NO
HIDE_UNDOC_CLASSES = NO
# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
# (class|struct|union) declarations. If set to NO, these declarations will be
# included in the documentation.
# declarations. If set to NO, these declarations will be included in the
# documentation.
# The default value is: NO.
HIDE_FRIEND_COMPOUNDS = NO
@ -518,11 +580,18 @@ HIDE_IN_BODY_DOCS = NO
INTERNAL_DOCS = NO
# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
# names in lower-case letters. If set to YES, upper-case letters are also
# allowed. This is useful if you have classes or files whose names only differ
# in case and if your file system supports case sensitive file names. Windows
# and Mac users are advised to set this option to NO.
# With the correct setting of option CASE_SENSE_NAMES doxygen will better be
# able to match the capabilities of the underlying filesystem. In case the
# filesystem is case sensitive (i.e. it supports files in the same directory
# whose names only differ in casing), the option must be set to YES to properly
# deal with such files in case they appear in the input. For filesystems that
# are not case sensitive the option should be be set to NO to properly deal with
# output files written for symbols that only differ in casing, such as for two
# classes, one named CLASS and the other named Class, and to also support
# references to files without having to specify the exact matching casing. On
# Windows (including Cygwin) and MacOS, users should typically set this option
# to NO, whereas on Linux or other Unix flavors it should typically be set to
# YES.
# The default value is: system dependent.
CASE_SENSE_NAMES = YES
@ -532,7 +601,7 @@ CASE_SENSE_NAMES = YES
# scope will be hidden.
# The default value is: NO.
HIDE_SCOPE_NAMES = NO
HIDE_SCOPE_NAMES = YES
# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
# append additional text to a page's title, such as Class Reference. If set to
@ -571,7 +640,7 @@ INLINE_INFO = YES
# name. If set to NO, the members will appear in declaration order.
# The default value is: YES.
SORT_MEMBER_DOCS = YES
SORT_MEMBER_DOCS = NO
# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
# descriptions of file, namespace and class members alphabetically by member
@ -754,13 +823,17 @@ WARN_IF_DOC_ERROR = YES
# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
# are documented, but have no documentation for their parameters or return
# value. If set to NO, doxygen will only warn about wrong or incomplete
# parameter documentation, but not about the absence of documentation.
# parameter documentation, but not about the absence of documentation. If
# EXTRACT_ALL is set to YES then this flag will automatically be disabled.
# The default value is: NO.
WARN_NO_PARAMDOC = NO
# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
# a warning is encountered.
# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS
# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but
# at the end of the doxygen process doxygen will return with a non-zero status.
# Possible values are: NO, YES and FAIL_ON_WARNINGS.
# The default value is: NO.
WARN_AS_ERROR = NO
@ -791,13 +864,13 @@ WARN_LOGFILE =
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched.
INPUT =
INPUT = libretro-common
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
# documentation (see: https://www.gnu.org/software/libiconv/) for the list of
# possible encodings.
# documentation (see:
# https://www.gnu.org/software/libiconv/) for the list of possible encodings.
# The default value is: UTF-8.
INPUT_ENCODING = UTF-8
@ -810,56 +883,17 @@ INPUT_ENCODING = UTF-8
# need to set EXTENSION_MAPPING for the extension otherwise the files are not
# read by doxygen.
#
# Note the list of default checked file patterns might differ from the list of
# default file extension mappings.
#
# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf.
# *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C comment),
# *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, *.vhdl,
# *.ucf, *.qsf and *.ice.
FILE_PATTERNS = *.c \
*.cc \
*.cxx \
*.cpp \
*.c++ \
*.java \
*.ii \
*.ixx \
*.ipp \
*.i++ \
*.inl \
*.idl \
*.ddl \
*.odl \
*.h \
*.hh \
*.hxx \
*.hpp \
*.h++ \
*.cs \
*.d \
*.php \
*.php4 \
*.php5 \
*.phtml \
*.inc \
*.m \
*.markdown \
*.md \
*.mm \
*.dox \
*.py \
*.pyw \
*.f90 \
*.f95 \
*.f03 \
*.f08 \
*.f \
*.for \
*.tcl \
*.vhd \
*.vhdl \
*.ucf \
*.qsf
FILE_PATTERNS = *.h
# The RECURSIVE tag can be used to specify whether or not subdirectories should
# be searched for input files as well.
@ -890,7 +924,11 @@ EXCLUDE_SYMLINKS = NO
# Note that the wildcards are matched against the file with absolute path, so to
# exclude all test directories for example use the pattern */test/*
EXCLUDE_PATTERNS =
EXCLUDE_PATTERNS = */libretro-common/rthreads/* \
*/libretro-common/formats/* \
*/libretro-common/crt/* \
*/libretro-common/samples/* \
*/libretro-common/include/glsym/*
# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
# (namespaces, classes, functions, etc.) that should be excluded from the
@ -901,7 +939,9 @@ EXCLUDE_PATTERNS =
# Note that the wildcards are matched against the file with absolute path, so to
# exclude all test directories use the pattern */test/*
EXCLUDE_SYMBOLS =
EXCLUDE_SYMBOLS = bool \
void \
const
# The EXAMPLE_PATH tag can be used to specify one or more files or directories
# that contain example code fragments that are included (see the \include
@ -1012,7 +1052,7 @@ INLINE_SOURCES = NO
STRIP_CODE_COMMENTS = YES
# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
# function all documented functions referencing it will be listed.
# entity all documented functions referencing it will be listed.
# The default value is: NO.
REFERENCED_BY_RELATION = NO
@ -1049,7 +1089,7 @@ SOURCE_TOOLTIPS = YES
#
# To use it do the following:
# - Install the latest version of global
# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file
# - Make sure the INPUT points to the root of the source tree
# - Run doxygen as normal
#
@ -1071,6 +1111,44 @@ USE_HTAGS = NO
VERBATIM_HEADERS = YES
# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
# clang parser (see:
# http://clang.llvm.org/) for more accurate parsing at the cost of reduced
# performance. This can be particularly helpful with template rich C++ code for
# which doxygen's built-in parser lacks the necessary type information.
# Note: The availability of this option depends on whether or not doxygen was
# generated with the -Duse_libclang=ON option for CMake.
# The default value is: NO.
CLANG_ASSISTED_PARSING = NO
# If clang assisted parsing is enabled and the CLANG_ADD_INC_PATHS tag is set to
# YES then doxygen will add the directory of each input to the include path.
# The default value is: YES.
CLANG_ADD_INC_PATHS = YES
# If clang assisted parsing is enabled you can provide the compiler with command
# line options that you would normally use when invoking the compiler. Note that
# the include paths will already be set by doxygen for the files and directories
# specified with INPUT and INCLUDE_PATH.
# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
CLANG_OPTIONS =
# If clang assisted parsing is enabled you can provide the clang parser with the
# path to the directory containing a file called compile_commands.json. This
# file is the compilation database (see:
# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the
# options used when the source files were built. This is equivalent to
# specifying the -p option to a clang tool, such as clang-check. These options
# will then be passed to the parser. Any options specified with CLANG_OPTIONS
# will be added as well.
# Note: The availability of this option depends on whether or not doxygen was
# generated with the -Duse_libclang=ON option for CMake.
CLANG_DATABASE_PATH =
#---------------------------------------------------------------------------
# Configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
@ -1082,20 +1160,14 @@ VERBATIM_HEADERS = YES
ALPHABETICAL_INDEX = YES
# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
# which the alphabetical index list will be split.
# Minimum value: 1, maximum value: 20, default value: 5.
# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
COLS_IN_ALPHA_INDEX = 5
# In case all classes in a project start with a common prefix, all classes will
# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
# can be used to specify a prefix (or a list of prefixes) that should be ignored
# while generating the index headers.
# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
IGNORE_PREFIX =
IGNORE_PREFIX = retro_ \
RETRO_
#---------------------------------------------------------------------------
# Configuration options related to the HTML output
@ -1227,9 +1299,9 @@ HTML_TIMESTAMP = NO
# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
# documentation will contain a main index with vertical navigation menus that
# are dynamically created via Javascript. If disabled, the navigation index will
# are dynamically created via JavaScript. If disabled, the navigation index will
# consists of multiple levels of tabs that are statically embedded in every HTML
# page. Disable this option to support browsers that do not have Javascript,
# page. Disable this option to support browsers that do not have JavaScript,
# like the Qt help browser.
# The default value is: YES.
# This tag requires that the tag GENERATE_HTML is set to YES.
@ -1259,13 +1331,14 @@ HTML_INDEX_NUM_ENTRIES = 100
# If the GENERATE_DOCSET tag is set to YES, additional index files will be
# generated that can be used as input for Apple's Xcode 3 integrated development
# environment (see: https://developer.apple.com/tools/xcode/), introduced with
# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
# Makefile in the HTML output directory. Running make will produce the docset in
# that directory and running make install will install the docset in
# environment (see:
# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To
# create a documentation set, doxygen will generate a Makefile in the HTML
# output directory. Running make will produce the docset in that directory and
# running make install will install the docset in
# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
# startup. See https://developer.apple.com/tools/creatingdocsetswithdoxygen.html
# for more information.
# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy
# genXcode/_index.html for more information.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
@ -1304,8 +1377,8 @@ DOCSET_PUBLISHER_NAME = Publisher
# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
# Windows.
# (see:
# https://www.microsoft.com/en-us/download/details.aspx?id=21138) on Windows.
#
# The HTML Help Workshop contains a compiler that can convert all HTML output
# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
@ -1335,7 +1408,7 @@ CHM_FILE =
HHC_LOCATION =
# The GENERATE_CHI flag controls if a separate .chi index file is generated
# (YES) or that it should be included in the master .chm file (NO).
# (YES) or that it should be included in the main .chm file (NO).
# The default value is: NO.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
@ -1380,7 +1453,8 @@ QCH_FILE =
# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
# Project output. For more information please see Qt Help Project / Namespace
# (see: http://doc.qt.io/qt-4.8/qthelpproject.html#namespace).
# (see:
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
# The default value is: org.doxygen.Project.
# This tag requires that the tag GENERATE_QHP is set to YES.
@ -1388,7 +1462,8 @@ QHP_NAMESPACE = org.doxygen.Project
# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
# Help Project output. For more information please see Qt Help Project / Virtual
# Folders (see: http://doc.qt.io/qt-4.8/qthelpproject.html#virtual-folders).
# Folders (see:
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders).
# The default value is: doc.
# This tag requires that the tag GENERATE_QHP is set to YES.
@ -1396,28 +1471,30 @@ QHP_VIRTUAL_FOLDER = doc
# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
# filter to add. For more information please see Qt Help Project / Custom
# Filters (see: http://doc.qt.io/qt-4.8/qthelpproject.html#custom-filters).
# Filters (see:
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_CUST_FILTER_NAME =
# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
# custom filter to add. For more information please see Qt Help Project / Custom
# Filters (see: http://doc.qt.io/qt-4.8/qthelpproject.html#custom-filters).
# Filters (see:
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_CUST_FILTER_ATTRS =
# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
# project's filter section matches. Qt Help Project / Filter Attributes (see:
# http://doc.qt.io/qt-4.8/qthelpproject.html#filter-attributes).
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes).
# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_SECT_FILTER_ATTRS =
# The QHG_LOCATION tag can be used to specify the location of Qt's
# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
# generated .qhp file.
# The QHG_LOCATION tag can be used to specify the location (absolute path
# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to
# run qhelpgenerator on the generated .qhp file.
# This tag requires that the tag GENERATE_QHP is set to YES.
QHG_LOCATION =
@ -1468,7 +1545,7 @@ DISABLE_INDEX = NO
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
GENERATE_TREEVIEW = NO
GENERATE_TREEVIEW = YES
# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
# doxygen will group on one line in the generated HTML documentation.
@ -1494,6 +1571,17 @@ TREEVIEW_WIDTH = 250
EXT_LINKS_IN_WINDOW = NO
# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg
# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see
# https://inkscape.org) to generate formulas as SVG images instead of PNGs for
# the HTML output. These images will generally look nicer at scaled resolutions.
# Possible values are: png (the default) and svg (looks nicer but requires the
# pdf2svg or inkscape tool).
# The default value is: png.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_FORMULA_FORMAT = png
# Use this tag to change the font size of LaTeX formulas included as images in
# the HTML documentation. When you change the font size after a successful
# doxygen run you need to manually remove any form_*.png images from the HTML
@ -1514,8 +1602,14 @@ FORMULA_FONTSIZE = 10
FORMULA_TRANSPARENT = YES
# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands
# to create new LaTeX commands to be used in formulas as building blocks. See
# the section "Including formulas" for details.
FORMULA_MACROFILE =
# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
# https://www.mathjax.org) which uses client side Javascript for the rendering
# https://www.mathjax.org) which uses client side JavaScript for the rendering
# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
# installed or if you want to formulas look prettier in the HTML output. When
# enabled you may also need to install MathJax separately and configure the path
@ -1527,7 +1621,7 @@ USE_MATHJAX = NO
# When MathJax is enabled you can set the default output format to be used for
# the MathJax output. See the MathJax site (see:
# http://docs.mathjax.org/en/latest/output.html) for more details.
# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details.
# Possible values are: HTML-CSS (which is slower, but has the best
# compatibility), NativeMML (i.e. MathML) and SVG.
# The default value is: HTML-CSS.
@ -1543,7 +1637,7 @@ MATHJAX_FORMAT = HTML-CSS
# Content Delivery Network so you can quickly see the result without installing
# MathJax. However, it is strongly recommended to install a local copy of
# MathJax from https://www.mathjax.org before deployment.
# The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/.
# The default value is: https://cdn.jsdelivr.net/npm/mathjax@2.
# This tag requires that the tag USE_MATHJAX is set to YES.
MATHJAX_RELPATH = https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/
@ -1557,7 +1651,8 @@ MATHJAX_EXTENSIONS =
# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
# of code that will be used on startup of the MathJax code. See the MathJax site
# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
# (see:
# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an
# example see the documentation.
# This tag requires that the tag USE_MATHJAX is set to YES.
@ -1585,7 +1680,7 @@ MATHJAX_CODEFILE =
SEARCHENGINE = YES
# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
# implemented using a web server instead of a web client using Javascript. There
# implemented using a web server instead of a web client using JavaScript. There
# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
# setting. When disabled, doxygen will generate a PHP script for searching and
# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
@ -1604,7 +1699,8 @@ SERVER_BASED_SEARCH = NO
#
# Doxygen ships with an example indexer (doxyindexer) and search engine
# (doxysearch.cgi) which are based on the open source search engine library
# Xapian (see: https://xapian.org/).
# Xapian (see:
# https://xapian.org/).
#
# See the section "External Indexing and Searching" for details.
# The default value is: NO.
@ -1617,8 +1713,9 @@ EXTERNAL_SEARCH = NO
#
# Doxygen ships with an example indexer (doxyindexer) and search engine
# (doxysearch.cgi) which are based on the open source search engine library
# Xapian (see: https://xapian.org/). See the section "External Indexing and
# Searching" for details.
# Xapian (see:
# https://xapian.org/). See the section "External Indexing and Searching" for
# details.
# This tag requires that the tag SEARCHENGINE is set to YES.
SEARCHENGINE_URL =
@ -1669,21 +1766,35 @@ LATEX_OUTPUT = latex
# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
# invoked.
#
# Note that when enabling USE_PDFLATEX this option is only used for generating
# bitmaps for formulas in the HTML output, but not in the Makefile that is
# written to the output directory.
# The default file is: latex.
# Note that when not enabling USE_PDFLATEX the default is latex when enabling
# USE_PDFLATEX the default is pdflatex and when in the later case latex is
# chosen this is overwritten by pdflatex. For specific output languages the
# default can have been set differently, this depends on the implementation of
# the output language.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_CMD_NAME = latex
# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
# index for LaTeX.
# Note: This tag is used in the Makefile / make.bat.
# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file
# (.tex).
# The default file is: makeindex.
# This tag requires that the tag GENERATE_LATEX is set to YES.
MAKEINDEX_CMD_NAME = makeindex
# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to
# generate index for LaTeX. In case there is no backslash (\) as first character
# it will be automatically added in the LaTeX code.
# Note: This tag is used in the generated output file (.tex).
# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat.
# The default value is: makeindex.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_MAKEINDEX_CMD = makeindex
# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
# documents. This may be useful for small projects and may help to save some
# trees in general.
@ -1768,9 +1879,11 @@ LATEX_EXTRA_FILES =
PDF_HYPERLINKS = YES
# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
# the PDF file directly from the LaTeX files. Set this option to YES, to get a
# higher quality PDF documentation.
# If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as
# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX
# files. Set this option to YES, to get a higher quality PDF documentation.
#
# See also section LATEX_CMD_NAME for selecting the engine.
# The default value is: YES.
# This tag requires that the tag GENERATE_LATEX is set to YES.
@ -1818,6 +1931,14 @@ LATEX_BIB_STYLE = plain
LATEX_TIMESTAMP = NO
# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)
# path from which the emoji images will be read. If a relative path is entered,
# it will be relative to the LATEX_OUTPUT directory. If left blank the
# LATEX_OUTPUT directory will be used.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_EMOJI_DIRECTORY =
#---------------------------------------------------------------------------
# Configuration options related to the RTF output
#---------------------------------------------------------------------------
@ -1857,9 +1978,9 @@ COMPACT_RTF = NO
RTF_HYPERLINKS = NO
# Load stylesheet definitions from file. Syntax is similar to doxygen's config
# file, i.e. a series of assignments. You only have to provide replacements,
# missing definitions are set to their default value.
# Load stylesheet definitions from file. Syntax is similar to doxygen's
# configuration file, i.e. a series of assignments. You only have to provide
# replacements, missing definitions are set to their default value.
#
# See also section "Doxygen usage" for information on how to generate the
# default style sheet that doxygen normally uses.
@ -1868,8 +1989,8 @@ RTF_HYPERLINKS = NO
RTF_STYLESHEET_FILE =
# Set optional variables used in the generation of an RTF document. Syntax is
# similar to doxygen's config file. A template extensions file can be generated
# using doxygen -e rtf extensionFile.
# similar to doxygen's configuration file. A template extensions file can be
# generated using doxygen -e rtf extensionFile.
# This tag requires that the tag GENERATE_RTF is set to YES.
RTF_EXTENSIONS_FILE =
@ -1955,6 +2076,13 @@ XML_OUTPUT = xml
XML_PROGRAMLISTING = YES
# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include
# namespace members in file scope as well, matching the HTML output.
# The default value is: NO.
# This tag requires that the tag GENERATE_XML is set to YES.
XML_NS_MEMB_FILE_SCOPE = NO
#---------------------------------------------------------------------------
# Configuration options related to the DOCBOOK output
#---------------------------------------------------------------------------
@ -1994,6 +2122,10 @@ DOCBOOK_PROGRAMLISTING = NO
GENERATE_AUTOGEN_DEF = NO
#---------------------------------------------------------------------------
# Configuration options related to Sqlite3 output
#---------------------------------------------------------------------------
#---------------------------------------------------------------------------
# Configuration options related to the Perl module output
#---------------------------------------------------------------------------
@ -2089,7 +2221,7 @@ INCLUDE_FILE_PATTERNS =
# recursively expanded use the := operator instead of the = operator.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
PREDEFINED =
PREDEFINED = DOXYGEN
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
# tag can be used to specify a list of macro names that should be expanded. The
@ -2156,12 +2288,6 @@ EXTERNAL_GROUPS = YES
EXTERNAL_PAGES = YES
# The PERL_PATH should be the absolute path and name of the perl script
# interpreter (i.e. the result of 'which perl').
# The default file (with absolute path) is: /usr/bin/perl.
PERL_PATH = /usr/bin/perl
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
@ -2173,16 +2299,7 @@ PERL_PATH = /usr/bin/perl
# powerful graphs.
# The default value is: YES.
CLASS_DIAGRAMS = YES
# You can define message sequence charts within doxygen comments using the \msc
# command. Doxygen will then run the mscgen tool (see:
# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
# documentation. The MSCGEN_PATH tag allows you to specify the directory where
# the mscgen tool resides. If left empty the tool is assumed to be found in the
# default search path.
MSCGEN_PATH =
CLASS_DIAGRAMS = NO
# You can include diagrams made with dia in doxygen documentation. Doxygen will
# then run dia to produce the diagram and insert it in the documentation. The
@ -2202,9 +2319,9 @@ HIDE_UNDOC_RELATIONS = YES
# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
# Bell Labs. The other options in this section have no effect if this option is
# set to NO
# The default value is: NO.
# The default value is: YES.
HAVE_DOT = YES
HAVE_DOT = NO
# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
# to run in parallel. When set to 0 doxygen will base this on the number of
@ -2281,10 +2398,32 @@ UML_LOOK = NO
# but if the number exceeds 15, the total amount of fields shown is limited to
# 10.
# Minimum value: 0, maximum value: 100, default value: 10.
# This tag requires that the tag HAVE_DOT is set to YES.
# This tag requires that the tag UML_LOOK is set to YES.
UML_LIMIT_NUM_FIELDS = 10
# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and
# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS
# tag is set to YES, doxygen will add type and arguments for attributes and
# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen
# will not generate fields with class member information in the UML graphs. The
# class diagrams will look similar to the default class diagrams but using UML
# notation for the relationships.
# Possible values are: NO, YES and NONE.
# The default value is: NO.
# This tag requires that the tag UML_LOOK is set to YES.
DOT_UML_DETAILS = NO
# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters
# to display on a single line. If the actual line length exceeds this threshold
# significantly it will wrapped across multiple lines. Some heuristics are apply
# to avoid ugly line breaks.
# Minimum value: 0, maximum value: 1000, default value: 17.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_WRAP_THRESHOLD = 17
# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
# collaboration graphs will show the relations between templates and their
# instances.
@ -2358,7 +2497,9 @@ DIRECTORY_GRAPH = YES
# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
# to make the SVG files visible in IE 9+ (other browsers do not have this
# requirement).
# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo,
# Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd,
# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo,
# gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd, png:cairo,
# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
# png:gdiplus:gdiplus.
# The default value is: png.
@ -2474,9 +2615,11 @@ DOT_MULTI_TARGETS = YES
GENERATE_LEGEND = YES
# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate
# files that are used to generate the various graphs.
#
# Note: This setting is not only used for dot files but also for msc and
# plantuml temporary files.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_CLEANUP = YES

View File

@ -226,7 +226,7 @@ $(OBJDIR)/%.o: %.S config.h config.mk $(HEADERS)
$(OBJDIR)/%.o: %.rc $(HEADERS)
@mkdir -p $(dir $@)
@$(if $(Q), $(shell echo echo WINDRES $<),)
$(Q)$(WINDRES) -o $@ $<
$(Q)$(WINDRES) $(DEFINES) -o $@ $<
install: $(TARGET)
mkdir -p $(DESTDIR)$(BIN_DIR) 2>/dev/null || /bin/true
@ -239,21 +239,21 @@ install: $(TARGET)
cp $(TARGET) $(DESTDIR)$(BIN_DIR)
cp tools/cg2glsl.py $(DESTDIR)$(BIN_DIR)/retroarch-cg2glsl
cp retroarch.cfg $(DESTDIR)$(GLOBAL_CONFIG_DIR)
cp com.libretro.RetroArch.appdata.xml $(DESTDIR)$(DATA_DIR)/metainfo
cp retroarch.desktop $(DESTDIR)$(DATA_DIR)/applications
cp com.libretro.RetroArch.metainfo.xml $(DESTDIR)$(DATA_DIR)/metainfo
cp com.libretro.RetroArch.desktop $(DESTDIR)$(DATA_DIR)/applications
cp docs/retroarch.6 $(DESTDIR)$(MAN_DIR)/man6
cp docs/retroarch-cg2glsl.6 $(DESTDIR)$(MAN_DIR)/man6
cp media/retroarch.svg $(DESTDIR)$(DATA_DIR)/pixmaps
cp media/com.libretro.RetroArch.svg $(DESTDIR)$(DATA_DIR)/pixmaps
cp COPYING $(DESTDIR)$(DOC_DIR)
cp README.md $(DESTDIR)$(DOC_DIR)
chmod 755 $(DESTDIR)$(BIN_DIR)/$(TARGET)
chmod 755 $(DESTDIR)$(BIN_DIR)/retroarch-cg2glsl
chmod 644 $(DESTDIR)$(GLOBAL_CONFIG_DIR)/retroarch.cfg
chmod 644 $(DESTDIR)$(DATA_DIR)/applications/retroarch.desktop
chmod 644 $(DESTDIR)$(DATA_DIR)/metainfo/com.libretro.RetroArch.appdata.xml
chmod 644 $(DESTDIR)$(DATA_DIR)/applications/com.libretro.RetroArch.desktop
chmod 644 $(DESTDIR)$(DATA_DIR)/metainfo/com.libretro.RetroArch.metainfo.xml
chmod 644 $(DESTDIR)$(MAN_DIR)/man6/retroarch.6
chmod 644 $(DESTDIR)$(MAN_DIR)/man6/retroarch-cg2glsl.6
chmod 644 $(DESTDIR)$(DATA_DIR)/pixmaps/retroarch.svg
chmod 644 $(DESTDIR)$(DATA_DIR)/pixmaps/com.libretro.RetroArch.svg
@if test -d media/assets && test $(HAVE_ASSETS); then \
echo "Installing media assets..."; \
mkdir -p $(DESTDIR)$(ASSETS_DIR)/assets; \
@ -274,9 +274,9 @@ uninstall:
rm -f $(DESTDIR)$(BIN_DIR)/$(TARGET)
rm -f $(DESTDIR)$(BIN_DIR)/retroarch-cg2glsl
rm -f $(DESTDIR)$(GLOBAL_CONFIG_DIR)/retroarch.cfg
rm -f $(DESTDIR)$(DATA_DIR)/applications/retroarch.desktop
rm -f $(DESTDIR)$(DATA_DIR)/metainfo/com.libretro.RetroArch.appdata.xml
rm -f $(DESTDIR)$(DATA_DIR)/pixmaps/retroarch.svg
rm -f $(DESTDIR)$(DATA_DIR)/applications/com.libretro.RetroArch.desktop
rm -f $(DESTDIR)$(DATA_DIR)/metainfo/com.libretro.RetroArch.metainfo.xml
rm -f $(DESTDIR)$(DATA_DIR)/pixmaps/com.libretro.RetroArch.svg
rm -f $(DESTDIR)$(DOC_DIR)/COPYING
rm -f $(DESTDIR)$(DOC_DIR)/COPYING.assets
rm -f $(DESTDIR)$(DOC_DIR)/README.md

View File

@ -15,7 +15,9 @@ ifeq ($(HAVE_NOUNUSED_VARIABLE), 1)
DEF_FLAGS += $(NOUNUSED_VARIABLE_CFLAGS)
endif
ifeq ($(HAVE_CXX11), 1)
ifeq ($(HAVE_QT6), 1)
CXXFLAGS += $(CXX17_CFLAGS)
else ifeq ($(HAVE_CXX11), 1)
CXXFLAGS += $(CXX11_CFLAGS)
endif
@ -240,20 +242,37 @@ OBJ += frontend/frontend_driver.o \
ui/ui_companion_driver.o \
camera/camera_driver.o \
record/record_driver.o \
record/drivers/record_wav.o \
command.o \
msg_hash.o \
midi_driver.o \
location_driver.o \
intl/msg_hash_us.o \
$(LIBRETRO_COMM_DIR)/queues/task_queue.o \
tasks/task_content.o
ifeq ($(HAVE_PATCH), 1)
DEFINES += -DHAVE_PATCH
OBJ += tasks/task_patch.o
OBJ += tasks/task_patch.o
ifeq ($(HAVE_XDELTA), 1)
DEFINES += -DHAVE_XDELTA -DSECONDARY_DJW -DSECONDARY_LZMA -DSECONDARY_FGK
INCLUDE_DIRS += -I$(DEPS_DIR)/xdelta3 -I$(LIBRETRO_COMM_DIR)
LIBS += -llzma
OBJ += $(DEPS_DIR)/xdelta3/xdelta3.o
HEADERS += xdelta3.h \
xdelta3-cfgs.h \
xdelta3-fgk.h \
xdelta3-hash.h \
xdelta3-internal.h \
xdelta3-list.h \
xdelta3-lzma.h \
xdelta3-second.h
# These headers are added to the makefile because xdelta3 does weird things
# with its #includes, which affects dependency tracking and project analysis
# (e.g. for IDEs).
endif
endif
OBJ += \
save.o \
tasks/task_save.o \
tasks/task_movie.o \
tasks/task_file_transfer.o \
@ -319,14 +338,17 @@ OBJ += \
gfx/video_driver.o \
gfx/gfx_display.o \
gfx/gfx_animation.o \
gfx/gfx_thumbnail_path.o \
gfx/gfx_thumbnail.o \
gfx/video_coord_array.o \
configuration.o \
$(LIBRETRO_COMM_DIR)/dynamic/dylib.o \
cores/dynamic_dummy.o \
$(LIBRETRO_COMM_DIR)/queues/message_queue.o
ifeq ($(HAVE_MENU), 1)
OBJ += \
gfx/gfx_thumbnail_path.o \
gfx/gfx_thumbnail.o
endif
ifeq ($(HAVE_MICROPHONE), 1)
DEFINES += -DHAVE_MICROPHONE
OBJ += audio/microphone_driver.o
@ -449,9 +471,6 @@ endif
ifeq ($(HAVE_LANGEXTRA), 1)
DEFINES += -DHAVE_LANGEXTRA
DEF_FLAGS += -finput-charset=UTF-8
OBJ += intl/msg_hash_chs.o \
intl/msg_hash_pt_br.o
endif
ifneq ($(HAVE_GETOPT_LONG), 1)
@ -518,10 +537,18 @@ ifeq ($(HAVE_QT), 1)
endif
DEFINES += -DHAVE_MAIN
ifeq ($(HAVE_QT6), 1)
CXXFLAGS += -DQT_DISABLE_DEPRECATED_BEFORE=0x060000 $(QT6CORE_CFLAGS) $(QT6GUI_CFLAGS) $(QT6WIDGETS_CFLAGS) $(QT6CONCURRENT_CFLAGS) $(QT6NETWORK_CFLAGS)
#DEF_FLAGS += $(QT6WEBENGINE_CFLAGS)
LIBS += $(QT6CORE_LIBS) $(QT6GUI_LIBS) $(QT6WIDGETS_LIBS) $(QT6CONCURRENT_LIBS) $(QT6NETWORK_LIBS)
#LIBS += $(QT6WEBENGINE_LIBS)
else
DEF_FLAGS += $(QT5CORE_CFLAGS) $(QT5GUI_CFLAGS) $(QT5WIDGETS_CFLAGS) $(QT5CONCURRENT_CFLAGS) $(QT5NETWORK_CFLAGS)
#DEF_FLAGS += $(QT5WEBENGINE_CFLAGS)
LIBS += $(QT5CORE_LIBS) $(QT5GUI_LIBS) $(QT5WIDGETS_LIBS) $(QT5CONCURRENT_LIBS) $(QT5NETWORK_LIBS)
#LIBS += $(QT5WEBENGINE_LIBS)
endif
NEED_CXX_LINKER = 1
ifneq ($(findstring Linux,$(OS)),)
@ -741,7 +768,8 @@ else ifeq ($(HAVE_BUILTINMBEDTLS), 1)
OBJ += $(OBJS_TLS_CRYPTO) $(OBJS_TLS_X509) $(OBJS_TLS)
else ifeq ($(HAVE_SSL), 1)
DEFINES += -DHAVE_SSL
LIBS += $(SYSTEMMBEDTLS_LIBS)
LIBS += $(SYSTEMMBEDTLS_LIBS) $(SYSTEMMBEDX509_LIBS) $(SYSTEMMBEDCRYPTO_LIBS)
DEF_FLAGS += $(SYSTEMMBEDTLS_CFLAGS) $(SYSTEMMBEDX509_CFLAGS) $(SYSTEMMBEDCRYPTO_CFLAGS)
endif
# Miscellaneous
@ -1044,16 +1072,22 @@ endif
ifeq ($(HAVE_LAKKA), 1)
DEFINES += -DHAVE_LAKKA
ifneq ($(HAVE_LAKKA_PROJECT),)
DEFINES += -DHAVE_LAKKA_PROJECT=\"${HAVE_LAKKA_PROJECT}\"
else
$(error You asked for Lakka, but you did not specify a target device name in HAVE_LAKKA_PROJECT)
endif
ifneq ($(HAVE_LAKKA_SERVER),)
DEFINES += -DHAVE_LAKKA_SERVER=\"${HAVE_LAKKA_SERVER}\"
else
$(error You asked for Lakka, but you did not specify update server in HAVE_LAKKA_SERVER)
endif
endif
ifeq ($(HAVE_LAKKA_SWITCH), 1)
DEFINES += -DHAVE_LAKKA_SWITCH
endif
ifeq ($(HAVE_LAKKA_NIGHTLY), 1)
DEFINES += -DHAVE_LAKKA_NIGHTLY
endif
ifeq ($(HAVE_MENU_COMMON), 1)
OBJ += menu/menu_setting.o \
menu/menu_driver.o \
@ -1223,6 +1257,7 @@ ifeq ($(HAVE_WAYLAND), 1)
input/common/wayland_common.o \
input/drivers/wayland_input.o \
gfx/common/wayland_common.o \
gfx/common/wayland/fractional-scale-v1.o \
gfx/common/wayland/viewporter.o \
gfx/common/wayland/xdg-shell.o \
gfx/common/wayland/idle-inhibit-unstable-v1.o \
@ -1286,6 +1321,9 @@ ifeq ($(HAVE_X11), 1)
ifeq ($(HAVE_XCB),1)
LIBS += -lX11-xcb
endif
ifeq ($(HAVE_XSCRNSAVER),1)
LIBS += -lXss
endif
ifneq ($(HAVE_OPENGLES), 1)
OBJ += gfx/drivers_context/x_ctx.o
endif
@ -1822,10 +1860,6 @@ ifeq ($(HAVE_BUILTINGLSLANG), 1)
$(wildcard $(DEPS_DIR)/glslang/glslang/glslang/MachineIndependent/*.cpp) \
$(wildcard $(DEPS_DIR)/glslang/glslang/glslang/MachineIndependent/preprocessor/*.cpp) \
$(DEPS_DIR)/glslang/glslang/glslang/OSDependent/$(GLSLANG_PLATFORM)/ossource.cpp
ifneq ($(findstring Win32,$(OS)),)
DEFINES += -DENABLE_HLSL
GLSLANG_SOURCES += $(wildcard $(DEPS_DIR)/glslang/glslang/hlsl/*.cpp)
endif
else ifeq ($(HAVE_GLSLANG),1)
HAVE_GLSLANG_COMMON = 1
GLSLANG_SOURCES := gfx/drivers_shader/glslang.cpp
@ -1836,7 +1870,6 @@ else ifeq ($(HAVE_GLSLANG),1)
$(GLSLANG_GENERICCODEGEN_LIBS) \
$(GLSLANG_OSDEPENDENT_LIBS) \
$(GLSLANG_OGLCOMPILER_LIBS) \
$(GLSLANG_HLSL_LIBS) \
$(GLSLANG_SPIRV_LIBS) \
$(GLSLANG_SPIRV_TOOLS_OPT_LIBS) \
$(GLSLANG_SPIRV_TOOLS_LIBS)
@ -1967,6 +2000,90 @@ ifeq ($(HAVE_ZLIB_COMMON), 1)
ifeq ($(HAVE_CHD), 1)
INCLUDE_DIRS += -I$(LIBRETRO_COMM_DIR)/formats/libchdr
DEFINES += -DHAVE_CHD -DWANT_SUBCODE -DWANT_RAW_DATA_SECTOR
ifeq ($(HAVE_STATIC_CORES), 1)
DEFINES += -Dbitstream_overflow=retroarch_internal_bitstream_overflow
DEFINES += -Dcreate_bitstream=retroarch_internal_create_bitstream
DEFINES += -Dbitstream_peek=retroarch_internal_bitstream_peek
DEFINES += -Dbitstream_remove=retroarch_internal_bitstream_remove
DEFINES += -Dbitstream_read=retroarch_internal_bitstream_read
DEFINES += -Dbitstream_read_offset=retroarch_internal_bitstream_read_offset
DEFINES += -Dbitstream_flush=retroarch_internal_bitstream_flush
DEFINES += -Decc_compute_bytes=retroarch_internal_ecc_compute_bytes
DEFINES += -Decc_verify=retroarch_internal_ecc_verify
DEFINES += -Decc_generate=retroarch_internal_ecc_generate
DEFINES += -Decc_clear=retroarch_internal_ecc_clear
DEFINES += -Ds_cd_sync_header=retroarch_internal_s_cd_sync_header
DEFINES += -Dchd_open_file=retroarch_internal_chd_open_file
DEFINES += -Dchd_precache=retroarch_internal_chd_precache
DEFINES += -Dchd_open=retroarch_internal_chd_open
DEFINES += -Dchd_close=retroarch_internal_chd_close
DEFINES += -Dchd_core_file=retroarch_internal_chd_core_file
DEFINES += -Dchd_error_string=retroarch_internal_chd_error_string
DEFINES += -Dchd_get_header=retroarch_internal_chd_get_header
DEFINES += -Dchd_read=retroarch_internal_chd_read
DEFINES += -Dchd_get_metadata=retroarch_internal_chd_get_metadata
DEFINES += -Dchd_codec_config=retroarch_internal_chd_codec_config
DEFINES += -Dchd_get_codec_name=retroarch_internal_chd_get_codec_name
DEFINES += -Dcreate_huffman_decoder=retroarch_internal_create_huffman_decoder
DEFINES += -Ddelete_huffman_decoder=retroarch_internal_delete_huffman_decoder
DEFINES += -Dhuffman_decode_one=retroarch_internal_huffman_decode_one
DEFINES += -Dhuffman_import_tree_rle=retroarch_internal_huffman_import_tree_rle
DEFINES += -Dhuffman_import_tree_huffman=retroarch_internal_huffman_import_tree_huffman
DEFINES += -Dhuffman_compute_tree_from_histo=retroarch_internal_huffman_compute_tree_from_histo
DEFINES += -Dhuffman_build_tree=retroarch_internal_huffman_build_tree
DEFINES += -Dhuffman_assign_canonical_codes=retroarch_internal_huffman_assign_canonical_codes
DEFINES += -Dhuffman_build_lookup_table=retroarch_internal_huffman_build_lookup_table
DEFINES += -Dcdzl_codec_init=retroarch_internal_cdzl_codec_init
DEFINES += -Dcdzl_codec_free=retroarch_internal_cdzl_codec_free
DEFINES += -Dcdzl_codec_decompress=retroarch_internal_cdzl_codec_decompress
DEFINES += -Dzlib_codec_init=retroarch_internal_zlib_codec_init
DEFINES += -Dzlib_codec_free=retroarch_internal_zlib_codec_free
DEFINES += -Dzlib_codec_decompress=retroarch_internal_zlib_codec_decompress
DEFINES += -Dzlib_fast_alloc=retroarch_internal_zlib_fast_alloc
DEFINES += -Dzlib_fast_free=retroarch_internal_zlib_fast_free
DEFINES += -Dchdstream_open=retroarch_internal_chdstream_open
DEFINES += -Dchdstream_close=retroarch_internal_chdstream_close
DEFINES += -Dchdstream_read=retroarch_internal_chdstream_read
DEFINES += -Dchdstream_getc=retroarch_internal_chdstream_getc
DEFINES += -Dchdstream_gets=retroarch_internal_chdstream_gets
DEFINES += -Dchdstream_tell=retroarch_internal_chdstream_tell
DEFINES += -Dchdstream_rewind=retroarch_internal_chdstream_rewind
DEFINES += -Dchdstream_seek=retroarch_internal_chdstream_seek
DEFINES += -Dchdstream_get_size=retroarch_internal_chdstream_get_size
DEFINES += -Dchdstream_get_track_start=retroarch_internal_chdstream_get_track_start
DEFINES += -Dchdstream_get_frame_size=retroarch_internal_chdstream_get_frame_size
DEFINES += -Dchdstream_get_first_track_sector=retroarch_internal_chdstream_get_first_track_sector
DEFINES += -Dflac_decoder_init=retroarch_internal_flac_decoder_init
DEFINES += -Dflac_decoder_free=retroarch_internal_flac_decoder_free
DEFINES += -Dflac_decoder_reset=retroarch_internal_flac_decoder_reset
DEFINES += -Dflac_decoder_decode_interleaved=retroarch_internal_flac_decoder_decode_interleaved
DEFINES += -Dflac_decoder_finish=retroarch_internal_flac_decoder_finish
DEFINES += -Dflac_decoder_read_callback_static=retroarch_internal_flac_decoder_read_callback_static
DEFINES += -Dflac_decoder_read_callback=retroarch_internal_flac_decoder_read_callback
DEFINES += -Dflac_decoder_metadata_callback_static=retroarch_internal_flac_decoder_metadata_callback_static
DEFINES += -Dflac_decoder_tell_callback_static=retroarch_internal_flac_decoder_tell_callback_static
DEFINES += -Dflac_decoder_write_callback_static=retroarch_internal_flac_decoder_write_callback_static
DEFINES += -Dflac_decoder_write_callback=retroarch_internal_flac_decoder_write_callback
DEFINES += -Dflac_decoder_error_callback_static=retroarch_internal_flac_decoder_error_callback_static
DEFINES += -Dcdfl_codec_init=retroarch_internal_cdfl_codec_init
DEFINES += -Dcdfl_codec_free=retroarch_internal_cdfl_codec_free
DEFINES += -Dcdfl_codec_decompress=retroarch_internal_cdfl_codec_decompress
DEFINES += -Dlzma_allocator_init=retroarch_internal_lzma_allocator_init
DEFINES += -Dlzma_allocator_free=retroarch_internal_lzma_allocator_free
DEFINES += -Dlzma_codec_init=retroarch_internal_lzma_codec_init
DEFINES += -Dlzma_codec_free=retroarch_internal_lzma_codec_free
DEFINES += -Dlzma_codec_decompress=retroarch_internal_lzma_codec_decompress
DEFINES += -Dcdlz_codec_init=retroarch_internal_cdlz_codec_init
DEFINES += -Dcdlz_codec_free=retroarch_internal_cdlz_codec_free
DEFINES += -Dcdlz_codec_decompress=retroarch_internal_cdlz_codec_decompress
endif
OBJ += $(LIBRETRO_COMM_DIR)/formats/libchdr/libchdr_bitstream.o \
$(LIBRETRO_COMM_DIR)/formats/libchdr/libchdr_cdrom.o \
$(LIBRETRO_COMM_DIR)/formats/libchdr/libchdr_chd.o \
@ -2063,13 +2180,31 @@ ifeq ($(HAVE_NETWORKING), 1)
tasks/task_http.o \
tasks/task_netplay_lan_scan.o \
tasks/task_netplay_nat_traversal.o \
tasks/task_pl_thumbnail_download.o \
tasks/task_netplay_find_content.o
ifeq ($(HAVE_MENU), 1)
OBJ += tasks/task_pl_thumbnail_download.o
endif
ifeq ($(HAVE_MENU_COMMON), 1)
OBJ += tasks/task_core_updater.o
endif
ifneq ($(findstring Linux,$(OS)),)
HAVE_CLOUDSYNC = 1
endif
ifneq ($(findstring Win,$(OS)),)
HAVE_CLOUDSYNC = 1
endif
ifeq ($(HAVE_CLOUDSYNC), 1)
DEFINES += -DHAVE_CLOUDSYNC
OBJ += tasks/task_cloudsync.o \
network/cloud_sync/webdav.o \
network/cloud_sync_driver.o
endif
ifeq ($(HAVE_BUILTINBEARSSL), 1)
OBJ += $(LIBRETRO_COMM_DIR)/net/net_socket_ssl_bear.o
else ifeq ($(HAVE_SSL), 1)
@ -2098,15 +2233,27 @@ ifeq ($(HAVE_NETWORKING), 1)
# RetroAchievements
ifeq ($(HAVE_CHEEVOS), 1)
DEFINES += -DHAVE_CHEEVOS
DEFINES += -DHAVE_CHEEVOS -DRC_CLIENT_SUPPORTS_HASH
INCLUDE_DIRS += -Ideps/rcheevos/include
ifneq ($(HAVE_THREADS), 1)
DEFINES += -DRC_NO_THREADS
else ifneq (,$(filter GEKKO,$(CFLAGS)))
# Gekko (Wii) and 3DS use custom pthread wrappers (see rthreads.c)
DEFINES += -DRC_NO_THREADS
else ifneq (,$(filter _3DS,$(CFLAGS)))
DEFINES += -DRC_NO_THREADS
endif
OBJ += cheevos/cheevos.o \
cheevos/cheevos_client.o \
cheevos/cheevos_menu.o \
$(LIBRETRO_COMM_DIR)/formats/cdfs/cdfs.o \
deps/rcheevos/src/rc_client.o \
deps/rcheevos/src/rc_compat.o \
deps/rcheevos/src/rc_libretro.o \
deps/rcheevos/src/rc_util.o \
deps/rcheevos/src/rcheevos/alloc.o \
deps/rcheevos/src/rcheevos/compat.o \
deps/rcheevos/src/rcheevos/condition.o \
deps/rcheevos/src/rcheevos/condset.o \
deps/rcheevos/src/rcheevos/consoleinfo.o \
@ -2114,15 +2261,16 @@ ifeq ($(HAVE_NETWORKING), 1)
deps/rcheevos/src/rcheevos/lboard.o \
deps/rcheevos/src/rcheevos/memref.o \
deps/rcheevos/src/rcheevos/operand.o \
deps/rcheevos/src/rcheevos/rc_libretro.o \
deps/rcheevos/src/rcheevos/richpresence.o \
deps/rcheevos/src/rcheevos/runtime.o \
deps/rcheevos/src/rcheevos/runtime_progress.o \
deps/rcheevos/src/rcheevos/trigger.o \
deps/rcheevos/src/rcheevos/value.o \
deps/rcheevos/src/rhash/aes.o \
deps/rcheevos/src/rhash/cdreader.o \
deps/rcheevos/src/rhash/hash.o \
deps/rcheevos/src/rapi/rc_api_common.o \
deps/rcheevos/src/rapi/rc_api_info.o \
deps/rcheevos/src/rapi/rc_api_runtime.o \
deps/rcheevos/src/rapi/rc_api_user.o \
@ -2368,13 +2516,16 @@ ifeq ($(WANT_LIBFAT), 1)
endif
ifeq ($(HAVE_STATIC_AUDIO_FILTERS), 1)
OBJ += libretro-common/audio/dsp_filters/echo.o \
OBJ += libretro-common/audio/dsp_filters/chorus.o \
libretro-common/audio/dsp_filters/crystalizer.o \
libretro-common/audio/dsp_filters/echo.o \
libretro-common/audio/dsp_filters/eq.o \
libretro-common/audio/dsp_filters/chorus.o \
libretro-common/audio/dsp_filters/iir.o \
libretro-common/audio/dsp_filters/panning.o \
libretro-common/audio/dsp_filters/phaser.o \
libretro-common/audio/dsp_filters/reverb.o \
libretro-common/audio/dsp_filters/tremolo.o \
libretro-common/audio/dsp_filters/vibrato.o \
libretro-common/audio/dsp_filters/wahwah.o
endif
@ -2402,6 +2553,13 @@ ifeq ($(HAVE_WEBOS), 1)
DEFINES += -DWEBOS
endif
ifeq ($(HAVE_TEST_DRIVERS), 1)
DEFINES += -DHAVE_TEST_DRIVERS
OBJ += input/drivers_joypad/test_joypad.o
OBJ += input/drivers/test_input.o
endif
#####################################
### Android Play Feature Delivery ###
### (Play Store build core ###

View File

@ -47,6 +47,7 @@ HAVE_DSP_FILTER = 1
HAVE_VIDEO_FILTER = 1
HAVE_STATIC_VIDEO_FILTERS = 1
HAVE_STATIC_AUDIO_FILTERS = 1
HAVE_STATIC_CORES = 1
HAVE_FILTERS_BUILTIN = 1
HAVE_MENU = 1
HAVE_CONFIGFILE = 1
@ -62,10 +63,11 @@ HAVE_COMMAND := 1
HAVE_STDIN_CMD := 1
HAVE_CMD := 1
HAVE_CHEEVOS = 0
HAVE_CHD = 0 # disabled due to static libretro-common and libchdr conflicts between different cores
HAVE_CHD = 1
HAVE_STB_VORBIS = 1
HAVE_IBXM = 1
HAVE_CORE_INFO_CACHE = 1
HAVE_XDELTA = 0 # disabled because <lzma.h> isn't available (or we haven't figured out how to install it)
HAVE_RGUI = 1
HAVE_MATERIALUI = 0

View File

@ -2,6 +2,7 @@ HAVE_STATIC_DUMMY ?= 0
ifeq ($(TARGET),)
ifeq ($(LIBRETRO),)
TARGET := retroarch.js
LIBRETRO = dummy
else
TARGET := $(LIBRETRO)_libretro.js
endif
@ -48,7 +49,6 @@ HAVE_7ZIP = 1
HAVE_BSV_MOVIE = 1
HAVE_AL = 1
# WARNING -- READ BEFORE ENABLING
# The rwebaudio driver is known to have several audio bugs, such as
# minor crackling, or the entire page freezing/crashing.
@ -78,8 +78,11 @@ OBJDIR := obj-emscripten
#if you compile with SDL2 flag add this Emscripten flag "-s USE_SDL=2" to LDFLAGS:
LIBS := -s USE_ZLIB=1
LDFLAGS := -L. --no-heap-copy -s $(LIBS) -s TOTAL_MEMORY=$(MEMORY) -s NO_EXIT_RUNTIME=0 -s FULL_ES2=1 -s "EXTRA_EXPORTED_RUNTIME_METHODS=['callMain']" \
-s ALLOW_MEMORY_GROWTH=1 -s EXPORTED_FUNCTIONS="['_main', '_malloc', '_cmd_savefiles', '_cmd_save_state', '_cmd_load_state', '_cmd_take_screenshot']" \
LDFLAGS := -L. --no-heap-copy -s $(LIBS) -s TOTAL_MEMORY=$(MEMORY) -s NO_EXIT_RUNTIME=0 -s FULL_ES2=1 \
-s "EXPORTED_RUNTIME_METHODS=['callMain', 'FS', 'PATH', 'ERRNO_CODES']" \
-s ALLOW_MEMORY_GROWTH=1 -s "EXPORTED_FUNCTIONS=['_main', '_malloc', '_cmd_savefiles', '_cmd_save_state', '_cmd_load_state', '_cmd_take_screenshot']" \
-s MODULARIZE=1 -s EXPORT_ES6=1 -s EXPORT_NAME="libretro_$(subst -,_,$(LIBRETRO))" \
-s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=1 \
--js-library emscripten/library_errno_codes.js \
--js-library emscripten/library_rwebcam.js
@ -90,6 +93,7 @@ endif
ifeq ($(HAVE_AL), 1)
LDFLAGS += -lopenal
DEFINES += -DHAVE_AL
ASYNC = 1
endif
ifneq ($(PTHREAD), 0)
@ -101,7 +105,10 @@ else
endif
ifeq ($(ASYNC), 1)
LDFLAGS += -s ASYNCIFY=$(ASYNC)
LDFLAGS += -s ASYNCIFY=$(ASYNC) -s ASYNCIFY_STACK_SIZE=8192
ifeq ($(DEBUG), 1)
LDFLAGS += -s ASYNCIFY_DEBUG=1 # -s ASYNCIFY_ADVISE
endif
endif
ifeq ($(HAVE_SDL2), 1)
@ -126,8 +133,8 @@ ifneq ($(V), 1)
endif
ifeq ($(DEBUG), 1)
LDFLAGS += -O0 -g
CFLAGS += -O0 -g
LDFLAGS += -O0 -g -gsource-map -s SAFE_HEAP=1 -s STACK_OVERFLOW_CHECK=2 -s ASSERTIONS=1
CFLAGS += -O0 -g -gsource-map -s SAFE_HEAP=1 -s SAFE_HEAP_LOG=1 -s STACK_OVERFLOW_CHECK=2 -s ASSERTIONS=1
else
LDFLAGS += -O3 -s WASM=1
# WARNING: some optimizations can break some cores (ex: LTO breaks tyrquake)
@ -138,7 +145,12 @@ else
CFLAGS += -O3
endif
CFLAGS += -Wall -I. -Ilibretro-common/include -std=gnu99 $(LIBS) #\
# 128 * 1024, double the usual emscripten stack size
LDFLAGS += -s STACK_SIZE=131072
LDFLAGS += --extern-pre-js emscripten/pre.js
CFLAGS += -Wall -I. -Ilibretro-common/include -std=gnu99 #\
# -s EXPORTED_FUNCTIONS="['_main', '_malloc', '_cmd_savefiles', '_cmd_save_state', '_cmd_take_screenshot']"
RARCH_OBJ := $(addprefix $(OBJDIR)/,$(OBJ))

View File

@ -213,21 +213,21 @@ install: $(TARGET)
cp $(TARGET) $(DESTDIR)$(BIN_DIR)
cp tools/cg2glsl.py $(DESTDIR)$(BIN_DIR)/retroarch-cg2glsl
cp retroarch.cfg $(DESTDIR)$(GLOBAL_CONFIG_DIR)
cp com.libretro.RetroArch.appdata.xml $(DESTDIR)$(DATA_DIR)/metainfo
cp retroarch.desktop $(DESTDIR)$(DATA_DIR)/applications
cp com.libretro.RetroArch.metainfo.xml $(DESTDIR)$(DATA_DIR)/metainfo
cp com.libretro.RetroArch.desktop $(DESTDIR)$(DATA_DIR)/applications
cp docs/retroarch.6 $(DESTDIR)$(MAN_DIR)/man6
cp docs/retroarch-cg2glsl.6 $(DESTDIR)$(MAN_DIR)/man6
cp media/retroarch.svg $(DESTDIR)$(DATA_DIR)/pixmaps
cp media/com.libretro.RetroArch.svg $(DESTDIR)$(DATA_DIR)/pixmaps
cp COPYING $(DESTDIR)$(DOC_DIR)
cp README.md $(DESTDIR)$(DOC_DIR)
chmod 755 $(DESTDIR)$(BIN_DIR)/$(TARGET)
chmod 755 $(DESTDIR)$(BIN_DIR)/retroarch-cg2glsl
chmod 644 $(DESTDIR)$(GLOBAL_CONFIG_DIR)/retroarch.cfg
chmod 644 $(DESTDIR)$(DATA_DIR)/applications/retroarch.desktop
chmod 644 $(DESTDIR)$(DATA_DIR)/metainfo/com.libretro.RetroArch.appdata.xml
chmod 644 $(DESTDIR)$(DATA_DIR)/applications/com.libretro.RetroArch.desktop
chmod 644 $(DESTDIR)$(DATA_DIR)/metainfo/com.libretro.RetroArch.metainfo.xml
chmod 644 $(DESTDIR)$(MAN_DIR)/man6/retroarch.6
chmod 644 $(DESTDIR)$(MAN_DIR)/man6/retroarch-cg2glsl.6
chmod 644 $(DESTDIR)$(DATA_DIR)/pixmaps/retroarch.svg
chmod 644 $(DESTDIR)$(DATA_DIR)/pixmaps/com.libretro.RetroArch.svg
@if test -d media/assets && test $(HAVE_ASSETS); then \
echo "Installing media assets..."; \
mkdir -p $(DESTDIR)$(ASSETS_DIR)/assets; \

View File

@ -41,6 +41,7 @@ HAVE_DSP_FILTER = 1
HAVE_VIDEO_FILTER = 1
HAVE_STATIC_VIDEO_FILTERS = 1
HAVE_STATIC_AUDIO_FILTERS = 1
HAVE_STATIC_CORES = 1
HAVE_FILTERS_BUILTIN = 1
HAVE_MENU = 1
HAVE_CONFIGFILE = 1
@ -52,7 +53,7 @@ HAVE_IFINFO = 1
HAVE_NETPLAYDISCOVERY = 1
HAVE_STB_FONT = 1
HAVE_CHEEVOS = 1
HAVE_CHD = 0 # disabled due to static libretro-common and libchdr conflicts between different cores
HAVE_CHD = 1
HAVE_STB_VORBIS = 1
HAVE_IBXM = 1
HAVE_CORE_INFO_CACHE = 1

View File

@ -105,6 +105,7 @@ HAVE_OZONE = 0
HAVE_ZLIB = 1
HAVE_CONFIGFILE = 1
HAVE_PATCH = 1
HAVE_XDELTA = 0 # Disabled until we figure out how to include <lzma.h>
HAVE_CHEATS = 1
HAVE_CHEEVOS = 0
HAVE_LIBSHAKE = 0

View File

@ -25,11 +25,11 @@ HAVE_D3D12 := 1
HAVE_CG := 1
HAVE_OPENGL := 1
HAVE_OPENGL1 := 1
HAVE_GFX_WIDGETS := 1
HAVE_GFX_WIDGETS := 1
HAVE_VULKAN := 1
HAVE_XAUDIO := 1
HAVE_XINPUT := 1
HAVE_WASAPI := 0
HAVE_WASAPI := 1
HAVE_THREAD_STORAGE := 1
HAVE_WINMM := 1

View File

@ -129,6 +129,7 @@ HAVE_ZLIB := 1
HAVE_7ZIP := 1
HAVE_CONFIGFILE := 1
HAVE_PATCH := 1
HAVE_XDELTA := 0 # disabled because <lzma.h> isn't available (or we haven't figured out how to install it)
HAVE_CHEATS := 1
HAVE_SCREENSHOTS := 1
HAVE_REWIND := 1

View File

@ -54,6 +54,7 @@ else
HAVE_MENU = 1
HAVE_CONFIGFILE = 1
HAVE_PATCH = 1
HAVE_PATCH = 0 # disabled because <lzma.h> isn't available (or we haven't figured out how to install it)
HAVE_CHEATS = 1
HAVE_RGUI = 1
HAVE_MATERIALUI = 0
@ -116,7 +117,11 @@ run:
ps2client -h $(PS2_IP) execee host:$(EE_BIN)
sim:
PCSX2 --elf=$(PWD)/$(EE_BIN) --nogui
ifeq ($(shell uname), Darwin)
/Applications/PCSX2.app/Contents/MacOS/PCSX2 -elf $(PWD)/$(EE_BIN)
else
PCSX2 -elf $(PWD)/$(EE_BIN) -nogui
endif
debug: clean all run

View File

@ -6,7 +6,7 @@ HAVE_THREADS ?= 1
BIG_STACK ?= 0
LOAD_WITHOUT_CORE_INFO ?= 0
HAVE_STATIC_DUMMY ?= 0
HAVE_XDELTA ?= 1
TARGET = retroarchpsp
ifeq ($(DEBUG), 1)

View File

@ -107,6 +107,7 @@ HAVE_OZONE = 0
HAVE_ZLIB = 1
HAVE_CONFIGFILE = 1
HAVE_PATCH = 1
HAVE_XDELTA = 0 # disabled because <lzma.h> isn't available (or we haven't figured out how to install it)
HAVE_CHEATS = 1
HAVE_CHEEVOS = 0
HAVE_LIBSHAKE = 0

View File

@ -107,6 +107,7 @@ HAVE_OZONE = 0
HAVE_ZLIB = 1
HAVE_CONFIGFILE = 1
HAVE_PATCH = 1
HAVE_XDELTA = 0 # Disabled until we figure out how to include <lzma.h>
HAVE_CHEATS = 1
HAVE_CHEEVOS = 0
HAVE_LIBSHAKE = 0

View File

@ -84,6 +84,7 @@ else
HAVE_GFX_WIDGETS := 1
HAVE_CONFIGFILE := 1
HAVE_PATCH := 1
HAVE_XDELTA := 1 # disabled because <lzma.h> isn't available (or we haven't figured out how to install it)
HAVE_CHEATS := 1
HAVE_OVERLAY := 1
HAVE_MATERIALUI := 1

View File

@ -1,11 +1,23 @@
include version.all
$(call assert,$(call seq,$(TARGET_PREFIX),arm-webos-linux-gnueabi-),webOS SDK isn't setup properly. See https://github.com/webosbrew/meta-lg-webos-ndk#compile-program-by-command-line)
ifneq ($(CROSS_COMPILE),arm-webos-linux-gnueabi-)
$(error You need webOS toolchain to build this. See https://github.com/webosbrew/native-toolchain)
endif
WEBOS_FREETYPE_CONFIG ?= $(SDKTARGETSYSROOT)/usr/bin/freetype-config
ifdef SDKTARGETSYSROOT
$(warning OE-based toolchain isn't supported anymore. Please use https://github.com/webosbrew/native-toolchain)
STAGING_DIR = $(SDKTARGETSYSROOT)
else ifndef STAGING_DIR
$(error Can't find buildroot based toolchain. Please use https://github.com/webosbrew/native-toolchain)
endif
WEBOS_INC_DIR ?= $(SDKTARGETSYSROOT)/usr/include
WEBOS_LIB_DIR ?= $(SDKTARGETSYSROOT)/usr/lib
WEBOS_FREETYPE_CONFIG ?= $(STAGING_DIR)/usr/bin/freetype-config
WEBOS_INC_DIR ?= $(STAGING_DIR)/usr/include
WEBOS_LIB_DIR ?= $(STAGING_DIR)/usr/lib
ADD_SDL2_LIB ?= 0
SDL2_PREBUILT_ARCHIVE ?= https://github.com/webosbrew/SDL-webOS/releases/download/release-2.30.0-webos.2/SDL2-2.30.0-webos.tar.gz
#########################
#########################
@ -15,6 +27,7 @@ PACKAGE_VERSION := $(patsubst "%",%,$(RARCH_VERSION))
DEBUG ?= 0
HAVE_CLOUDSYNC = 1
HAVE_SCREENSHOTS = 1
HAVE_REWIND = 1
HAVE_7ZIP = 1
@ -120,7 +133,7 @@ OS = Linux
TARGET = retroarch
OBJ :=
LINK := $(CXX)
LINK := $(CC)
DEF_FLAGS += -ffunction-sections -fdata-sections
DEF_FLAGS += -I. -Ideps -Ideps/stb -DWEBOS=1 -MMD
DEF_FLAGS += -Wall -Wno-unused-variable
@ -128,7 +141,7 @@ LIBS := -ldl -lz -lrt -pthread
CFLAGS :=
CXXFLAGS := -fno-exceptions -fno-rtti -std=c++11 -D__STDC_CONSTANT_MACROS
ASFLAGS :=
LDFLAGS := -Wl,--gc-sections
LDFLAGS := -Wl,-rpath=\$$ORIGIN/lib,--gc-sections
INCLUDE_DIRS = -I$(WEBOS_INC_DIR)
LIBRARY_DIRS = -L$(WEBOS_LIB_DIR)
DEFINES := -DRARCH_INTERNAL -D_FILE_OFFSET_BITS=64 -UHAVE_STATIC_DUMMY
@ -140,10 +153,12 @@ DEFINES += -DHAVE_PULSE
DEFINES += -DHAVE_NETWORKING -DHAVE_IFINFO -DHAVE_ONLINE_UPDATER -DHAVE_UPDATE_ASSETS -DHAVE_UPDATE_CORES
DEFINES += -DHAVE_UPDATE_CORE_INFO
SDL2_CFLAGS := $(shell pkg-config --cflags sdl2)
SDL2_LIBS := $(shell pkg-config --libs sdl2)
PKG_CONFIG=pkg-config
SDL2_CFLAGS := $(shell $(PKG_CONFIG) --cflags sdl2)
SDL2_LIBS := $(shell $(PKG_CONFIG) --libs sdl2)
OPENGLES_LIBS = -lGLESv2
PULSE_LIBS = $(shell pkg-config --libs libpulse)
PULSE_LIBS = $(shell $(PKG_CONFIG) --libs libpulse)
MMAP_LIBS = -lc
NEON_CFLAGS = -mfpu=neon
NEON_ASFLAGS = -mfpu=neon
@ -221,15 +236,26 @@ clean:
rm -rf $(OBJDIR_BASE)
rm -f $(TARGET)
rm -f *.d
rm -rf SDL
rm -rf webos/*.ipk
rm -rf webos/dist
ipk: $(TARGET)
sdl2: $(TARGET)
ifeq ($(ADD_SDL2_LIB), 1)
@echo "Downloading SDL2 prebuilt"
mkdir -p SDL
wget -qO - $(SDL2_PREBUILT_ARCHIVE) | tar -C SDL -zxvf -
endif
ipk: $(TARGET) sdl2
rm -rf webos/dist
mkdir -p webos/dist/lib
echo "$$APPINFO" > webos/dist/appinfo.json
cp -t webos/dist -vf $(TARGET) webos/icon160.png
cp -t webos/dist/lib -vf $(WEBOS_LIB_DIR)/libstdc++.so.6
ifeq ($(ADD_SDL2_LIB), 1)
cp -t webos/dist/lib -vf SDL/lib/libSDL2-2.0.so.0
endif
$(STRIP) webos/dist/$(TARGET)
cd webos && ares-package dist

View File

@ -1,6 +1,7 @@
ROOT_DIR := .
DEPS_DIR := $(ROOT_DIR)/deps
DEBUG ?= 0
LOAD_WITHOUT_CORE_INFO ?= 0
HAVE_LOGGER = 0
HAVE_FILE_LOGGER = 0
HAVE_CC_RESAMPLER = 1
@ -137,6 +138,7 @@ HAVE_ZLIB := 1
HAVE_7ZIP := 1
HAVE_CONFIGFILE := 1
HAVE_PATCH := 1
HAVE_XDELTA := 0 # disabled because <lzma.h> isn't available (or we haven't figured out how to install it)
HAVE_CHEATS := 1
HAVE_SCREENSHOTS := 1
HAVE_REWIND := 1
@ -160,8 +162,9 @@ HAVE_XMB := 0
HAVE_OZONE := 0
HAVE_RGUI := 1
HAVE_MATERIALUI := 0
HAVE_CHEEVOS := 1
CFLAGS += -DHAVE_SOCKET_LEGACY
CFLAGS += -DHAVE_SOCKET_LEGACY -DHAVE_CHEEVOS
APP_BOOTER_DIR = wii/app_booter
PLATOBJS := $(APP_BOOTER_DIR)/app_booter.binobj
@ -172,6 +175,7 @@ endif
INCLUDE += -I./libretro-common/include \
-Ideps \
-Ideps/rcheevos/include \
-Ideps/stb
CFLAGS += -Wall -std=gnu99 $(MACHDEP) $(PLATCFLAGS) $(INCLUDE)
@ -257,6 +261,10 @@ else
CFLAGS += -O3
endif
ifeq ($(LOAD_WITHOUT_CORE_INFO),1)
CFLAGS += -DLOAD_WITHOUT_CORE_INFO
endif
OBJOUT = -o
LINKOUT = -o
LINK = $(CXX)

View File

@ -143,6 +143,7 @@ endif
HAVE_RBMP = 1
HAVE_CONFIGFILE = 1
HAVE_PATCH = 1
HAVE_XDELTA = 0 # disabled because <lzma.h> isn't available (or we haven't figured out how to install it)
HAVE_REWIND = 1
HAVE_CHEATS = 1
HAVE_MENU = 1

View File

@ -170,7 +170,7 @@ $(OBJDIR)/%.o: %.cpp | $(dir $@)
$(OBJDIR)/%.o: %.rc $(HEADERS)
@-mkdir -p $(dir $@) || mkdir $(subst /,\,$(dir $@)) || echo .
@$(if $(Q), $(shell echo echo WINDRES $<),)
$(Q)$(WINDRES) -o $@ $<
$(Q)$(WINDRES) $(DEFINES) -o $@ $<
clean:
rm -rf $(OBJDIR)

View File

@ -6,7 +6,7 @@ good fbdev implementation. It is derived from the old Android GLES driver.
It was meant to be used on Cubieboard/Cubieboard2/Cubietruck, but it should not
be used on an Odroid X2/U2/U3 where a superior solution (RetroArch exynos video driver) is available.
Fbdev implementation on Odroid harware is missing WAITFORVSYNC ioctl, so use Exynos driver there.
Fbdev implementation on Odroid hardware is missing WAITFORVSYNC ioctl, so use Exynos driver there.
This driver requires MALI r4p0 binary blobs for fbdev, and a kernel compatible with r4p0 binaries.

View File

@ -74,41 +74,43 @@ RetroArch has been ported to the following platforms:
- FreeBSD
- Haiku
- Linux
- Original Microsoft Xbox
- Microsoft Xbox 360 (Libxenon/XeXDK)
- Microsoft Xbox One
- Microsoft Xbox Series S/X
- Miyoo
- NetBSD
- Nintendo 3DS/2DS
- Nintendo GameCube
- Nintendo NES/SNES Classic Edition
- Nintendo Switch
- Nintendo GameCube
- Nintendo Wii
- Nintendo Switch
- Nintendo Wii U
- Nintendo 3DS/2DS
- OpenBSD
- OpenDingux
- Original Microsoft Xbox
- PlayStation2
- PlayStation3
- PlayStation4
- PlayStation Portable
- PlayStation Vita
- Raspberry Pi
- ReactOS
- Redox OS
- RetroFW
- RS90
- SerenityOS
- Solaris
- Windows 10
- Windows 11
- Windows 2000
- Windows 7
- Windows 8
- Windows NT 3.5
- Windows 95
- Windows 98
- Windows Millennium
- Windows NT 3.5
- Windows Vista
- Windows 2000
- Windows XP
- Windows Millennium
- Windows Vista
- Windows 7
- Windows 8
- Windows 10
- Windows 11
## Dependencies (PC)
@ -122,7 +124,7 @@ following dependencies come as recommended:
- GL headers / Vulkan headers
- X11 headers and libs, or EGL/KMS/GBM
OSX port of RetroArch requires latest versions of XCode to build.
OSX port of RetroArch requires latest versions of Xcode to build.
RetroArch can utilize these libraries if enabled:
@ -335,7 +337,7 @@ The links below belong to our official channels. Links other than this may have
- [YouTube Topic](https://www.youtube.com/channel/UC5q007PYyQPgin0HHbzF0zQ)
- [Patreon](https://www.patreon.com/libretro)
- [BOUNTYSOURCE](https://www.bountysource.com/teams/libretro/issues)
- [Discord](https://discord.gg/27Xxm2h)
- [Discord](https://discord.com/invite/VZ2b7wghxR)
- [Teespring](https://teespring.com/stores/retroarch)
- [Documentation](https://docs.libretro.com/)
- [Forum](https://forums.libretro.com/)

View File

@ -23,6 +23,7 @@
#include <string/stdstring.h>
#include <encodings/utf.h>
#include <retro_miscellaneous.h>
#include <clamping.h>
#include <memalign.h>
#include <audio/conversion/float_to_s16.h>
@ -76,7 +77,7 @@ audio_driver_t audio_null = {
NULL,
NULL,
NULL, /* write_avail */
NULL /* buffer_size */
NULL /* buffer_size */
};
audio_driver_t *audio_drivers[] = {
@ -224,7 +225,7 @@ static bool audio_driver_free_devices_list(void)
{
audio_driver_state_t *audio_st = &audio_driver_st;
if (
!audio_st->current_audio
!audio_st->current_audio
|| !audio_st->current_audio->device_list_free
|| !audio_st->context_audio_data)
return false;
@ -274,7 +275,7 @@ static void audio_driver_deinit_resampler(void)
static bool audio_driver_deinit_internal(bool audio_enable)
{
audio_driver_state_t *audio_st = &audio_driver_st;
if ( audio_st->current_audio
if ( audio_st->current_audio
&& audio_st->current_audio->free)
{
if (audio_st->context_audio_data)
@ -412,7 +413,7 @@ static void audio_driver_flush(
struct resampler_data src_data;
float audio_volume_gain = (audio_st->mute_enable ||
(audio_fastforward_mute && is_fastforward))
? 0.0f
? 0.0f
: audio_st->volume_gain;
src_data.data_out = NULL;
@ -458,25 +459,26 @@ static void audio_driver_flush(
src_data.data_out = audio_st->output_samples_buf;
/* Now the resampler will write to the driver state's scratch buffer */
if (audio_st->flags & AUDIO_FLAG_CONTROL)
/* Count samples. */
{
/* Readjust the audio input rate. */
int half_size = (int)(audio_st->buffer_size / 2);
int avail =
(int)audio_st->current_audio->write_avail(
audio_st->context_audio_data);
int delta_mid = avail - half_size;
double direction = (double)delta_mid / half_size;
double adjust = 1.0 +
audio_st->rate_control_delta * direction;
unsigned write_idx =
audio_st->free_samples_count++ &
(AUDIO_BUFFER_FREE_SAMPLES_COUNT - 1);
unsigned write_idx =
audio_st->free_samples_count++ & (AUDIO_BUFFER_FREE_SAMPLES_COUNT - 1);
audio_st->free_samples_buf[write_idx] = avail;
audio_st->source_ratio_current =
audio_st->source_ratio_original * adjust;
if (audio_st->flags & AUDIO_FLAG_CONTROL)
{
/* Readjust the audio input rate. */
int avail = (int)audio_st->current_audio->write_avail(
audio_st->context_audio_data);
int half_size = (int)(audio_st->buffer_size / 2);
int delta_mid = avail - half_size;
double direction = (double)delta_mid / half_size;
double adjust = 1.0 + audio_st->rate_control_delta * direction;
audio_st->free_samples_buf[write_idx]
= avail;
audio_st->source_ratio_current
= audio_st->source_ratio_original * adjust;
}
#if 0
if (verbosity_is_enabled())
@ -526,7 +528,7 @@ static void audio_driver_flush(
audio_st->last_flush_time = flush_time;
}
audio_st->resampler->process(
audio_st->resampler_data, &src_data);
@ -542,7 +544,7 @@ static void audio_driver_flush(
if (audio_st->mixer_volume_gain == 1.0f)
override = false;
mixer_gain = audio_st->mixer_volume_gain;
}
audio_mixer_mix(audio_st->output_samples_buf,
src_data.output_frames, mixer_gain, override);
@ -609,7 +611,7 @@ bool audio_driver_init_internal(
#ifdef HAVE_REWIND
int16_t *rewind_buf = NULL;
#endif
/* Accomodate rewind since at some point we might have two full buffers. */
/* Accommodate rewind since at some point we might have two full buffers. */
size_t outsamples_max = AUDIO_CHUNK_SIZE_NONBLOCKING * 2 * AUDIO_MAX_RATIO * slowmotion_ratio;
int16_t *out_conv_buf = (int16_t*)memalign_alloc(64, outsamples_max * sizeof(int16_t));
size_t audio_buf_length = AUDIO_CHUNK_SIZE_NONBLOCKING * 2 * sizeof(float);
@ -710,7 +712,7 @@ bool audio_driver_init_internal(
audio_driver_st.context_audio_data))
audio_driver_st.flags |= AUDIO_FLAG_USE_FLOAT;
if ( !audio_sync
if ( !audio_sync
&& (audio_driver_st.flags & AUDIO_FLAG_ACTIVE))
{
if ( (audio_driver_st.flags & AUDIO_FLAG_ACTIVE)
@ -812,6 +814,8 @@ void audio_driver_sample(int16_t left, int16_t right)
uint32_t runloop_flags;
audio_driver_state_t *audio_st = &audio_driver_st;
recording_state_t *recording_st = NULL;
if (!audio_st || !audio_st->output_samples_conv_buf)
return;
if (audio_st->flags & AUDIO_FLAG_SUSPENDED)
return;
audio_st->output_samples_conv_buf[audio_st->data_ptr++] = left;
@ -835,7 +839,7 @@ void audio_driver_sample(int16_t left, int16_t right)
recording_st->driver->push_audio(recording_st->data, &ffemu_data);
}
if (!( (runloop_flags & RUNLOOP_FLAG_PAUSED)
if (!( (runloop_flags & RUNLOOP_FLAG_PAUSED)
|| !(audio_st->flags & AUDIO_FLAG_ACTIVE)
|| !(audio_st->output_samples_buf)))
audio_driver_flush(audio_st,
@ -843,8 +847,8 @@ void audio_driver_sample(int16_t left, int16_t right)
config_get_ptr()->bools.audio_fastforward_mute,
audio_st->output_samples_conv_buf,
audio_st->data_ptr,
runloop_flags & RUNLOOP_FLAG_SLOWMOTION,
runloop_flags & RUNLOOP_FLAG_FASTMOTION);
(runloop_flags & RUNLOOP_FLAG_SLOWMOTION) ? true : false,
(runloop_flags & RUNLOOP_FLAG_FASTMOTION) ? true : false);
audio_st->data_ptr = 0;
}
@ -893,8 +897,8 @@ size_t audio_driver_sample_batch(const int16_t *data, size_t frames)
config_get_ptr()->bools.audio_fastforward_mute,
data,
frames_to_write << 1,
runloop_flags & RUNLOOP_FLAG_SLOWMOTION,
runloop_flags & RUNLOOP_FLAG_FASTMOTION);
(runloop_flags & RUNLOOP_FLAG_SLOWMOTION) ? true : false,
(runloop_flags & RUNLOOP_FLAG_FASTMOTION) ? true : false);
frames_remaining -= frames_to_write;
data += frames_to_write << 1;
@ -948,9 +952,8 @@ bool audio_driver_dsp_filter_init(const char *device)
retro_dsp_filter_t *audio_driver_dsp = NULL;
struct string_list *plugs = NULL;
#if defined(HAVE_DYLIB) && !defined(HAVE_FILTERS_BUILTIN)
char ext_name[32];
char basedir[256];
ext_name[0] = '\0';
char ext_name[16];
char basedir[NAME_MAX_LENGTH];
fill_pathname_basedir(basedir, device, sizeof(basedir));
if (!frontend_driver_get_core_extension(ext_name, sizeof(ext_name)))
return false;
@ -1009,44 +1012,29 @@ bool audio_driver_get_devices_list(void **data)
#ifdef HAVE_AUDIOMIXER
bool audio_driver_mixer_extension_supported(const char *ext)
{
unsigned i;
struct string_list str_list;
union string_list_elem_attr attr;
bool ret = false;
attr.i = 0;
if (!string_list_initialize(&str_list))
return false;
#ifdef HAVE_STB_VORBIS
string_list_append(&str_list, "ogg", attr);
if (string_is_equal_noncase("ogg", ext))
return true;
#endif
#ifdef HAVE_IBXM
string_list_append(&str_list, "mod", attr);
string_list_append(&str_list, "s3m", attr);
string_list_append(&str_list, "xm", attr);
if (string_is_equal_noncase("mod", ext))
return true;
if (string_is_equal_noncase("s3m", ext))
return true;
if (string_is_equal_noncase("xm", ext))
return true;
#endif
#ifdef HAVE_DR_FLAC
string_list_append(&str_list, "flac", attr);
if (string_is_equal_noncase("flac", ext))
return true;
#endif
#ifdef HAVE_DR_MP3
string_list_append(&str_list, "mp3", attr);
if (string_is_equal_noncase("mp3", ext))
return true;
#endif
string_list_append(&str_list, "wav", attr);
for (i = 0; i < str_list.size; i++)
{
const char *str_ext = str_list.elems[i].data;
if (string_is_equal_noncase(str_ext, ext))
{
ret = true;
break;
}
}
string_list_deinitialize(&str_list);
return ret;
if (string_is_equal_noncase("wav", ext))
return true;
return false;
}
static int audio_mixer_find_index(
@ -1242,7 +1230,7 @@ bool audio_driver_mixer_add_stream(audio_mixer_stream_params_t *params)
* so have to do it here */
free(buf);
buf = NULL;
break;
break;
case AUDIO_MIXER_TYPE_OGG:
handle = audio_mixer_load_ogg(buf, (int32_t)params->bufsize);
break;
@ -1344,7 +1332,7 @@ static void audio_driver_load_menu_bgm_callback(retro_task_t *task,
void audio_driver_load_system_sounds(void)
{
char basename_noext[256];
char basename_noext[NAME_MAX_LENGTH];
char sounds_path[PATH_MAX_LENGTH];
char sounds_fallback_path[PATH_MAX_LENGTH];
settings_t *settings = config_get_ptr();
@ -1623,16 +1611,16 @@ bool audio_driver_callback(void)
{
settings_t *settings = config_get_ptr();
uint32_t runloop_flags = runloop_get_flags();
bool runloop_paused = runloop_flags & RUNLOOP_FLAG_PAUSED;
bool runloop_paused = (runloop_flags & RUNLOOP_FLAG_PAUSED) ? true : false;
#ifdef HAVE_MENU
#ifdef HAVE_NETWORKING
bool core_paused = runloop_paused ||
( settings->bools.menu_pause_libretro
bool core_paused = runloop_paused
|| (settings->bools.menu_pause_libretro
&& (menu_state_get_ptr()->flags & MENU_ST_FLAG_ALIVE)
&& netplay_driver_ctl(RARCH_NETPLAY_CTL_ALLOW_PAUSE, NULL));
#else
bool core_paused = runloop_paused ||
(settings->bools.menu_pause_libretro
bool core_paused = runloop_paused
|| (settings->bools.menu_pause_libretro
&& (menu_state_get_ptr()->flags & MENU_ST_FLAG_ALIVE));
#endif
#else
@ -1667,7 +1655,7 @@ bool audio_driver_start(bool is_shutdown)
{
audio_driver_state_t *audio_st = &audio_driver_st;
if (
!audio_st->current_audio
!audio_st->current_audio
|| !audio_st->current_audio->start
|| !audio_st->context_audio_data)
goto error;
@ -1688,6 +1676,14 @@ error:
return false;
}
const char *audio_driver_get_ident(void)
{
audio_driver_state_t *audio_st = &audio_driver_st;
if (!audio_st->current_audio)
return NULL;
return audio_st->current_audio->ident;
}
bool audio_driver_stop(void)
{
bool stopped;
@ -1744,8 +1740,8 @@ void audio_driver_frame_is_reverse(void)
audio_st->rewind_ptr,
audio_st->rewind_size -
audio_st->rewind_ptr,
runloop_flags & RUNLOOP_FLAG_SLOWMOTION,
runloop_flags & RUNLOOP_FLAG_FASTMOTION);
(runloop_flags & RUNLOOP_FLAG_SLOWMOTION) ? true : false,
(runloop_flags & RUNLOOP_FLAG_FASTMOTION) ? true : false);
}
}
#endif
@ -1820,9 +1816,12 @@ bool audio_compute_buffer_statistics(audio_statistics_t *stats)
if (samples < 3)
return false;
stats->samples = (unsigned)
stats->samples = (unsigned)
audio_st->free_samples_count;
if (!(audio_st->flags & AUDIO_FLAG_CONTROL))
return false;
#ifdef WARPUP
/* uint64 to double not implemented, fair chance
* signed int64 to double doesn't exist either */
@ -1909,8 +1908,8 @@ void audio_driver_menu_sample(void)
settings->bools.audio_fastforward_mute,
samples_buf,
1024,
runloop_flags & RUNLOOP_FLAG_SLOWMOTION,
runloop_flags & RUNLOOP_FLAG_FASTMOTION);
(runloop_flags & RUNLOOP_FLAG_SLOWMOTION) ? true : false,
(runloop_flags & RUNLOOP_FLAG_FASTMOTION) ? true : false);
sample_count -= 1024;
}
if ( recording_st->data &&
@ -1931,7 +1930,7 @@ void audio_driver_menu_sample(void)
settings->bools.audio_fastforward_mute,
samples_buf,
sample_count,
runloop_flags & RUNLOOP_FLAG_SLOWMOTION,
runloop_flags & RUNLOOP_FLAG_FASTMOTION);
(runloop_flags & RUNLOOP_FLAG_SLOWMOTION) ? true : false,
(runloop_flags & RUNLOOP_FLAG_FASTMOTION) ? true : false);
}
#endif

View File

@ -443,6 +443,8 @@ extern audio_driver_t audio_rwebaudio;
audio_driver_state_t *audio_state_get_ptr(void);
const char *audio_driver_get_ident(void);
extern audio_driver_t *audio_drivers[];
RETRO_END_DECLS

View File

@ -19,8 +19,9 @@
#include <alsa/asoundlib.h>
#include <asm-generic/errno.h>
#include "alsa.h"
#include "../audio_driver.h"
#include "../common/alsa.h"
#include "../../verbosity.h"
int alsa_init_pcm(snd_pcm_t **pcm,
@ -459,7 +460,7 @@ struct string_list *alsa_device_list_type_new(const char* type)
char *io = snd_device_name_get_hint(*n, "IOID");
char *desc = snd_device_name_get_hint(*n, "DESC");
/* description of device IOID - input / output identifcation
/* description of device IOID - input / output identification
* ("Input" or "Output"), NULL means both) */
if (!io || (string_is_equal(io, type)))

View File

@ -18,8 +18,9 @@
#define _RETROARCH_ALSA
#include <boolean.h>
#include "queues/fifo_queue.h"
#include "rthreads/rthreads.h"
#include <queues/fifo_queue.h>
#include <rthreads/rthreads.h>
/* Header file for common functions that are used by alsa and alsathread. */
/**

View File

@ -19,9 +19,9 @@
#include <alsa/asoundlib.h>
#include <boolean.h>
#include "queues/fifo_queue.h"
#include "rthreads/rthreads.h"
#include "./alsa.h"
#include <queues/fifo_queue.h>
#include <rthreads/rthreads.h>
#include "alsa.h"
typedef struct alsa_thread_info
{

View File

@ -21,7 +21,6 @@
#include "mmdevice_common.h"
#include "mmdevice_common_inline.h"
char* mmdevice_name(IMMDevice *device)
{
HRESULT hr;

View File

@ -15,17 +15,18 @@
*/
#include "wasapi.h"
#include <stdio.h>
#ifdef HAVE_MICROPHONE
#include "audio/microphone_driver.h"
#include "../microphone_driver.h"
#endif
#include "queues/fifo_queue.h"
#include "lists/string_list.h"
#include "configuration.h"
#include "verbosity.h"
#include "string/stdstring.h"
#include <string/stdstring.h>
#include <queues/fifo_queue.h>
#include <lists/string_list.h>
#include "mmdevice_common.h"
#include "../../configuration.h"
#include "../../verbosity.h"
const char *hresult_name(HRESULT hr)
{
switch (hr)
@ -93,15 +94,14 @@ const char *hresult_name(HRESULT hr)
return "<unknown>";
}
const char *wave_subtype_name(const GUID *guid)
static const char *wave_subtype_name(const GUID *guid)
{
if (IsEqualGUID(guid, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))
if (!memcmp(guid, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, sizeof(GUID)))
return "KSDATAFORMAT_SUBTYPE_IEEE_FLOAT";
return "<unknown sub-format>";
}
const char *wave_format_name(const WAVEFORMATEXTENSIBLE *format)
static const char *wave_format_name(const WAVEFORMATEXTENSIBLE *format)
{
switch (format->Format.wFormatTag)
{
@ -150,132 +150,6 @@ static const char* wasapi_data_flow_name(EDataFlow data_flow)
return "<unknown>";
}
static void wasapi_set_format(WAVEFORMATEXTENSIBLE *wf,
bool float_fmt, unsigned rate, unsigned channels);
/**
* @param[in] format The format to check.
* @return \c true if \c format is suitable for RetroArch.
*/
static bool wasapi_is_format_suitable(const WAVEFORMATEXTENSIBLE *format)
{
/* RetroArch only supports mono mic input and stereo speaker output */
if (!format || format->Format.nChannels == 0 || format->Format.nChannels > 2)
return false;
switch (format->Format.wFormatTag)
{
case WAVE_FORMAT_PCM:
if (format->Format.wBitsPerSample != 16)
/* Integer samples must be 16-bit */
return false;
break;
case WAVE_FORMAT_EXTENSIBLE:
if (!IsEqualGUID(&format->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))
/* RetroArch doesn't support any other subformat */
return false;
if (format->Format.wBitsPerSample != 32)
/* floating-point samples must be 32-bit */
return false;
break;
default:
/* Other formats are unsupported */
return false;
}
return true;
}
/**
* Selects a sample format suitable for the given device.
* @param[in,out] format The place where the chosen format will be written,
* as well as the first format checked.
* @param[in] client The audio client (i.e. device handle) for which a format will be selected.
* @param[in] mode The device mode (shared or exclusive) that \c client will use.
* @param[in] channels The number of channels that will constitute one audio frame.
* @return \c true if successful, \c false if a suitable format wasn't found or there was an error.
* If \c true, the selected format will be written to \c format.
* If \c false, the value referred by \c format will be unchanged.
*/
static bool wasapi_select_device_format(WAVEFORMATEXTENSIBLE *format, IAudioClient *client, AUDCLNT_SHAREMODE mode, unsigned channels)
{
static const unsigned preferred_rates[] = { 48000, 44100, 96000, 192000, 32000 };
const bool preferred_formats[] = {format->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE, format->Format.wFormatTag != WAVE_FORMAT_EXTENSIBLE};
/* Try the requested sample format first, then try the other one */
WAVEFORMATEXTENSIBLE *suggested_format = NULL;
bool result = false;
HRESULT hr = _IAudioClient_IsFormatSupported(
client, mode,
(const WAVEFORMATEX *)format,
(WAVEFORMATEX **)&suggested_format);
/* The Windows docs say that casting these arguments to WAVEFORMATEX* is okay. */
switch (hr)
{
case S_OK:
/* The requested format is okay without any changes */
RARCH_DBG("[WASAPI]: Desired format (%s, %u-channel, %uHz) can be used as-is.\n",
wave_format_name(format), format->Format.nChannels, format->Format.nSamplesPerSec);
result = true;
break;
case S_FALSE:
/* The requested format is unsupported, but Windows has suggested a similar one. */
RARCH_DBG("[WASAPI]: Windows suggests a format of (%s, %u-channel, %uHz).\n",
wave_format_name(suggested_format), suggested_format->Format.nChannels, suggested_format->Format.nSamplesPerSec);
if (wasapi_is_format_suitable(suggested_format))
{
*format = *suggested_format;
result = true;
}
else
{
result = false;
RARCH_ERR("[WASAPI]: Windows suggested a format, but RetroArch can't use it.\n");
}
break;
case AUDCLNT_E_UNSUPPORTED_FORMAT:
{ /* The requested format is unsupported
* and Windows was unable to suggest another.
* Usually happens with exclusive mode.
* RetroArch will try selecting a format. */
size_t i, j;
WAVEFORMATEXTENSIBLE possible_format;
HRESULT format_check_hr;
RARCH_WARN("[WASAPI]: Requested format not supported, and Windows could not suggest one. RetroArch will do so.\n");
for (i = 0; i < ARRAY_SIZE(preferred_formats); ++i)
{
for (j = 0; j < ARRAY_SIZE(preferred_rates); ++j)
{
wasapi_set_format(&possible_format, preferred_formats[i], preferred_rates[j], channels);
format_check_hr = _IAudioClient_IsFormatSupported(client, mode, (const WAVEFORMATEX *) &possible_format, NULL);
if (SUCCEEDED(format_check_hr))
{
*format = possible_format;
result = true;
RARCH_DBG("[WASAPI]: RetroArch suggests a format of (%s, %u-channel, %uHz).\n",
wave_format_name(format), format->Format.nChannels, format->Format.nSamplesPerSec);
goto done;
}
}
}
RARCH_ERR("[WASAPI]: Failed to select client format: No suitable format available\n");
result = false;
break;
}
default:
/* Something else went wrong. */
RARCH_ERR("[WASAPI]: Failed to select client format: %s\n", hresult_name(hr));
result = false;
break;
}
done:
/* IAudioClient::IsFormatSupported allocates a format object */
if (suggested_format)
CoTaskMemFree(suggested_format);
return result;
}
static void wasapi_set_format(WAVEFORMATEXTENSIBLE *wf,
bool float_fmt, unsigned rate, unsigned channels)
{
@ -307,6 +181,133 @@ static void wasapi_set_format(WAVEFORMATEXTENSIBLE *wf,
}
}
/**
* @param[in] format The format to check.
* @return \c true if \c format is suitable for RetroArch.
*/
static bool wasapi_is_format_suitable(const WAVEFORMATEXTENSIBLE *format)
{
/* RetroArch only supports mono mic input and stereo speaker output */
if (!format || format->Format.nChannels == 0 || format->Format.nChannels > 2)
return false;
switch (format->Format.wFormatTag)
{
case WAVE_FORMAT_PCM:
if (format->Format.wBitsPerSample != 16)
/* Integer samples must be 16-bit */
return false;
break;
case WAVE_FORMAT_EXTENSIBLE:
if (!(!memcmp(&format->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, sizeof(GUID))))
/* RetroArch doesn't support any other subformat */
return false;
if (format->Format.wBitsPerSample != 32)
/* floating-point samples must be 32-bit */
return false;
break;
default:
/* Other formats are unsupported */
return false;
}
return true;
}
/**
* Selects a sample format suitable for the given device.
* @param[in,out] format The place where the chosen format will be written,
* as well as the first format checked.
* @param[in] client The audio client (i.e. device handle) for which a format will be selected.
* @param[in] mode The device mode (shared or exclusive) that \c client will use.
* @param[in] channels The number of channels that will constitute one audio frame.
* @return \c true if successful, \c false if a suitable format wasn't found or there was an error.
* If \c true, the selected format will be written to \c format.
* If \c false, the value referred by \c format will be unchanged.
*/
static bool wasapi_select_device_format(WAVEFORMATEXTENSIBLE *format, IAudioClient *client, AUDCLNT_SHAREMODE mode, unsigned channels)
{
/* Try the requested sample format first, then try the other one. */
WAVEFORMATEXTENSIBLE *suggested_format = NULL;
bool result = false;
HRESULT hr = _IAudioClient_IsFormatSupported(
client, mode,
(const WAVEFORMATEX *)format,
(WAVEFORMATEX **)&suggested_format);
/* The Windows docs say that casting these arguments to WAVEFORMATEX* is okay. */
switch (hr)
{
case S_OK:
/* The requested format is okay without any changes. */
result = true;
break;
case S_FALSE:
/* The requested format is unsupported, but Windows has suggested a similar one. */
RARCH_DBG("[WASAPI]: Windows suggests a format of (%s, %u-channel, %uHz).\n",
wave_format_name(suggested_format),
suggested_format->Format.nChannels,
suggested_format->Format.nSamplesPerSec);
if (wasapi_is_format_suitable(suggested_format))
{
*format = *suggested_format;
result = true;
}
else
{
RARCH_ERR("[WASAPI]: Windows suggested a format, but RetroArch can't use it.\n");
}
break;
case AUDCLNT_E_UNSUPPORTED_FORMAT:
{
/* The requested format is unsupported
* and Windows was unable to suggest another.
* Usually happens with exclusive mode.
* RetroArch will try selecting a format. */
size_t i, j;
bool preferred_formats[2];
preferred_formats[0] = (format->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE);
preferred_formats[1] = (format->Format.wFormatTag != WAVE_FORMAT_EXTENSIBLE);
RARCH_WARN("[WASAPI]: Requested format not supported, and Windows could not suggest one. RetroArch will do so.\n");
for (i = 0; i < ARRAY_SIZE(preferred_formats); ++i)
{
static const unsigned preferred_rates[] = { 48000, 44100, 96000, 192000, 32000 };
for (j = 0; j < ARRAY_SIZE(preferred_rates); ++j)
{
HRESULT format_check_hr;
WAVEFORMATEXTENSIBLE possible_format;
wasapi_set_format(&possible_format, preferred_formats[i], preferred_rates[j], channels);
format_check_hr = _IAudioClient_IsFormatSupported(client, mode, (const WAVEFORMATEX *) &possible_format, NULL);
if (SUCCEEDED(format_check_hr))
{
*format = possible_format;
result = true;
RARCH_DBG("[WASAPI]: RetroArch suggests a format of (%s, %u-channel, %uHz).\n",
wave_format_name(format),
format->Format.nChannels,
format->Format.nSamplesPerSec);
goto done;
}
}
}
RARCH_ERR("[WASAPI]: Failed to select client format: No suitable format available.\n");
break;
}
default:
/* Something else went wrong. */
RARCH_ERR("[WASAPI]: Failed to select client format: %s.\n", hresult_name(hr));
break;
}
done:
/* IAudioClient::IsFormatSupported allocates a format object. */
if (suggested_format)
CoTaskMemFree(suggested_format);
return result;
}
static IAudioClient *wasapi_init_client_ex(IMMDevice *device,
bool *float_fmt, unsigned *rate, unsigned latency, unsigned channels)
{
@ -320,59 +321,57 @@ static IAudioClient *wasapi_init_client_ex(IMMDevice *device,
if (FAILED(hr))
{
RARCH_ERR("[WASAPI]: IMMDevice::Activate failed: %s\n", hresult_name(hr));
RARCH_ERR("[WASAPI]: IMMDevice::Activate failed: %s.\n", hresult_name(hr));
return NULL;
}
hr = _IAudioClient_GetDevicePeriod(client, NULL, &minimum_period);
if (FAILED(hr))
{
RARCH_ERR("[WASAPI]: Failed to get device period of exclusive-mode client: %s\n", hresult_name(hr));
RARCH_ERR("[WASAPI]: Failed to get minimum device period of exclusive client: %s.\n", hresult_name(hr));
goto error;
}
/* buffer_duration is in 100ns units */
/* Buffer_duration is in 100ns units. */
buffer_duration = latency * 10000.0;
if (buffer_duration < minimum_period)
buffer_duration = minimum_period;
wasapi_set_format(&wf, *float_fmt, *rate, channels);
RARCH_LOG("[WASAPI]: Requesting format: %u-bit %u-channel client with %s samples at %uHz\n",
wf.Format.wBitsPerSample,
wf.Format.nChannels, wave_format_name(&wf), wf.Format.nSamplesPerSec);
if (wasapi_select_device_format(&wf, client, AUDCLNT_SHAREMODE_EXCLUSIVE, channels))
{
RARCH_LOG("[WASAPI]: Using format: %u-bit %u-channel client with %s samples at %uHz\n",
RARCH_DBG("[WASAPI]: Requesting exclusive %u-bit %u-channel client with %s samples at %uHz %ums.\n",
wf.Format.wBitsPerSample,
wf.Format.nChannels, wave_format_name(&wf), wf.Format.nSamplesPerSec);
}
else
wf.Format.nChannels,
wave_format_name(&wf),
wf.Format.nSamplesPerSec,
latency);
if (!wasapi_select_device_format(&wf, client, AUDCLNT_SHAREMODE_EXCLUSIVE, channels))
{
RARCH_ERR("[WASAPI]: Failed to select a suitable device format\n");
RARCH_ERR("[WASAPI]: Failed to select a suitable device format.\n");
goto error;
}
hr = _IAudioClient_Initialize(client, AUDCLNT_SHAREMODE_EXCLUSIVE,
AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_NOPERSIST,
buffer_duration, buffer_duration, (WAVEFORMATEX*)&wf, NULL);
if (hr == AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED)
{
RARCH_WARN("[WASAPI] Unaligned buffer size: %s\n", hresult_name(hr));
RARCH_WARN("[WASAPI]: Unaligned buffer size: %s.\n", hresult_name(hr));
hr = _IAudioClient_GetBufferSize(client, &buffer_length);
if (FAILED(hr))
{
RARCH_ERR("[WASAPI] Failed to get buffer size of client: %s\n", hresult_name(hr));
RARCH_ERR("[WASAPI]: Failed to get buffer size of client: %s.\n", hresult_name(hr));
goto error;
}
IFACE_RELEASE(client);
hr = _IMMDevice_Activate(device,
hr = _IMMDevice_Activate(device,
IID_IAudioClient,
CLSCTX_ALL, NULL, (void**)&client);
if (FAILED(hr))
{
RARCH_ERR("[WASAPI] IMMDevice::Activate failed: %s\n", hresult_name(hr));
RARCH_ERR("[WASAPI]: IMMDevice::Activate failed: %s.\n", hresult_name(hr));
return NULL;
}
@ -384,12 +383,12 @@ static IAudioClient *wasapi_init_client_ex(IMMDevice *device,
if (hr == AUDCLNT_E_ALREADY_INITIALIZED)
{
IFACE_RELEASE(client);
hr = _IMMDevice_Activate(device,
hr = _IMMDevice_Activate(device,
IID_IAudioClient,
CLSCTX_ALL, NULL, (void**)&client);
if (FAILED(hr))
{
RARCH_ERR("[WASAPI] IMMDevice::Activate failed: %s\n", hresult_name(hr));
RARCH_ERR("[WASAPI] IMMDevice::Activate failed: %s.\n", hresult_name(hr));
return NULL;
}
@ -408,16 +407,13 @@ static IAudioClient *wasapi_init_client_ex(IMMDevice *device,
if (FAILED(hr))
{
RARCH_ERR("[WASAPI]: Failed to create exclusive-mode client: %s\n", hresult_name(hr));
RARCH_ERR("[WASAPI]: IAudioClient::Initialize failed: %s.\n", hresult_name(hr));
goto error;
}
*float_fmt = wf.Format.wFormatTag != WAVE_FORMAT_PCM;
*rate = wf.Format.nSamplesPerSec;
RARCH_LOG("[WASAPI]: Initialized exclusive %s client at %uHz, latency %ums\n",
*float_fmt ? "float" : "pcm", *rate, latency);
return client;
error:
@ -430,27 +426,46 @@ static IAudioClient *wasapi_init_client_sh(IMMDevice *device,
bool *float_fmt, unsigned *rate, unsigned latency, unsigned channels)
{
WAVEFORMATEXTENSIBLE wf;
IAudioClient *client = NULL;
bool float_fmt_res = *float_fmt;
unsigned rate_res = *rate;
HRESULT hr = _IMMDevice_Activate(device,
IID_IAudioClient,
CLSCTX_ALL, NULL, (void**)&client);
IAudioClient *client = NULL;
settings_t *settings = config_get_ptr();
unsigned sh_buffer_length = settings->uints.audio_wasapi_sh_buffer_length;
REFERENCE_TIME default_period = 0;
REFERENCE_TIME buffer_duration = 0;
HRESULT hr = _IMMDevice_Activate(device,
IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&client);
if (FAILED(hr))
{ /* If we couldn't create the IAudioClient... */
RARCH_ERR("[WASAPI]: Failed to create %s IAudioClient: %s\n", hresult_name(hr));
{
RARCH_ERR("[WASAPI]: IMMDevice::Activate failed: %s.\n", hresult_name(hr));
return NULL;
}
wasapi_set_format(&wf, float_fmt_res, rate_res, channels);
if (wasapi_select_device_format(&wf, client, AUDCLNT_SHAREMODE_SHARED, channels))
hr = _IAudioClient_GetDevicePeriod(client, &default_period, NULL);
if (FAILED(hr))
{
RARCH_LOG("[WASAPI]: Requesting %u-channel shared-mode client with %s samples at %uHz.\n",
wf.Format.nChannels, wave_format_name(&wf), wf.Format.nSamplesPerSec);
RARCH_ERR("[WASAPI]: Failed to get default device period of shared client: %s.\n", hresult_name(hr));
goto error;
}
else
/* Use audio latency setting for buffer size if allowed */
if ( (sh_buffer_length < WASAPI_SH_BUFFER_DEVICE_PERIOD)
|| (sh_buffer_length > WASAPI_SH_BUFFER_CLIENT_BUFFER))
{
/* Buffer_duration is in 100ns units. */
buffer_duration = latency * 10000.0;
if (buffer_duration < default_period)
buffer_duration = default_period;
}
wasapi_set_format(&wf, *float_fmt, *rate, channels);
RARCH_DBG("[WASAPI]: Requesting shared %u-bit %u-channel client with %s samples at %uHz %ums.\n",
wf.Format.wBitsPerSample,
wf.Format.nChannels,
wave_format_name(&wf),
wf.Format.nSamplesPerSec,
latency);
if (!wasapi_select_device_format(&wf, client, AUDCLNT_SHAREMODE_SHARED, channels))
{
RARCH_ERR("[WASAPI]: Failed to select a suitable device format.\n");
goto error;
@ -458,37 +473,34 @@ static IAudioClient *wasapi_init_client_sh(IMMDevice *device,
hr = _IAudioClient_Initialize(client, AUDCLNT_SHAREMODE_SHARED,
AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
0, 0, (WAVEFORMATEX*)&wf, NULL);
buffer_duration, 0, (WAVEFORMATEX*)&wf, NULL);
if (hr == AUDCLNT_E_ALREADY_INITIALIZED)
{
IFACE_RELEASE(client);
hr = _IMMDevice_Activate(device,
hr = _IMMDevice_Activate(device,
IID_IAudioClient,
CLSCTX_ALL, NULL, (void**)&client);
if (FAILED(hr))
{
RARCH_ERR("[WASAPI]: IMMDevice::Activate failed: %s\n", hresult_name(hr));
RARCH_ERR("[WASAPI]: IMMDevice::Activate failed: %s.\n", hresult_name(hr));
return NULL;
}
hr = _IAudioClient_Initialize(client, AUDCLNT_SHAREMODE_SHARED,
AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
0, 0, (WAVEFORMATEX*)&wf, NULL);
buffer_duration, 0, (WAVEFORMATEX*)&wf, NULL);
}
if (FAILED(hr))
{
RARCH_ERR("[WASAPI]: IAudioClient::Initialize failed: %s\n", hresult_name(hr));
RARCH_ERR("[WASAPI]: IAudioClient::Initialize failed: %s.\n", hresult_name(hr));
goto error;
}
*float_fmt = wf.Format.wFormatTag != WAVE_FORMAT_PCM;
*rate = wf.Format.nSamplesPerSec;
RARCH_LOG("[WASAPI]: Initialized shared %s client at %uHz.\n",
wave_format_name(&wf), *rate);
return client;
error:
@ -507,29 +519,26 @@ IMMDevice *wasapi_init_device(const char *id, EDataFlow data_flow)
const char *data_flow_name = wasapi_data_flow_name(data_flow);
if (id)
{
RARCH_LOG("[WASAPI]: Initializing %s device \"%s\"..\n", data_flow_name, id);
}
RARCH_DBG("[WASAPI]: Initializing %s device \"%s\"..\n", data_flow_name, id);
else
{
RARCH_LOG("[WASAPI]: Initializing default %s device..\n", data_flow_name);
}
RARCH_DBG("[WASAPI]: Initializing default %s device..\n", data_flow_name);
#ifdef __cplusplus
hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL,
IID_IMMDeviceEnumerator, (void **)&enumerator);
#else
hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL,
&IID_IMMDeviceEnumerator, (void **)&enumerator);
&IID_IMMDeviceEnumerator, (void **)&enumerator);
#endif
if (FAILED(hr))
{
RARCH_ERR("[WASAPI]: Failed to create device enumerator: %s\n", hresult_name(hr));
RARCH_ERR("[WASAPI]: Failed to create device enumerator: %s.\n", hresult_name(hr));
goto error;
}
if (id)
{ /* If a specific device was requested... */
{
/* If a specific device was requested... */
int32_t idx_found = -1;
struct string_list *list = (struct string_list*)mmdevice_list_new(NULL, data_flow);
@ -540,20 +549,21 @@ IMMDevice *wasapi_init_device(const char *id, EDataFlow data_flow)
}
if (list->elems)
{ /* If any devices were found... */
{
/* If any devices were found... */
unsigned d;
for (d = 0; d < list->size; d++)
{
if (string_is_equal(id, list->elems[d].data))
{
RARCH_DBG("[WASAPI]: Found device #%d: \"%s\"\n", d, list->elems[d].data);
RARCH_DBG("[WASAPI]: Found device #%d: \"%s\".\n", d, list->elems[d].data);
idx_found = d;
break;
}
}
/* Index was not found yet based on name string,
* just assume id is a one-character number index. */
if (idx_found == -1 && isdigit(id[0]))
{
idx_found = strtoul(id, NULL, 0);
@ -569,14 +579,14 @@ IMMDevice *wasapi_init_device(const char *id, EDataFlow data_flow)
data_flow, DEVICE_STATE_ACTIVE, &collection);
if (FAILED(hr))
{
RARCH_ERR("[WASAPI]: Failed to enumerate audio endpoints: %s\n", hresult_name(hr));
RARCH_ERR("[WASAPI]: Failed to enumerate audio endpoints: %s.\n", hresult_name(hr));
goto error;
}
hr = _IMMDeviceCollection_GetCount(collection, &dev_count);
if (FAILED(hr))
{
RARCH_ERR("[WASAPI]: Failed to count IMMDevices: %s\n", hresult_name(hr));
RARCH_ERR("[WASAPI]: Failed to count IMMDevices: %s.\n", hresult_name(hr));
goto error;
}
@ -585,7 +595,7 @@ IMMDevice *wasapi_init_device(const char *id, EDataFlow data_flow)
hr = _IMMDeviceCollection_Item(collection, i, &device);
if (FAILED(hr))
{
RARCH_ERR("[WASAPI]: Failed to get IMMDevice #%d: %s\n", i, hresult_name(hr));
RARCH_ERR("[WASAPI]: Failed to get IMMDevice #%d: %s.\n", i, hresult_name(hr));
goto error;
}
@ -601,7 +611,7 @@ IMMDevice *wasapi_init_device(const char *id, EDataFlow data_flow)
enumerator, data_flow, eConsole, &device);
if (FAILED(hr))
{
RARCH_ERR("[WASAPI]: Failed to get default audio endpoint: %s\n", hresult_name(hr));
RARCH_ERR("[WASAPI]: Failed to get default audio endpoint: %s.\n", hresult_name(hr));
goto error;
}
}
@ -619,13 +629,9 @@ error:
IFACE_RELEASE(enumerator);
if (id)
{
RARCH_WARN("[WASAPI]: Failed to initialize %s device \"%s\".\n", data_flow_name, id);
}
else
{
RARCH_ERR("[WASAPI]: Failed to initialize default %s device.\n", data_flow_name);
}
return NULL;
}
@ -635,14 +641,11 @@ IAudioClient *wasapi_init_client(IMMDevice *device, bool *exclusive,
{
HRESULT hr;
IAudioClient *client;
double latency_res;
REFERENCE_TIME device_period = 0;
REFERENCE_TIME stream_latency = 0;
UINT32 buffer_length = 0;
RARCH_DBG("[WASAPI]: Requesting %s %s client (rate=%uHz, latency=%ums).\n",
*exclusive ? "exclusive" : "shared",
*float_fmt ? "float" : "pcm", *rate, latency);
float latency_res;
REFERENCE_TIME device_period = 0;
REFERENCE_TIME device_period_min = 0;
REFERENCE_TIME stream_latency = 0;
UINT32 buffer_length = 0;
if (*exclusive)
{
@ -670,45 +673,24 @@ IAudioClient *wasapi_init_client(IMMDevice *device, bool *exclusive,
if (!client)
return NULL;
/* next calls are allowed to fail (we losing info only) */
/* Remaining calls are for logging purposes. */
if (*exclusive)
hr = _IAudioClient_GetDevicePeriod(client, &device_period, &device_period_min);
if (SUCCEEDED(hr))
{
hr = _IAudioClient_GetDevicePeriod(client, NULL, &device_period);
if (SUCCEEDED(hr))
{
RARCH_LOG("[WASAPI]: Minimum exclusive-mode device period is %uns (%.1fms).\n",
device_period * 100, (double)device_period * 100 / 1e6);
}
/* device_period is in 100ns units */
RARCH_DBG("[WASAPI]: Default device period is %.1fms.\n", (float)device_period * 100 / 1e6);
RARCH_DBG("[WASAPI]: Minimum device period is %.1fms.\n", (float)device_period_min * 100 / 1e6);
}
else
{
hr = _IAudioClient_GetDevicePeriod(client, &device_period, NULL);
if (SUCCEEDED(hr))
{
RARCH_LOG("[WASAPI]: Default shared-mode device period is %uns (%.1fms).\n",
device_period * 100, (double)device_period * 100 / 1e6);
}
}
if (FAILED(hr))
{
RARCH_WARN("[WASAPI]: IAudioClient::GetDevicePeriod failed: %s\n", hresult_name(hr));
}
RARCH_WARN("[WASAPI]: IAudioClient::GetDevicePeriod failed: %s.\n", hresult_name(hr));
if (!*exclusive)
{
hr = _IAudioClient_GetStreamLatency(client, &stream_latency);
if (SUCCEEDED(hr))
{
RARCH_LOG("[WASAPI]: Shared stream latency is %uns (%.1fms).\n",
stream_latency * 100, (double)stream_latency * 100 / 1e6);
}
RARCH_DBG("[WASAPI]: Shared stream latency is %.1fms.\n", (float)stream_latency * 100 / 1e6);
else
{
RARCH_WARN("[WASAPI]: IAudioClient::GetStreamLatency failed: %s\n", hresult_name(hr));
}
RARCH_WARN("[WASAPI]: IAudioClient::GetStreamLatency failed: %s.\n", hresult_name(hr));
}
hr = _IAudioClient_GetBufferSize(client, &buffer_length);
@ -716,29 +698,38 @@ IAudioClient *wasapi_init_client(IMMDevice *device, bool *exclusive,
{
size_t num_samples = buffer_length * channels;
size_t num_bytes = num_samples * (*float_fmt ? sizeof(float) : sizeof(int16_t));
RARCH_LOG("[WASAPI]: Endpoint buffer size is %u frames (%u samples, %u bytes).\n",
buffer_length, num_samples, num_bytes);
RARCH_DBG("[WASAPI]: Endpoint buffer size is %u frames (%u samples, %u bytes, %.1f ms).\n",
buffer_length, num_samples, num_bytes, (float)buffer_length * 1000.0 / *rate);
}
else
{
RARCH_WARN("[WASAPI]: IAudioClient::GetBufferSize failed: %s.\n", hresult_name(hr));
}
if (*exclusive)
latency_res = (double)buffer_length * 1000.0 / (*rate);
latency_res = (float)buffer_length * 1000.0 / (*rate);
else
latency_res = (double)(stream_latency + device_period) / 10000.0;
{
settings_t *settings = config_get_ptr();
unsigned sh_buffer_length = settings->uints.audio_wasapi_sh_buffer_length;
switch (sh_buffer_length)
{
case WASAPI_SH_BUFFER_AUDIO_LATENCY:
case WASAPI_SH_BUFFER_CLIENT_BUFFER:
latency_res = (float)buffer_length * 1000.0 / (*rate);
break;
case WASAPI_SH_BUFFER_DEVICE_PERIOD:
latency_res = (float)(stream_latency + device_period) / 10000.0;
break;
default:
latency_res = (float)sh_buffer_length * 1000.0 / (*rate);
break;
}
}
RARCH_LOG("[WASAPI]: Client initialized (%s, %s, %uHz, %.1fms).\n",
*exclusive ? "exclusive" : "shared",
*float_fmt ? "float" : "pcm",
*float_fmt ? "FLOAT" : "PCM",
*rate, latency_res);
RARCH_LOG("[WASAPI]: Client's buffer length is %u frames (%.1fms).\n",
buffer_length, (double)buffer_length * 1000.0 / (*rate));
RARCH_LOG("[WASAPI]: Device period is %lld frames (%.1fms).\n",
device_period * (*rate) / 10000000, (double)device_period / 10000.0);
return client;
}

View File

@ -23,8 +23,13 @@
#ifndef RETROARCH_COMMON_WASAPI_H
#define RETROARCH_COMMON_WASAPI_H
#include "../common/mmdevice_common_inline.h"
#include "boolean.h"
#include "mmdevice_common_inline.h"
#include <boolean.h>
/* Shared buffer size replacement placeholders */
#define WASAPI_SH_BUFFER_AUDIO_LATENCY 0
#define WASAPI_SH_BUFFER_DEVICE_PERIOD 32
#define WASAPI_SH_BUFFER_CLIENT_BUFFER 64
const char *hresult_name(HRESULT hr);
const char* wasapi_error(DWORD error);
@ -32,4 +37,4 @@ IMMDevice *wasapi_init_device(const char *id, EDataFlow data_flow);
IAudioClient *wasapi_init_client(IMMDevice *device, bool *exclusive,
bool *float_fmt, unsigned *rate, unsigned latency, unsigned channels);
#endif /* RETROARCH_COMMON_WASAPI_H */
#endif /* RETROARCH_COMMON_WASAPI_H */

View File

@ -153,7 +153,7 @@ static void choose_output_device(coreaudio_t *dev, const char* device)
#endif
propaddr.mSelector = kAudioDevicePropertyDeviceName;
for (i = 0; i < deviceCount; i ++)
for (i = 0; i < (int)deviceCount; i ++)
{
char device_name[1024];
device_name[0] = 0;

View File

@ -136,7 +136,10 @@ static void *psp_audio_init(const char *device,
return NULL;
if ((port = configureAudio(rate)) < 0)
{
free(psp);
return NULL;
}
#if defined(ORBIS)
sceAudioOutInit();

View File

@ -257,9 +257,9 @@ int rsd_set_param (rsound_t *rd, enum rsd_settings option, void* param);
void rsd_set_callback (rsound_t *rd, rsd_audio_callback_t callback, rsd_error_callback_t err_callback, size_t max_size, void *userdata);
/* Lock and unlock the callback. When the callback lock is aquired, the callback is guaranteed to not be executing.
/* Lock and unlock the callback. When the callback lock is acquired, the callback is guaranteed to not be executing.
The lock has to be unlocked afterwards.
Attemping to call several rsd_callback_lock() in succession might cause a deadlock.
Attempting to call several rsd_callback_lock() in succession might cause a deadlock.
The lock should be held for as short period as possible.
Try to avoid calling code that may block when holding the lock. */
void rsd_callback_lock (rsound_t *rd);
@ -294,10 +294,10 @@ size_t rsd_write (rsound_t *rd, const void* buf, size_t size);
*NOTE* This function is deprecated, it should not be used in new applications. */
size_t rsd_pointer (rsound_t *rd);
/* Aquires how much data can be written to the buffer without blocking */
/* Acquires how much data can be written to the buffer without blocking */
size_t rsd_get_avail (rsound_t *rd);
/* Aquires the latency at the moment for the audio stream. It is measured in bytes. Useful for syncing video and audio. */
/* Acquires the latency at the moment for the audio stream. It is measured in bytes. Useful for syncing video and audio. */
size_t rsd_delay (rsound_t *rd);
/* Utility for returning latency in milliseconds. */

View File

@ -93,7 +93,7 @@ static void sdl_audio_playback_cb(void *data, Uint8 *stream, int len)
memset(stream + write_size, 0, len - write_size);
}
static INLINE int find_num_frames(int rate, int latency)
static INLINE int sdl_audio_find_num_frames(int rate, int latency)
{
int frames = (rate * latency) / 1000;
@ -137,7 +137,7 @@ static void *sdl_audio_init(const char *device,
* carry approximately half of the latency.
*
* SDL double buffers audio and we do as well. */
frames = find_num_frames(rate, latency / 4);
frames = sdl_audio_find_num_frames(rate, latency / 4);
/* First, let's initialize the output device. */
spec.freq = rate;

View File

@ -121,8 +121,8 @@
*/
#define PCM_STATE_RUNNING 0x03
/** For inputs, this means an overrun occured.
* For outputs, this means an underrun occured.
/** For inputs, this means an overrun occurred.
* For outputs, this means an underrun occurred.
*/
#define PCM_STATE_XRUN 0x04
@ -755,13 +755,13 @@ struct pcm
unsigned int running:1;
/** Whether or not the PCM has been prepared */
unsigned int prepared:1;
/** The number of underruns that have occured */
/** The number of underruns that have occurred */
int underruns;
/** Size of the buffer */
unsigned int buffer_size;
/** The boundary for ring buffer pointers */
unsigned int boundary;
/** Description of the last error that occured */
/** Description of the last error that occurred */
char error[PCM_ERROR_MAX];
/** Configuration that was passed to @ref pcm_open */
struct pcm_config config;
@ -845,10 +845,10 @@ static int pcm_get_file_descriptor(const struct pcm *pcm)
return pcm->fd;
}
/** Gets the error message for the last error that occured.
* If no error occured and this function is called, the results are undefined.
/** Gets the error message for the last error that occurred.
* If no error occurred and this function is called, the results are undefined.
* @param pcm A PCM handle.
* @return The error message of the last error that occured.
* @return The error message of the last error that occurred.
* @ingroup libtinyalsa-pcm
*/
static const char* pcm_get_error(const struct pcm *pcm)
@ -1195,7 +1195,7 @@ static int pcm_mmap_begin(struct pcm *pcm, void **areas, unsigned int *offset,
avail = pcm->buffer_size;
continuous = pcm->buffer_size - *offset;
/* we can only copy frames if the are availabale and continuos */
/* we can only copy frames if the are available and continuous */
copy_frames = *frames;
if (copy_frames > avail)
copy_frames = avail;
@ -1939,8 +1939,8 @@ static int pcm_state(struct pcm *pcm)
* @param pcm A PCM handle.
* @param timeout The maximum amount of time to wait for, in terms of milliseconds.
* @returns If frames became available, one is returned.
* If a timeout occured, zero is returned.
* If an error occured, a negative number is returned.
* If a timeout occurred, zero is returned.
* If an error occurred, a negative number is returned.
* @ingroup libtinyalsa-pcm
*/
static int pcm_wait(struct pcm *pcm, int timeout)

View File

@ -27,8 +27,15 @@
#include "../../verbosity.h"
#include "../../configuration.h"
/* Get automatic buffer size from client buffer instead of device period */
#define USE_CLIENT_BUFFER
/* Max time to wait before continuing */
#define WASAPI_TIMEOUT 256
enum wasapi_flags
{
WASAPI_FLG_EXCLUSIVE = (1 << 0),
WASAPI_FLG_NONBLOCK = (1 << 1),
WASAPI_FLG_RUNNING = (1 << 2)
};
typedef struct
{
@ -36,12 +43,10 @@ typedef struct
IMMDevice *device;
IAudioClient *client;
IAudioRenderClient *renderer;
fifo_buffer_t *buffer; /* NULL in unbuffered shared mode */
size_t frame_size; /* 4 or 8 only */
fifo_buffer_t *buffer;
size_t engine_buffer_size;
bool exclusive;
bool nonblock;
bool running;
unsigned char frame_size; /* 4 or 8 only */
uint8_t flags;
} wasapi_t;
static void *wasapi_init(const char *dev_id, unsigned rate, unsigned latency,
@ -54,70 +59,61 @@ static void *wasapi_init(const char *dev_id, unsigned rate, unsigned latency,
settings_t *settings = config_get_ptr();
bool float_format = settings->bools.audio_wasapi_float_format;
bool exclusive_mode = settings->bools.audio_wasapi_exclusive_mode;
int sh_buffer_length = settings->ints.audio_wasapi_sh_buffer_length;
unsigned sh_buffer_length = settings->uints.audio_wasapi_sh_buffer_length;
wasapi_t *w = (wasapi_t*)calloc(1, sizeof(wasapi_t));
if (!w)
return NULL;
w->exclusive = exclusive_mode;
w->device = wasapi_init_device(dev_id, eRender);
if (!w->device && dev_id)
w->device = wasapi_init_device(NULL, eRender);
if (!w->device)
goto error;
w->client = wasapi_init_client(w->device,
&w->exclusive, &float_format, &rate, latency, 2);
if (!w->client)
if (!(w->client = wasapi_init_client(w->device,
&exclusive_mode, &float_format, &rate, latency, 2)))
goto error;
if (exclusive_mode)
w->flags |= WASAPI_FLG_EXCLUSIVE;
hr = _IAudioClient_GetBufferSize(w->client, &frame_count);
if (FAILED(hr))
goto error;
w->frame_size = float_format ? 8 : 4;
w->engine_buffer_size = frame_count * w->frame_size;
w->frame_size = float_format ? 8 : 4;
w->engine_buffer_size = frame_count * w->frame_size;
if (w->exclusive)
if ((w->flags & WASAPI_FLG_EXCLUSIVE) > 0)
{
w->buffer = fifo_new(w->engine_buffer_size);
if (!w->buffer)
if (!(w->buffer = fifo_new(w->engine_buffer_size)))
goto error;
RARCH_LOG("[WASAPI]: Intermediate buffer length is %u frames (%.1fms).\n",
frame_count, (double)frame_count * 1000.0 / rate);
}
else if (sh_buffer_length)
{
if (sh_buffer_length < 0)
{
#ifdef USE_CLIENT_BUFFER
sh_buffer_length = frame_count;
#else
hr = _IAudioClient_GetDevicePeriod(w->client, &dev_period, NULL);
if (FAILED(hr))
goto error;
sh_buffer_length = dev_period * rate / 10000000;
#endif
}
w->buffer = fifo_new(sh_buffer_length * w->frame_size);
if (!w->buffer)
goto error;
RARCH_LOG("[WASAPI]: Intermediate buffer length is %u frames (%.1fms).\n",
sh_buffer_length, (double)sh_buffer_length * 1000.0 / rate);
}
else
{
RARCH_LOG("[WASAPI]: Intermediate buffer is off. \n");
switch (sh_buffer_length)
{
case WASAPI_SH_BUFFER_AUDIO_LATENCY:
case WASAPI_SH_BUFFER_CLIENT_BUFFER:
sh_buffer_length = frame_count;
break;
case WASAPI_SH_BUFFER_DEVICE_PERIOD:
hr = _IAudioClient_GetDevicePeriod(w->client, &dev_period, NULL);
if (FAILED(hr))
goto error;
sh_buffer_length = dev_period * rate / 10000000;
break;
default:
break;
}
if (!(w->buffer = fifo_new(sh_buffer_length * w->frame_size)))
goto error;
}
w->write_event = CreateEventA(NULL, FALSE, FALSE, NULL);
if (!w->write_event)
if (!(w->write_event = CreateEventA(NULL, FALSE, FALSE, NULL)))
goto error;
hr = _IAudioClient_SetEventHandle(w->client, w->write_event);
@ -143,8 +139,11 @@ static void *wasapi_init(const char *dev_id, unsigned rate, unsigned latency,
if (FAILED(hr))
goto error;
w->running = true;
w->nonblock = !settings->bools.audio_sync;
w->flags |= WASAPI_FLG_RUNNING;
if (settings->bools.audio_sync)
w->flags &= ~(WASAPI_FLG_NONBLOCK);
else
w->flags |= (WASAPI_FLG_NONBLOCK);
if (new_rate)
*new_rate = rate;
@ -164,205 +163,194 @@ error:
return NULL;
}
static bool wasapi_flush(wasapi_t * w, const void * data, size_t size)
{
BYTE *dest = NULL;
UINT32 frame_count = size / w->frame_size;
if (FAILED(_IAudioRenderClient_GetBuffer(
w->renderer, frame_count, &dest)))
return false;
memcpy(dest, data, size);
if (FAILED(_IAudioRenderClient_ReleaseBuffer(
w->renderer, frame_count, 0)))
return false;
return true;
}
static bool wasapi_flush_buffer(wasapi_t * w, size_t size)
{
BYTE *dest = NULL;
UINT32 frame_count = size / w->frame_size;
if (FAILED(_IAudioRenderClient_GetBuffer(
w->renderer, frame_count, &dest)))
return false;
fifo_read(w->buffer, dest, size);
if (FAILED(_IAudioRenderClient_ReleaseBuffer(
w->renderer, frame_count, 0)))
return false;
return true;
}
static ssize_t wasapi_write_sh_buffer(wasapi_t *w, const void * data, size_t size)
{
ssize_t written = -1;
size_t write_avail = FIFO_WRITE_AVAIL(w->buffer);
UINT32 padding = 0;
if (!write_avail)
{
size_t read_avail = 0;
if (!(WaitForSingleObject(w->write_event, INFINITE) == WAIT_OBJECT_0))
return -1;
if (FAILED(_IAudioClient_GetCurrentPadding(w->client, &padding)))
return -1;
read_avail = FIFO_READ_AVAIL(w->buffer);
write_avail = w->engine_buffer_size - padding * w->frame_size;
written = read_avail < write_avail ? read_avail : write_avail;
if (written)
if (!wasapi_flush_buffer(w, written))
return -1;
}
write_avail = FIFO_WRITE_AVAIL(w->buffer);
written = size < write_avail ? size : write_avail;
if (written)
fifo_write(w->buffer, data, written);
return written;
}
static ssize_t wasapi_write_sh(wasapi_t *w, const void * data, size_t size)
{
ssize_t written = -1;
size_t write_avail = 0;
UINT32 padding = 0;
if (!(WaitForSingleObject(w->write_event, INFINITE) == WAIT_OBJECT_0))
return -1;
if (FAILED(_IAudioClient_GetCurrentPadding(w->client, &padding)))
return -1;
write_avail = w->engine_buffer_size - padding * w->frame_size;
if (!write_avail)
return 0;
written = size < write_avail ? size : write_avail;
if (written)
if (!wasapi_flush(w, data, written))
return -1;
return written;
}
static ssize_t wasapi_write_sh_nonblock(wasapi_t *w, const void * data, size_t size)
{
ssize_t written = -1;
size_t write_avail = 0;
UINT32 padding = 0;
if (w->buffer)
{
write_avail = FIFO_WRITE_AVAIL(w->buffer);
if (!write_avail)
{
size_t read_avail = 0;
if (FAILED(_IAudioClient_GetCurrentPadding(w->client, &padding)))
return -1;
read_avail = FIFO_READ_AVAIL(w->buffer);
write_avail = w->engine_buffer_size - padding * w->frame_size;
written = read_avail < write_avail ? read_avail : write_avail;
if (written)
if (!wasapi_flush_buffer(w, written))
return -1;
}
write_avail = FIFO_WRITE_AVAIL(w->buffer);
written = size < write_avail ? size : write_avail;
if (written)
fifo_write(w->buffer, data, written);
}
else
{
if (FAILED(_IAudioClient_GetCurrentPadding(w->client, &padding)))
return -1;
if (!(write_avail = w->engine_buffer_size - padding * w->frame_size))
return 0;
written = size < write_avail ? size : write_avail;
if (written)
if (!wasapi_flush(w, data, written))
return -1;
}
return written;
}
static ssize_t wasapi_write_ex(wasapi_t *w, const void * data, size_t size, DWORD ms)
{
ssize_t written = 0;
size_t write_avail = FIFO_WRITE_AVAIL(w->buffer);
if (!write_avail)
{
if (WaitForSingleObject(w->write_event, ms) != WAIT_OBJECT_0)
return 0;
if (!wasapi_flush_buffer(w, w->engine_buffer_size))
return -1;
write_avail = w->engine_buffer_size;
}
written = size < write_avail ? size : write_avail;
fifo_write(w->buffer, data, written);
return written;
}
static ssize_t wasapi_write(void *wh, const void *data, size_t size)
{
size_t written = 0;
wasapi_t *w = (wasapi_t*)wh;
uint8_t flg = w->flags;
if (w->nonblock)
{
if (w->exclusive)
return wasapi_write_ex(w, data, size, 0);
return wasapi_write_sh_nonblock(w, data, size);
}
if (!((flg & WASAPI_FLG_RUNNING) > 0))
return -1;
if (w->exclusive)
if ((flg & WASAPI_FLG_EXCLUSIVE) > 0)
{
ssize_t ir;
for (ir = -1; written < size; written += ir)
if ((flg & WASAPI_FLG_NONBLOCK) > 0)
{
ir = wasapi_write_ex(w, (char*)data + written, size - written, INFINITE);
if (ir == -1)
return -1;
size_t write_avail = FIFO_WRITE_AVAIL(w->buffer);
if (!write_avail)
{
UINT32 frame_count;
BYTE *dest = NULL;
if (WaitForSingleObject(w->write_event, 0) != WAIT_OBJECT_0)
return 0;
frame_count = w->engine_buffer_size / w->frame_size;
if (FAILED(_IAudioRenderClient_GetBuffer(
w->renderer, frame_count, &dest)))
return -1;
fifo_read(w->buffer, dest, w->engine_buffer_size);
if (FAILED(_IAudioRenderClient_ReleaseBuffer(
w->renderer, frame_count, 0)))
return -1;
write_avail = w->engine_buffer_size;
}
written = (size < write_avail) ? size : write_avail;
fifo_write(w->buffer, data, written);
}
else
{
ssize_t ir;
for (ir = -1; written < size; written += ir)
{
const void *_data = (char*)data + written;
size_t __size = size - written;
size_t write_avail = FIFO_WRITE_AVAIL(w->buffer);
if (!write_avail)
{
BYTE *dest = NULL;
if (WaitForSingleObject(w->write_event, WASAPI_TIMEOUT) != WAIT_OBJECT_0)
ir = 1;
else
{
UINT32 frame_count = w->engine_buffer_size / w->frame_size;
if (FAILED(_IAudioRenderClient_GetBuffer(
w->renderer, frame_count, &dest)))
return -1;
fifo_read(w->buffer, dest, w->engine_buffer_size);
if (FAILED(_IAudioRenderClient_ReleaseBuffer(
w->renderer, frame_count, 0)))
return -1;
write_avail = w->engine_buffer_size;
}
}
ir = (__size < write_avail) ? __size : write_avail;
fifo_write(w->buffer, _data, ir);
}
}
}
else
{
ssize_t ir;
if (w->buffer)
if ((flg & WASAPI_FLG_NONBLOCK) > 0)
{
size_t write_avail = 0;
UINT32 padding = 0;
if (w->buffer)
{
if (!(write_avail = FIFO_WRITE_AVAIL(w->buffer)))
{
size_t read_avail = 0;
if (FAILED(_IAudioClient_GetCurrentPadding(w->client, &padding)))
return -1;
read_avail = FIFO_READ_AVAIL(w->buffer);
write_avail = w->engine_buffer_size - padding * w->frame_size;
written = read_avail < write_avail ? read_avail : write_avail;
if (written)
{
BYTE *dest = NULL;
UINT32 frame_count = written / w->frame_size;
if (FAILED(_IAudioRenderClient_GetBuffer(
w->renderer, frame_count, &dest)))
return -1;
fifo_read(w->buffer, dest, written);
if (FAILED(_IAudioRenderClient_ReleaseBuffer(
w->renderer, frame_count, 0)))
return -1;
}
}
write_avail = FIFO_WRITE_AVAIL(w->buffer);
written = size < write_avail ? size : write_avail;
if (written)
fifo_write(w->buffer, data, written);
}
else
{
if (FAILED(_IAudioClient_GetCurrentPadding(w->client, &padding)))
return -1;
if (!(write_avail = w->engine_buffer_size - padding * w->frame_size))
return 0;
written = size < write_avail ? size : write_avail;
if (written)
{
BYTE *dest = NULL;
UINT32 frame_count = written / w->frame_size;
if (FAILED(_IAudioRenderClient_GetBuffer(
w->renderer, frame_count, &dest)))
return -1;
memcpy(dest, data, written);
if (FAILED(_IAudioRenderClient_ReleaseBuffer(
w->renderer, frame_count, 0)))
return -1;
}
}
}
else if (w->buffer)
{
ssize_t ir;
for (ir = -1; written < size; written += ir)
{
ir = wasapi_write_sh_buffer(w, (char*)data + written, size - written);
if (ir == -1)
return -1;
const void *_data = (char*)data + written;
size_t _size = size - written;
size_t write_avail = FIFO_WRITE_AVAIL(w->buffer);
UINT32 padding = 0;
if (!write_avail)
{
size_t read_avail = 0;
if (!(WaitForSingleObject(w->write_event, WASAPI_TIMEOUT) == WAIT_OBJECT_0))
return -1;
if (FAILED(_IAudioClient_GetCurrentPadding(w->client, &padding)))
return -1;
read_avail = FIFO_READ_AVAIL(w->buffer);
write_avail = w->engine_buffer_size - padding * w->frame_size;
ir = read_avail < write_avail ? read_avail : write_avail;
if (ir)
{
BYTE *dest = NULL;
UINT32 frame_count = ir / w->frame_size;
if (FAILED(_IAudioRenderClient_GetBuffer(
w->renderer, frame_count, &dest)))
return -1;
fifo_read(w->buffer, dest, ir);
if (FAILED(_IAudioRenderClient_ReleaseBuffer(
w->renderer, frame_count, 0)))
return -1;
}
}
write_avail = FIFO_WRITE_AVAIL(w->buffer);
ir = (_size < write_avail) ? _size : write_avail;
if (ir)
fifo_write(w->buffer, _data, ir);
}
}
else
{
ssize_t ir;
for (ir = -1; written < size; written += ir)
{
ir = wasapi_write_sh(w, (char*)data + written, size - written);
if (ir == -1)
const void *_data = (char*)data + written;
size_t _size = size - written;
size_t write_avail = 0;
UINT32 padding = 0;
if (!(WaitForSingleObject(w->write_event, WASAPI_TIMEOUT) == WAIT_OBJECT_0))
return -1;
if (FAILED(_IAudioClient_GetCurrentPadding(w->client, &padding)))
return -1;
if (!(write_avail = w->engine_buffer_size - padding * w->frame_size))
ir = 0;
else
{
ir = (_size < write_avail) ? _size : write_avail;
if (ir)
{
BYTE *dest = NULL;
UINT32 frame_count = ir / w->frame_size;
if (FAILED(_IAudioRenderClient_GetBuffer(
w->renderer, frame_count, &dest)))
return -1;
memcpy(dest, _data, ir);
if (FAILED(_IAudioRenderClient_ReleaseBuffer(
w->renderer, frame_count, 0)))
return -1;
}
}
}
}
}
@ -375,9 +363,9 @@ static bool wasapi_stop(void *wh)
wasapi_t *w = (wasapi_t*)wh;
if (FAILED(_IAudioClient_Stop(w->client)))
return !w->running;
return (!(w->flags & WASAPI_FLG_RUNNING));
w->running = false;
w->flags &= ~(WASAPI_FLG_RUNNING);
return true;
}
@ -386,33 +374,29 @@ static bool wasapi_start(void *wh, bool u)
{
wasapi_t *w = (wasapi_t*)wh;
HRESULT hr = _IAudioClient_Start(w->client);
if (hr == AUDCLNT_E_NOT_STOPPED)
return true;
if (FAILED(hr))
return w->running;
w->running = true;
if (hr != AUDCLNT_E_NOT_STOPPED)
{
if (FAILED(hr))
return ((w->flags & WASAPI_FLG_RUNNING) > 0);
w->flags |= (WASAPI_FLG_RUNNING);
}
return true;
}
static bool wasapi_alive(void *wh)
{
wasapi_t *w = (wasapi_t*)wh;
return w->running;
return ((w->flags & WASAPI_FLG_RUNNING) > 0);
}
static void wasapi_set_nonblock_state(void *wh, bool nonblock)
{
wasapi_t *w = (wasapi_t*)wh;
if (w->nonblock != nonblock)
RARCH_DBG("[WASAPI]: Sync %s.\n", nonblock ? "off" : "on");
w->nonblock = nonblock;
if (nonblock)
w->flags |= WASAPI_FLG_NONBLOCK;
else
w->flags &= ~WASAPI_FLG_NONBLOCK;
}
static void wasapi_free(void *wh)
@ -434,7 +418,6 @@ static void wasapi_free(void *wh)
if (ir == WAIT_FAILED)
RARCH_ERR("[WASAPI]: WaitForSingleObject failed with error %d.\n", GetLastError());
/* If event isn't signaled log and leak */
if (!(ir == WAIT_OBJECT_0))
return;
@ -460,13 +443,10 @@ static size_t wasapi_write_avail(void *wh)
{
wasapi_t *w = (wasapi_t*)wh;
UINT32 padding = 0;
if (w->buffer)
return FIFO_WRITE_AVAIL(w->buffer);
if (FAILED(_IAudioClient_GetCurrentPadding(w->client, &padding)))
return 0;
if (w->buffer) /* Exaggerate available size for best results.. */
return FIFO_WRITE_AVAIL(w->buffer) + padding * 2;
return w->engine_buffer_size - padding * w->frame_size;
}
@ -474,7 +454,7 @@ static size_t wasapi_buffer_size(void *wh)
{
wasapi_t *w = (wasapi_t*)wh;
if (!w->exclusive && w->buffer)
if (w->buffer)
return w->buffer->size;
return w->engine_buffer_size;

View File

@ -42,7 +42,7 @@ typedef struct sdl_microphone
bool nonblock;
} sdl_microphone_t;
static INLINE int find_num_frames(int rate, int latency)
static INLINE int sdl_microphone_find_num_frames(int rate, int latency)
{
int frames = (rate * latency) / 1000;
@ -132,6 +132,16 @@ static void *sdl_microphone_open_mic(void *driver_context,
SDL_AudioSpec desired_spec = {0};
void *tmp = NULL;
#if __APPLE__
if (!string_is_equal(audio_driver_get_ident(), "sdl2"))
{
runloop_msg_queue_push(
msg_hash_to_str(MSG_SDL2_MIC_NEEDS_SDL2_AUDIO), 1, 100, true, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_WARNING);
return NULL;
}
#endif
/* If the audio driver wasn't initialized yet... */
if (!SDL_WasInit(SDL_INIT_AUDIO))
{
@ -157,7 +167,7 @@ static void *sdl_microphone_open_mic(void *driver_context,
* carry approximately half of the latency.
*
* SDL double buffers audio and we do as well. */
frames = find_num_frames(rate, latency / 4);
frames = sdl_microphone_find_num_frames(rate, latency / 4);
desired_spec.freq = rate;
desired_spec.format = AUDIO_F32SYS;

View File

@ -119,7 +119,7 @@ static int wasapi_microphone_fetch_fifo(wasapi_microphone_handle_t *microphone)
/* If the queue has room for the packets we just got... */
if (FIFO_WRITE_AVAIL(microphone->buffer) >= bytes_read && bytes_read > 0)
{
{
fifo_write(microphone->buffer, mic_input, bytes_read);
/* ...then enqueue the bytes directly from the mic's buffer */
}
@ -140,11 +140,11 @@ static int wasapi_microphone_fetch_fifo(wasapi_microphone_handle_t *microphone)
/* If this is a shared-mode stream and we didn't run out of room in the sample queue... */
if (!microphone->exclusive && frames_read > 0)
{
{
hr = _IAudioCaptureClient_GetNextPacketSize(microphone->capture, &next_packet_size);
/* Get the number of frames that the mic has for us. */
if (FAILED(hr))
{
{
RARCH_ERR("[WASAPI]: Failed to get capture device \"%s\"'s next packet size: %s\n",
microphone->device_name, hresult_name(hr));
return -1;
@ -171,7 +171,7 @@ static bool wasapi_microphone_wait_for_capture_event(wasapi_microphone_handle_t
{
/*...then let's wait for the mic to tell us that samples are ready. */
switch (WaitForSingleObject(microphone->read_event, timeout))
{
{
case WAIT_OBJECT_0:
/* Okay, there's data available. */
return true;
@ -212,7 +212,7 @@ static int wasapi_microphone_read_buffered(
/* If we don't have any queued samples to give to the core... */
if (!bytes_available)
{
{
/* If we couldn't wait for the microphone to signal a capture event... */
if (!wasapi_microphone_wait_for_capture_event(microphone, timeout))
return -1;
@ -279,8 +279,6 @@ static void wasapi_microphone_set_nonblock_state(void *driver_context, bool nonb
{
wasapi_microphone_t *wasapi = (wasapi_microphone_t*)driver_context;
RARCH_DBG("[WASAPI mic]: Sync %s.\n", nonblock ? "off" : "on");
wasapi->nonblock = nonblock;
}
@ -296,7 +294,8 @@ static void *wasapi_microphone_open_mic(void *driver_context, const char *device
bool float_format = settings->bools.microphone_wasapi_float_format;
bool exclusive_mode = settings->bools.microphone_wasapi_exclusive_mode;
unsigned sh_buffer_length = settings->uints.microphone_wasapi_sh_buffer_length;
wasapi_microphone_handle_t *microphone = calloc(1, sizeof(wasapi_microphone_handle_t));
wasapi_microphone_handle_t *microphone = (wasapi_microphone_handle_t*)calloc(
1, sizeof(wasapi_microphone_handle_t));
if (!microphone)
return NULL;
@ -306,7 +305,7 @@ static void *wasapi_microphone_open_mic(void *driver_context, const char *device
/* If we requested a particular capture device, but couldn't open it... */
if (device && !microphone->device)
{
{
RARCH_WARN("[WASAPI]: Failed to open requested capture device \"%s\", attempting to open default device\n", device);
microphone->device = wasapi_init_device(NULL, eCapture);
}
@ -345,7 +344,7 @@ static void *wasapi_microphone_open_mic(void *driver_context, const char *device
/* If this mic should be used *exclusively* by RetroArch... */
if (microphone->exclusive)
{
{
microphone->buffer = fifo_new(microphone->engine_buffer_size);
if (!microphone->buffer)
{
@ -360,7 +359,7 @@ static void *wasapi_microphone_open_mic(void *driver_context, const char *device
{
/* If the user selected the "default" shared buffer length... */
if (sh_buffer_length <= 0)
{
{
hr = _IAudioClient_GetDevicePeriod(microphone->client, &dev_period, NULL);
if (FAILED(hr))
goto error;

View File

@ -33,7 +33,7 @@
* we approximate those with polynoms
*
* CC_RESAMPLER_PRECISION defines how accurate the approximation is
* a setting of 5 or more means full precison.
* a setting of 5 or more means full precision.
* setting 0 doesn't use a polynom
* setting 1 uses P(X) = X - (3/4)*X^3 + (1/4)*X^5
*

View File

@ -441,7 +441,7 @@ static int rsnd_send_header_info(rsound_t *rd)
return 0;
}
/* Recieves backend info from server that is of interest to the client. (This mini-protocol might be extended later on.) */
/* Receives backend info from server that is of interest to the client. (This mini-protocol might be extended later on.) */
static int rsnd_get_backend_info ( rsound_t *rd )
{
#define RSND_HEADER_SIZE 8
@ -563,7 +563,7 @@ static int rsnd_create_connection(rsound_t *rd)
{
/* Part of the uber simple protocol.
1. Send wave header.
2. Recieve backend info like latency and preferred packet size.
2. Receive backend info like latency and preferred packet size.
3. Starts the playback thread. */
rc = rsnd_send_header_info(rd);
@ -602,7 +602,7 @@ static int rsnd_create_connection(rsound_t *rd)
}
/* Sends a chunk over the network. Makes sure that everything is sent if blocking. Returns -1 if connection is lost, non-negative if success.
* If blocking, and not enough data is recieved, it will return -1. */
* If blocking, and not enough data is received, it will return -1. */
static ssize_t rsnd_send_chunk(int socket, const void* buf, size_t size, int blocking)
{
ssize_t rc = 0;
@ -652,8 +652,8 @@ static ssize_t rsnd_send_chunk(int socket, const void* buf, size_t size, int blo
return (ssize_t)wrote;
}
/* Recieved chunk. Makes sure that everything is recieved if blocking. Returns -1 if connection is lost, non-negative if success.
* If blocking, and not enough data is recieved, it will return -1. */
/* Received chunk. Makes sure that everything is received if blocking. Returns -1 if connection is lost, non-negative if success.
* If blocking, and not enough data is received, it will return -1. */
static ssize_t rsnd_recv_chunk(int socket, void *buf, size_t size, int blocking)
{
ssize_t rc = 0;
@ -960,7 +960,7 @@ static int rsnd_close_ctl(rsound_t *rd)
if (fd.revents & POLLIN)
{
const char *subchar;
/* We just read everything in large chunks until we find
/* We just read everything in large chunks until we find
* what we're looking for */
int rc = net_recv(rd->conn.ctl_socket, buf + index, RSD_PROTO_MAXSIZE*2 - 1 - index, 0);
@ -991,7 +991,7 @@ static int rsnd_close_ctl(rsound_t *rd)
return 0;
}
/* Sends delay info request to server on the ctl socket.
/* Sends delay info request to server on the ctl socket.
* This code section isn't critical, and will work if it works.
* It will never block. */
static int rsnd_send_info_query(rsound_t *rd)
@ -1026,7 +1026,7 @@ static int rsnd_update_server_info(rsound_t *rd)
char *tmpstr;
memset(temp, 0, sizeof(temp));
/* We first recieve the small header. We just use the larger buffer as it is disposable. */
/* We first receive the small header. We just use the larger buffer as it is disposable. */
rc = rsnd_recv_chunk(rd->conn.ctl_socket, temp, RSD_PROTO_CHUNKSIZE, 0);
if ( rc == 0 )
break;
@ -1044,7 +1044,7 @@ static int rsnd_update_server_info(rsound_t *rd)
/* The length of the argument message is stored in the small 8 byte header. */
long int len = strtol(substr, NULL, 0);
/* Recieve the rest of the data. */
/* Receive the rest of the data. */
if ( rsnd_recv_chunk(rd->conn.ctl_socket, temp, len, 0) < len )
return -1;

View File

@ -14,18 +14,22 @@
*/
#include <math.h>
#include <memalign.h>
#include <audio/conversion/s16_to_float.h>
#include <audio/conversion/float_to_s16.h>
#include <retro_assert.h>
#include <string/stdstring.h>
#include <lists/string_list.h>
#include <audio/conversion/dual_mono.h>
#include "microphone_driver.h"
#include "audio_defines.h"
#include "../configuration.h"
#include "../driver.h"
#include "../verbosity.h"
#include "../runloop.h"
#include "memalign.h"
#include "audio/conversion/s16_to_float.h"
#include "audio/conversion/float_to_s16.h"
#include "../list_special.h"
#include "retro_assert.h"
#include "string/stdstring.h"
#include "audio/conversion/dual_mono.h"
#include "../runloop.h"
#include "../verbosity.h"
static microphone_driver_state_t mic_driver_st;
@ -235,18 +239,14 @@ static void mic_driver_microphone_handle_free(retro_microphone_t *microphone, bo
microphone->resampler = NULL;
microphone->resampler_data = NULL;
/* If the mic driver is being reset and the microphone was already valid... */
if ((microphone->flags & MICROPHONE_FLAG_ACTIVE) && is_reset)
{ /* If the mic driver is being reset and the microphone was already valid... */
microphone->flags |= MICROPHONE_FLAG_PENDING;
/* ...then we need to keep the handle itself valid
* so it can be reinitialized.
* Otherwise the core will lose mic input. */
}
else
{
memset(microphone, 0, sizeof(*microphone));
}
/* Do NOT free the microphone handle itself! It's allocated statically! */
}
@ -265,10 +265,10 @@ bool microphone_driver_init_internal(void *settings_data)
bool verbosity_enabled = verbosity_is_enabled();
size_t max_frames = AUDIO_CHUNK_SIZE_NONBLOCKING * AUDIO_MAX_RATIO;
/* If the user has mic support turned off... */
if (!settings->bools.microphone_enable)
{ /* If the user has mic support turned off... */
{
mic_st->flags &= ~MICROPHONE_DRIVER_FLAG_ACTIVE;
RARCH_DBG("[Microphone]: Refused to initialize microphone driver because it's disabled in the settings.\n");
return false;
}
@ -276,7 +276,7 @@ bool microphone_driver_init_internal(void *settings_data)
convert_float_to_s16_init_simd();
if (!(microphone_driver_find_driver(settings,
"microphone driver", verbosity_enabled)))
"microphone driver", verbosity_enabled)))
{
RARCH_ERR("[Microphone]: Failed to initialize microphone driver. Will continue without mic input.\n");
goto error;
@ -316,8 +316,7 @@ bool microphone_driver_init_internal(void *settings_data)
if (!mic_st->driver || !mic_st->driver->init)
goto error;
mic_st->driver_context = mic_st->driver->init();
if (!mic_st->driver_context)
if (!(mic_st->driver_context = mic_st->driver->init()))
goto error;
if (!string_is_empty(settings->arrays.microphone_resampler))
@ -390,10 +389,9 @@ static bool mic_driver_open_mic_internal(retro_microphone_t* microphone)
microphone->actual_params.rate
);
if (mic_driver->mic_use_float && mic_driver->mic_use_float(mic_st->driver_context, microphone->microphone_context))
{
microphone->flags |= MICROPHONE_FLAG_USE_FLOAT;
}
if ( mic_driver->mic_use_float
&& mic_driver->mic_use_float(mic_st->driver_context, microphone->microphone_context))
microphone->flags |= MICROPHONE_FLAG_USE_FLOAT;
microphone->original_ratio = (double)microphone->effective_params.rate / microphone->actual_params.rate;
@ -423,13 +421,11 @@ static void microphone_driver_close_mic_internal(retro_microphone_t *microphone,
const microphone_driver_t *mic_driver = mic_st->driver;
void *driver_context = mic_st->driver_context;
if ( microphone &&
driver_context &&
mic_driver &&
mic_driver->close_mic)
{
if ( microphone
&& driver_context
&& mic_driver
&& mic_driver->close_mic)
mic_driver_microphone_handle_free(microphone, is_reset);
}
}
void microphone_driver_close_mic(retro_microphone_t *microphone)
@ -451,11 +447,14 @@ bool microphone_driver_set_mic_state(retro_microphone_t *microphone, bool state)
return false;
/* If the provided microphone was null or invalid, or the driver is incomplete, stop. */
/* If the driver is initialized... */
if (driver_context && microphone->microphone_context)
{ /* If the driver is initialized... */
{
bool success;
/* If we want to enable this mic... */
if (state)
{ /* If we want to enable this mic... */
{
success = mic_driver->start_mic(driver_context, microphone->microphone_context);
/* Enable the mic. (Enabling an active mic is a successful noop.) */
@ -472,8 +471,8 @@ bool microphone_driver_set_mic_state(retro_microphone_t *microphone, bool state)
else
{ /* If we want to pause this mic... */
success = mic_driver->stop_mic(driver_context, microphone->microphone_context);
/* Disable the mic. (If the mic is already stopped, disabling it should still be successful.) */
/* Disable the mic. (If the mic is already stopped, disabling it should still be successful.) */
if (success)
{
microphone->flags &= ~MICROPHONE_FLAG_ENABLED;
@ -491,13 +490,9 @@ bool microphone_driver_set_mic_state(retro_microphone_t *microphone, bool state)
{ /* The driver's not ready yet, so we'll make a note
* of what the mic's state should be */
if (state)
{
microphone->flags |= MICROPHONE_FLAG_ENABLED;
}
else
{
microphone->flags &= ~MICROPHONE_FLAG_ENABLED;
}
RARCH_DBG("[Microphone]: Set pending state to %s.\n",
state ? "enabled" : "disabled");
@ -510,7 +505,6 @@ bool microphone_driver_get_mic_state(const retro_microphone_t *microphone)
{
if (!microphone || !(microphone->flags & MICROPHONE_FLAG_ACTIVE))
return false;
return microphone->flags & MICROPHONE_FLAG_ENABLED;
}
@ -563,31 +557,30 @@ static size_t microphone_driver_flush(
/* ...then skip the resampler, since it'll produce (more or less) identical results. */
frames_to_enqueue = MIN(FIFO_WRITE_AVAIL(microphone->outgoing_samples), resampler_data.input_frames);
/* If this mic provides floating-point samples... */
if (microphone->flags & MICROPHONE_FLAG_USE_FLOAT)
{ /* If this mic provides floating-point samples... */
convert_float_to_s16(mic_st->final_frames, mic_st->input_frames, resampler_data.input_frames);
{
convert_float_to_s16(mic_st->final_frames, (const float*)mic_st->input_frames, resampler_data.input_frames);
fifo_write(microphone->outgoing_samples, mic_st->final_frames, frames_to_enqueue * sizeof(int16_t));
}
else
{
fifo_write(microphone->outgoing_samples, mic_st->input_frames, frames_to_enqueue * sizeof(int16_t));
}
return resampler_data.input_frames;
}
/* Couldn't take the fast path, so let's resample the mic input */
/* First we need to format the input for the resampler. */
/* If this mic provides floating-point samples... */
if (microphone->flags & MICROPHONE_FLAG_USE_FLOAT)
{/* If this mic provides floating-point samples... */
/* Samples are already in floating-point, so we just need to up-channel them. */
convert_to_dual_mono_float(mic_st->dual_mono_frames, mic_st->input_frames, resampler_data.input_frames);
}
convert_to_dual_mono_float(mic_st->dual_mono_frames,
(const float*)mic_st->input_frames, resampler_data.input_frames);
else
{
/* Samples are 16-bit, so we need to convert them first. */
convert_s16_to_float(mic_st->converted_input_frames, mic_st->input_frames, resampler_data.input_frames, 1.0f);
convert_s16_to_float(mic_st->converted_input_frames, (const int16_t*)mic_st->input_frames, resampler_data.input_frames, 1.0f);
convert_to_dual_mono_float(mic_st->dual_mono_frames, mic_st->converted_input_frames, resampler_data.input_frames);
}
@ -613,30 +606,30 @@ int microphone_driver_read(retro_microphone_t *microphone, int16_t* frames, size
size_t frames_remaining = num_frames;
microphone_driver_state_t *mic_st = &mic_driver_st;
const microphone_driver_t *driver = mic_st->driver;
bool core_paused = runloop_flags & RUNLOOP_FLAG_PAUSED;
bool is_fastforward = runloop_flags & RUNLOOP_FLAG_FASTMOTION;
bool is_slowmo = runloop_flags & RUNLOOP_FLAG_SLOWMOTION;
bool core_paused = (runloop_flags & RUNLOOP_FLAG_PAUSED) ? true : false;
bool is_fastforward = (runloop_flags & RUNLOOP_FLAG_FASTMOTION) ? true : false;
bool is_slowmo = (runloop_flags & RUNLOOP_FLAG_SLOWMOTION) ? true : false;
bool is_rewind = state_manager_frame_is_reversed();
bool driver_active = mic_st->flags & MICROPHONE_DRIVER_FLAG_ACTIVE;
bool driver_active = (mic_st->flags & MICROPHONE_DRIVER_FLAG_ACTIVE) ? true : false;
/* If the provided arguments aren't valid... */
if (!frames || !microphone)
/* If the provided arguments aren't valid... */
return -1;
/* If the microphone or driver aren't active... */
if (!driver_active || !(microphone->flags & MICROPHONE_FLAG_ACTIVE))
/* If the microphone or driver aren't active... */
return -1;
/* If the driver is invalid or doesn't have the functions it needs... */
if (!driver || !driver->read || !driver->mic_alive)
/* If the driver is invalid or doesn't have the functions it needs... */
return -1;
/* If the core didn't actually ask for any frames... */
if (num_frames == 0)
/* If the core didn't actually ask for any frames... */
return 0;
if ((microphone->flags & MICROPHONE_FLAG_PENDING)
|| (microphone->flags & MICROPHONE_FLAG_SUSPENDED)
if ( (microphone->flags & MICROPHONE_FLAG_PENDING)
|| (microphone->flags & MICROPHONE_FLAG_SUSPENDED)
|| !(microphone->flags & MICROPHONE_FLAG_ENABLED)
|| is_fastforward
|| is_slowmo
@ -655,18 +648,19 @@ int microphone_driver_read(retro_microphone_t *microphone, int16_t* frames, size
* Because I couldn't think of anything useful for the mic to do.
* If you can, send a PR! */
/* If the driver or microphone's state haven't been allocated... */
if (!mic_st->driver_context || !microphone->microphone_context)
/* If the driver or microphone's state haven't been allocated... */
return -1;
/* If the mic isn't active like it should be at this point... */
if (!driver->mic_alive(mic_st->driver_context, microphone->microphone_context))
{ /* If the mic isn't active like it should be at this point... */
{
RARCH_ERR("[Microphone]: Mic frontend has the mic enabled, but the backend has it disabled.\n");
return -1;
}
/* If the core asked for more frames than we can fit... */
if (num_frames > microphone->outgoing_samples->size)
/* If the core asked for more frames than we can fit... */
return -1;
retro_assert(mic_st->input_frames != NULL);
@ -674,9 +668,10 @@ int microphone_driver_read(retro_microphone_t *microphone, int16_t* frames, size
while (FIFO_READ_AVAIL(microphone->outgoing_samples) < num_frames * sizeof(int16_t))
{ /* Until we can give the core the frames it asked for... */
size_t frames_to_read = MIN(AUDIO_CHUNK_SIZE_NONBLOCKING, frames_remaining);
size_t frames_read = 0;
size_t frames_read = 0;
/* If the game is running and the mic driver is active... */
if (!core_paused)
/* If the game is running and the mic driver is active... */
frames_read = microphone_driver_flush(mic_st, microphone, frames_to_read);
/* Otherwise, advance the counters. We're not gonna get new data,
@ -690,16 +685,13 @@ int microphone_driver_read(retro_microphone_t *microphone, int16_t* frames, size
bool microphone_driver_get_effective_params(const retro_microphone_t *microphone, retro_microphone_params_t *params)
{
/* If the arguments are null... */
if (!microphone || !params)
/* If the arguments are null... */
return false;
/* If this isn't an opened microphone... */
if (!(microphone->flags & MICROPHONE_FLAG_ACTIVE))
/* If this isn't an opened microphone... */
return false;
*params = microphone->effective_params;
return true;
}
@ -742,8 +734,9 @@ retro_microphone_t *microphone_driver_open_mic(const retro_microphone_params_t *
return NULL;
}
/* If the core has requested a second microphone... */
if (mic_st->microphone.flags & MICROPHONE_FLAG_ACTIVE)
{ /* If the core has requested a second microphone... */
{
RARCH_ERR("[Microphone]: Failed to open a second microphone, frontend only supports one at a time right now.\n");
if (mic_st->microphone.flags & MICROPHONE_FLAG_PENDING)
/* If that mic is pending... */
@ -763,7 +756,8 @@ retro_microphone_t *microphone_driver_open_mic(const retro_microphone_params_t *
/* If driver_context is NULL, the handle won't have a valid microphone context (but we'll create one later) */
if (driver_context)
{ /* If the microphone driver is ready to open a microphone... */
{
/* If the microphone driver is ready to open a microphone... */
if (mic_driver_open_mic_internal(&mic_st->microphone)) /* If the microphone was successfully initialized... */
RARCH_LOG("[Microphone]: Opened the requested microphone successfully.\n");
else
@ -787,7 +781,7 @@ static bool microphone_driver_free_devices_list(void)
{
microphone_driver_state_t *mic_st = &mic_driver_st;
if (
!mic_st->driver
!mic_st->driver
|| !mic_st->driver->device_list_free
|| !mic_st->driver_context
|| !mic_st->devices_list)
@ -816,32 +810,32 @@ bool microphone_driver_deinit(bool is_reset)
if (mic_st->input_frames)
memalign_free(mic_st->input_frames);
mic_st->input_frames = NULL;
mic_st->input_frames = NULL;
mic_st->input_frames_length = 0;
if (mic_st->converted_input_frames)
memalign_free(mic_st->converted_input_frames);
mic_st->converted_input_frames = NULL;
mic_st->converted_input_frames = NULL;
mic_st->converted_input_frames_length = 0;
if (mic_st->dual_mono_frames)
memalign_free(mic_st->dual_mono_frames);
mic_st->dual_mono_frames = NULL;
mic_st->dual_mono_frames = NULL;
mic_st->dual_mono_frames_length = 0;
if (mic_st->resampled_frames)
memalign_free(mic_st->resampled_frames);
mic_st->resampled_frames = NULL;
mic_st->resampled_frames = NULL;
mic_st->resampled_frames_length = 0;
if (mic_st->resampled_mono_frames)
memalign_free(mic_st->resampled_mono_frames);
mic_st->resampled_mono_frames = NULL;
mic_st->resampled_mono_frames = NULL;
mic_st->resampled_mono_frames_length = 0;
if (mic_st->final_frames)
memalign_free(mic_st->final_frames);
mic_st->final_frames = NULL;
mic_st->final_frames = NULL;
mic_st->final_frames_length = 0;
mic_st->resampler_quality = RESAMPLER_QUALITY_DONTCARE;
@ -858,4 +852,4 @@ bool microphone_driver_get_devices_list(void **data)
return false;
*ptr = mic_driver_st.devices_list;
return true;
}
}

View File

@ -20,8 +20,8 @@
#include <lists/string_list.h>
#include <retro_common_api.h>
#include <libretro.h>
#include "audio/audio_resampler.h"
#include "queues/fifo_queue.h"
#include <audio/audio_resampler.h>
#include <queues/fifo_queue.h>
/**
* Flags that indicate the current state of the microphone driver.
@ -664,4 +664,4 @@ bool microphone_driver_find_driver(
bool microphone_driver_get_devices_list(void **ptr);
#endif /* RETROARCH_MICROPHONE_DRIVER_H */
#endif /* RETROARCH_MICROPHONE_DRIVER_H */

View File

@ -52,8 +52,8 @@ void _init_vita_heap(void) {
if (sceKernelCreateLwMutex((struct SceKernelLwMutexWork*)_newlib_sbrk_mutex, "sbrk mutex", 0, 0, 0) < 0) {
goto failure;
}
// Always allocating the max avaliable USER_RW mem on the system
// Always allocating the max available USER_RW mem on the system
SceKernelFreeMemorySizeInfo info;
info.size = sizeof(SceKernelFreeMemorySizeInfo);
sceKernelGetFreeMemorySize(&info);

View File

@ -67,7 +67,7 @@ typedef struct video4linux
uint32_t *buffer_output;
bool ready;
char dev_name[255];
char dev_name[NAME_MAX_LENGTH];
} video4linux_t;
static int xioctl(int fd, unsigned long request, void *args)

View File

@ -88,7 +88,7 @@ void cheat_manager_apply_cheats(void)
for (i = 0; i < cheat_st->size; i++)
{
if ( cheat_st->cheats[i].state
if ( cheat_st->cheats[i].state
&& cheat_st->cheats[i].handler == CHEAT_HANDLER_TYPE_EMU)
{
retro_ctx_cheat_info_t cheat_info;
@ -183,22 +183,16 @@ bool cheat_manager_save(
if (!(conf = config_file_new_alloc()))
return false;
conf->guaranteed_no_duplicates = true;
conf->flags |= CONF_FILE_FLG_GUARANTEED_NO_DUPLICATES;
config_set_int(conf, "cheats", cheat_st->size);
for (i = 0; i < cheat_st->size; i++)
{
size_t _len;
unsigned j;
char formatted_number[12];
char var_key[128];
char key[256];
formatted_number[0] = '\0';
snprintf(formatted_number, sizeof(formatted_number), "cheat%u_", i);
_len = strlcpy(var_key, formatted_number, sizeof(var_key));
char var_key[128];
size_t _len = snprintf(var_key, sizeof(var_key), "cheat%u_", i);
strlcpy(var_key + _len, "desc", sizeof(var_key) - _len);
if (!string_is_empty(cheat_st->cheats[i].desc))
@ -211,8 +205,8 @@ bool cheat_manager_save(
strlcpy(var_key + _len, "enable", sizeof(var_key) - _len);
config_set_string(conf, var_key,
cheat_st->cheats[i].state
? "true"
cheat_st->cheats[i].state
? "true"
: "false");
strlcpy(var_key + _len, "big_endian", sizeof(var_key) - _len);
@ -531,7 +525,7 @@ bool cheat_manager_load(const char *path, bool append)
}
cheat_st->loading_cheat_offset = orig_size;
cb.config_file_new_entry_cb =
cb.config_file_new_entry_cb =
cheat_manager_load_cb_second_pass;
conf = config_file_new_with_callback(path, &cb);
@ -619,11 +613,11 @@ void cheat_manager_update(cheat_manager_t *handle, unsigned handle_idx)
snprintf(msg, sizeof(msg),
"Cheat: #%u [%s]: %s",
handle_idx,
handle->cheats[handle_idx].state
? msg_hash_to_str(MENU_ENUM_LABEL_ON)
handle->cheats[handle_idx].state
? msg_hash_to_str(MENU_ENUM_LABEL_ON)
: msg_hash_to_str(MENU_ENUM_LABEL_OFF),
handle->cheats[handle_idx].desc
? (handle->cheats[handle_idx].desc)
handle->cheats[handle_idx].desc
? (handle->cheats[handle_idx].desc)
: (handle->cheats[handle_idx].code)
);
runloop_msg_queue_push(msg, 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
@ -813,7 +807,7 @@ int cheat_manager_initialize_memory(rarch_setting_t *setting, size_t idx, bool w
{
for (i = 0; i < sys_info->mmaps.num_descriptors; i++)
{
if ((sys_info->mmaps.descriptors[i].core.flags
if ((sys_info->mmaps.descriptors[i].core.flags
& RETRO_MEMDESC_SYSTEM_RAM) != 0
&& sys_info->mmaps.descriptors[i].core.ptr
&& sys_info->mmaps.descriptors[i].core.len > 0)
@ -1222,7 +1216,6 @@ int cheat_manager_add_matches(const char *path,
unsigned int bytes_per_item = 1;
unsigned int bits = 8;
unsigned int curr_val = 0;
unsigned int num_added = 0;
unsigned int offset = 0;
cheat_manager_t *cheat_st = &cheat_manager_state;
unsigned char *curr = cheat_st->curr_memory_buf;
@ -1273,7 +1266,6 @@ int cheat_manager_add_matches(const char *path,
runloop_msg_queue_push(msg_hash_to_str(MSG_CHEAT_SEARCH_ADDED_MATCHES_FAIL), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
return 0;
}
num_added++;
}
}
else
@ -1287,7 +1279,6 @@ int cheat_manager_add_matches(const char *path,
runloop_msg_queue_push(msg_hash_to_str(MSG_CHEAT_SEARCH_ADDED_MATCHES_FAIL), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
return 0;
}
num_added++;
}
}

View File

@ -87,8 +87,8 @@ enum cheat_rumble_type
struct item_cheat
{
/* Clock value for when rumbling should stop */
retro_time_t rumble_primary_end_time;
retro_time_t rumble_secondary_end_time;
retro_time_t rumble_primary_end_time;
retro_time_t rumble_secondary_end_time;
char *desc;
char *code;
@ -128,7 +128,7 @@ struct item_cheat
unsigned int rumble_prev_value;
unsigned int rumble_initialized;
/* 0-15 for specific port, anything else means "all ports" */
unsigned int rumble_port;
unsigned int rumble_port;
unsigned int rumble_primary_strength; /* 0-65535 */
unsigned int rumble_primary_duration; /* in milliseconds */
unsigned int rumble_secondary_strength; /* 0-65535 */
@ -141,7 +141,7 @@ struct item_cheat
* repeat_add_to_address - every iteration of repeat_count will have this amount added to item_cheat.address
*
* Note that repeat_add_to_address represents the number of "memory_search_size" blocks to add to
* item_cheat.address. If memory_seach_size is 16-bits and repeat_add_to_address is 2, then item_cheat.address
* item_cheat.address. If memory_search_size is 16-bits and repeat_add_to_address is 2, then item_cheat.address
* will be increased by 4 bytes 2*(16-bits) for every iteration.
*
* This is a cheating structure used for codes like unlocking all levels, giving yourself 1 of every item,etc.

File diff suppressed because it is too large Load Diff

View File

@ -35,6 +35,7 @@ bool rcheevos_set_serialized_data(void* buffer);
bool rcheevos_unload(void);
void rcheevos_test(void);
void rcheevos_idle(void);
void rcheevos_reset_game(bool widgets_ready);
void rcheevos_refresh_memory(void);
@ -44,6 +45,9 @@ void rcheevos_hardcore_enabled_changed(void);
void rcheevos_toggle_hardcore_paused(void);
bool rcheevos_hardcore_active(void);
bool rcheevos_is_pause_allowed(void);
void rcheevos_spectating_changed(void);
void rcheevos_validate_config_settings(void);
void rcheevos_leaderboard_trackers_visibility_changed(void);
@ -53,7 +57,8 @@ bool rcheevos_get_support_cheevos(void);
const char* rcheevos_get_hash(void);
int rcheevos_get_richpresence(char *s, size_t len);
uintptr_t rcheevos_get_badge_texture(const char *badge, bool locked);
int rcheevos_get_game_badge_url(char *s, size_t len);
uintptr_t rcheevos_get_badge_texture(const char* badge, bool locked, bool download_if_missing);
uint8_t* rcheevos_patch_address(unsigned address);

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2019-2021 - Brian Weiss
* Copyright (C) 2019-2023 - Brian Weiss
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
@ -20,28 +20,16 @@
RETRO_BEGIN_DECLS
typedef void (*rcheevos_client_callback)(void* userdata);
void rcheevos_client_download_placeholder_badge(void);
void rcheevos_client_download_game_badge(const rc_client_game_t* game);
void rcheevos_client_download_achievement_badges(rc_client_t* client);
void rcheevos_client_download_achievement_badge(const char* badge_name, bool locked);
void rcheevos_client_download_badge_from_url(const char* url, const char* badge_name);
void rcheevos_client_initialize(void);
void rcheevos_client_login_with_password(const char* username, const char* password,
rcheevos_client_callback callback, void* userdata);
void rcheevos_client_login_with_token(const char* username, const char* token,
rcheevos_client_callback callback, void* userdata);
void rcheevos_client_identify_game(const char* hash, rcheevos_client_callback callback, void* userdata);
void rcheevos_client_initialize_runtime(unsigned game_id, rcheevos_client_callback callback, void* userdata);
void rcheevos_client_start_session(unsigned game_id);
void rcheevos_client_award_achievement(unsigned achievement_id);
void rcheevos_client_submit_lboard_entry(unsigned leaderboard_id, int value);
void rcheevos_client_fetch_badges(rcheevos_client_callback callback, void* userdata);
void rcheevos_log_url(const char* api, const char* url);
void rcheevos_get_user_agent(rcheevos_locals_t *locals, char *buffer, size_t len);
void rcheevos_client_server_call(const rc_api_request_t* request,
rc_client_server_callback_t callback, void* callback_data, rc_client_t* client);
void rcheevos_get_user_agent(rcheevos_locals_t* locals, char* buffer, size_t len);
RETRO_END_DECLS

View File

@ -1,6 +1,6 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2015-2018 - Andre Leiradella
* Copyright (C) 2019-2021 - Brian Weiss
* Copyright (C) 2019-2023 - Brian Weiss
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
@ -17,8 +17,9 @@
#ifndef __RARCH_CHEEVOS_LOCALS_H
#define __RARCH_CHEEVOS_LOCALS_H
#include "../deps/rcheevos/include/rc_client.h"
#include "../deps/rcheevos/include/rc_runtime.h"
#include "../deps/rcheevos/src/rcheevos/rc_libretro.h"
#include "../deps/rcheevos/src/rc_libretro.h"
#include <boolean.h>
#include <queues/task_queue.h>
@ -57,66 +58,6 @@ RETRO_BEGIN_DECLS
* State *
************************************************************************/
enum
{
RCHEEVOS_ACTIVE_SOFTCORE = 1 << 0,
RCHEEVOS_ACTIVE_HARDCORE = 1 << 1,
RCHEEVOS_ACTIVE_UNOFFICIAL = 1 << 2,
RCHEEVOS_ACTIVE_UNSUPPORTED = 1 << 3
};
typedef struct rcheevos_racheevo_t
{
const char* title;
const char* description;
const char* badge;
const char* memaddr;
unsigned id;
unsigned points;
retro_time_t unlock_time;
uint8_t active;
#ifdef HAVE_MENU
uint8_t menu_bucket;
uint8_t menu_progress;
uint8_t menu_badge_grayscale;
uintptr_t menu_badge_texture;
#endif
} rcheevos_racheevo_t;
typedef struct rcheevos_ralboard_t
{
const char* title;
const char* description;
const char* mem;
unsigned id;
unsigned format;
#ifdef HAVE_GFX_WIDGETS
int value;
unsigned value_hash;
uint8_t active_tracker_id;
#endif
} rcheevos_ralboard_t;
enum rcheevos_load_state
{
RCHEEVOS_LOAD_STATE_NONE,
RCHEEVOS_LOAD_STATE_IDENTIFYING_GAME,
RCHEEVOS_LOAD_STATE_FETCHING_GAME_DATA,
RCHEEVOS_LOAD_STATE_STARTING_SESSION,
RCHEEVOS_LOAD_STATE_FETCHING_BADGES,
RCHEEVOS_LOAD_STATE_DONE,
RCHEEVOS_LOAD_STATE_UNKNOWN_GAME,
RCHEEVOS_LOAD_STATE_NETWORK_ERROR,
RCHEEVOS_LOAD_STATE_LOGIN_FAILED,
RCHEEVOS_LOAD_STATE_ABORTED
};
enum rcheevos_summary_notif
{
RCHEEVOS_SUMMARY_ALLGAMES = 0,
@ -125,40 +66,14 @@ enum rcheevos_summary_notif
RCHEEVOS_SUMMARY_LAST
};
typedef struct rcheevos_load_info_t
{
enum rcheevos_load_state state;
int hashes_tried;
int outstanding_requests;
#ifdef HAVE_THREADS
slock_t* request_lock;
#endif
} rcheevos_load_info_t;
typedef struct rcheevos_game_info_t
{
int id;
int console_id;
char* title;
char badge_name[16];
const char* hash;
bool mastery_placard_shown;
rc_libretro_hash_set_t hashes;
rcheevos_racheevo_t* achievements;
rcheevos_ralboard_t* leaderboards;
unsigned achievement_count;
unsigned leaderboard_count;
} rcheevos_game_info_t;
#ifdef HAVE_MENU
typedef struct rcheevos_menuitem_t
{
rcheevos_racheevo_t* cheevo;
rc_client_achievement_t* achievement;
uintptr_t menu_badge_texture;
uint32_t subset_id;
uint8_t menu_badge_grayscale;
enum msg_hash_enums state_label_idx;
} rcheevos_menuitem_t;
@ -166,17 +81,14 @@ typedef struct rcheevos_menuitem_t
typedef struct rcheevos_locals_t
{
rc_runtime_t runtime; /* rcheevos runtime state */
rcheevos_game_info_t game; /* information about the current game */
rc_client_t* client; /* rcheevos client state */
rc_libretro_memory_regions_t memory;/* achievement addresses to core memory mappings */
#ifdef HAVE_THREADS
enum event_command queued_command; /* action queued by background thread to be run on main thread */
bool game_placard_requested; /* request to display game placard */
#endif
char displayname[32]; /* name to display in messages */
char username[32]; /* case-corrected username */
char token[32]; /* user's session token */
char user_agent_prefix[128]; /* RetroArch/OS version information */
char user_agent_core[256]; /* RetroArch/OS/Core version information */
@ -186,28 +98,13 @@ typedef struct rcheevos_locals_t
unsigned menuitem_count; /* current number of items in the menuitems array */
#endif
#ifdef HAVE_GFX_WIDGETS
unsigned active_lboard_trackers; /* bit mask of active leaderboard tracker ids */
rcheevos_racheevo_t* tracker_achievement;
float tracker_progress;
#endif
bool hardcore_allowed; /* prevents enabling hardcore if illegal settings detected */
bool hardcore_being_enabled; /* allows callers to detect hardcore mode while it's being enabled */
rcheevos_load_info_t load_info; /* load info */
bool hardcore_active; /* hardcore functionality is active */
bool loaded; /* load task has completed */
#ifdef HAVE_GFX_WIDGETS
bool assign_new_trackers; /* a new leaderboard was started and needs a tracker assigned */
#endif
bool core_supports; /* false if core explicitly disables achievements */
} rcheevos_locals_t;
rcheevos_locals_t* get_rcheevos_locals(void);
void rcheevos_begin_load_state(enum rcheevos_load_state state);
int rcheevos_end_load_state(void);
bool rcheevos_load_aborted(void);
void rcheevos_show_mastery_placard(void);
RETRO_END_DECLS

View File

@ -1,5 +1,5 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2019-2021 - Brian Weiss
* Copyright (C) 2019-2023 - Brian Weiss
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
@ -13,121 +13,60 @@
* If not, see <http://www.gnu.org/licenses/>.
*/
#include <features/features_cpu.h>
#include <retro_assert.h>
#include "cheevos_locals.h"
#include "cheevos_client.h"
#include "../gfx/gfx_display.h"
#ifdef HAVE_MENU
#include "../file_path_special.h"
#include "cheevos.h"
#include "../deps/rcheevos/include/rc_runtime_types.h"
#include "../deps/rcheevos/include/rc_api_runtime.h"
#include "../deps/rcheevos/src/rc_client_internal.h"
#if HAVE_MENU
#include "../file_path_special.h"
#include "../menu/menu_driver.h"
#include "../menu/menu_entries.h"
#endif
#include <features/features_cpu.h>
#include <retro_assert.h>
enum rcheevos_menuitem_bucket
{
RCHEEVOS_MENUITEM_BUCKET_UNKNOWN = 0,
RCHEEVOS_MENUITEM_BUCKET_LOCKED,
RCHEEVOS_MENUITEM_BUCKET_UNLOCKED,
RCHEEVOS_MENUITEM_BUCKET_UNSUPPORTED,
RCHEEVOS_MENUITEM_BUCKET_UNOFFICIAL,
RCHEEVOS_MENUITEM_BUCKET_RECENTLY_UNLOCKED,
RCHEEVOS_MENUITEM_BUCKET_ACTIVE_CHALLENGE,
RCHEEVOS_MENUITEM_BUCKET_ALMOST_THERE
};
/* if menu_badge_grayscale is set to a value other than 1 or 0, it's a counter for the number of
* frames since the last time we checked for the file. When the counter reaches this value, we'll
* check for the file again. */
/* if menu_badge_grayscale is set to a value other than 1 or 0, it's a counter for the number of
* frames since the last time we checked for the file. When the counter reaches this value, we'll
* check for the file again. */
#define MENU_BADGE_RETRY_RELOAD_FRAMES 64
static void rcheevos_menu_update_bucket(rcheevos_racheevo_t* cheevo)
{
cheevo->menu_progress = 0;
#if HAVE_MENU
/* Non-active unsupported achievement */
if (cheevo->active & RCHEEVOS_ACTIVE_UNSUPPORTED)
cheevo->menu_bucket = RCHEEVOS_MENUITEM_BUCKET_UNSUPPORTED;
/* Non-active unlocked in hardcore achievement */
else if (!(cheevo->active & RCHEEVOS_ACTIVE_HARDCORE))
cheevo->menu_bucket = RCHEEVOS_MENUITEM_BUCKET_UNLOCKED;
else
{
rc_trigger_t* trigger;
const rcheevos_locals_t* rcheevos_locals = get_rcheevos_locals();
if (!rcheevos_locals->hardcore_active && !(cheevo->active & RCHEEVOS_ACTIVE_SOFTCORE))
{
/* Non-active unlocked in softcore achievement in softcore mode */
cheevo->menu_bucket = RCHEEVOS_MENUITEM_BUCKET_UNLOCKED;
return;
}
/* Active achievement */
if (cheevo->active & RCHEEVOS_ACTIVE_UNOFFICIAL)
cheevo->menu_bucket = RCHEEVOS_MENUITEM_BUCKET_UNOFFICIAL;
else
cheevo->menu_bucket = RCHEEVOS_MENUITEM_BUCKET_LOCKED;
trigger = rc_runtime_get_achievement(&rcheevos_locals->runtime, cheevo->id);
if (trigger)
{
if (trigger->measured_value && trigger->measured_target)
{
const unsigned long clamped_value = (unsigned long)
MIN(trigger->measured_value, trigger->measured_target);
cheevo->menu_progress =
(uint8_t)((clamped_value * 100) / trigger->measured_target);
}
if (trigger->state == RC_TRIGGER_STATE_PRIMED)
cheevo->menu_bucket = RCHEEVOS_MENUITEM_BUCKET_ACTIVE_CHALLENGE;
else if (cheevo->menu_progress >= 80)
cheevo->menu_bucket = RCHEEVOS_MENUITEM_BUCKET_ALMOST_THERE;
}
}
}
static void rcheevos_menu_update_buckets(void)
{
const rcheevos_locals_t *rcheevos_locals = get_rcheevos_locals();
rcheevos_racheevo_t *cheevo = rcheevos_locals->game.achievements;
rcheevos_racheevo_t *stop = cheevo +
rcheevos_locals->game.achievement_count;
while (cheevo < stop)
{
rcheevos_menu_update_bucket(cheevo);
++cheevo;
}
}
bool rcheevos_menu_get_state(unsigned menu_offset, char *buffer, size_t len)
bool rcheevos_menu_get_state(unsigned menu_offset, char* buffer, size_t buffer_size)
{
const rcheevos_locals_t* rcheevos_locals = get_rcheevos_locals();
if (menu_offset < rcheevos_locals->menuitem_count)
{
const rcheevos_menuitem_t* menuitem = &rcheevos_locals->menuitems[menu_offset];
const rcheevos_racheevo_t* cheevo = menuitem->cheevo;
const rc_client_achievement_t* cheevo = menuitem->achievement;
if (cheevo)
{
if (cheevo->menu_progress)
{
const int written = snprintf(buffer, len, "%s - ",
msg_hash_to_str(menuitem->state_label_idx));
if (len - written > 0)
rc_runtime_format_achievement_measured(&rcheevos_locals->runtime,
cheevo->id, buffer + written, len - written);
}
if (cheevo->state != RC_CLIENT_ACHIEVEMENT_STATE_ACTIVE)
strlcpy(buffer, msg_hash_to_str(menuitem->state_label_idx), buffer_size);
else
strlcpy(buffer, msg_hash_to_str(menuitem->state_label_idx), len);
{
const char* missable = cheevo->type == RC_CLIENT_ACHIEVEMENT_TYPE_MISSABLE ? "[m] " : "";
size_t _len = strlcpy(buffer, missable, buffer_size);
_len += strlcpy(buffer + _len, msg_hash_to_str(menuitem->state_label_idx), buffer_size - _len);
if (cheevo->measured_progress[0])
{
_len += strlcpy(buffer + _len, " - ", buffer_size - _len);
strlcpy(buffer + _len, cheevo->measured_progress, buffer_size - _len);
}
}
return true;
}
}
@ -138,15 +77,15 @@ bool rcheevos_menu_get_state(unsigned menu_offset, char *buffer, size_t len)
return false;
}
bool rcheevos_menu_get_sublabel(unsigned menu_offset, char *buffer, size_t len)
bool rcheevos_menu_get_sublabel(unsigned menu_offset, char* buffer, size_t buffer_size)
{
const rcheevos_locals_t* rcheevos_locals = get_rcheevos_locals();
if (menu_offset < rcheevos_locals->menuitem_count)
if (menu_offset < rcheevos_locals->menuitem_count && buffer)
{
const rcheevos_racheevo_t* cheevo = rcheevos_locals->menuitems[menu_offset].cheevo;
if (cheevo && buffer)
const rcheevos_menuitem_t* menuitem = &rcheevos_locals->menuitems[menu_offset];
if (menuitem->achievement)
{
strlcpy(buffer, cheevo->description, len);
strlcpy(buffer, menuitem->achievement->description, buffer_size);
return true;
}
}
@ -160,23 +99,23 @@ bool rcheevos_menu_get_sublabel(unsigned menu_offset, char *buffer, size_t len)
void rcheevos_menu_reset_badges(void)
{
const rcheevos_locals_t* rcheevos_locals = get_rcheevos_locals();
rcheevos_racheevo_t* cheevo = rcheevos_locals->game.achievements;
rcheevos_racheevo_t* stop = cheevo + rcheevos_locals->game.achievement_count;
rcheevos_menuitem_t* menuitem = rcheevos_locals->menuitems;
rcheevos_menuitem_t* stop = menuitem + rcheevos_locals->menuitem_count;
while (cheevo < stop)
while (menuitem < stop)
{
if (cheevo->menu_badge_texture)
if (menuitem->menu_badge_texture)
{
video_driver_texture_unload(&cheevo->menu_badge_texture);
cheevo->menu_badge_texture = 0;
cheevo->menu_badge_grayscale = MENU_BADGE_RETRY_RELOAD_FRAMES;
video_driver_texture_unload(&menuitem->menu_badge_texture);
menuitem->menu_badge_texture = 0;
menuitem->menu_badge_grayscale = MENU_BADGE_RETRY_RELOAD_FRAMES;
}
++cheevo;
++menuitem;
}
}
static rcheevos_menuitem_t* rcheevos_menu_allocate(
rcheevos_locals_t* rcheevos_locals, rcheevos_racheevo_t* cheevo)
rcheevos_locals_t* rcheevos_locals)
{
rcheevos_menuitem_t* menuitem;
@ -184,10 +123,10 @@ static rcheevos_menuitem_t* rcheevos_menu_allocate(
{
if (rcheevos_locals->menuitems)
{
rcheevos_menuitem_t *new_menuitems;
rcheevos_menuitem_t* new_menuitems;
rcheevos_locals->menuitem_capacity += 32;
new_menuitems = (rcheevos_menuitem_t*)realloc(rcheevos_locals->menuitems,
rcheevos_locals->menuitem_capacity * sizeof(rcheevos_menuitem_t));
rcheevos_locals->menuitem_capacity * sizeof(rcheevos_menuitem_t));
if (new_menuitems)
rcheevos_locals->menuitems = new_menuitems;
@ -195,7 +134,7 @@ static rcheevos_menuitem_t* rcheevos_menu_allocate(
{
/* realloc failed */
CHEEVOS_ERR(RCHEEVOS_TAG " could not allocate space for %u menu items\n",
rcheevos_locals->menuitem_capacity);
rcheevos_locals->menuitem_capacity);
rcheevos_locals->menuitem_capacity -= 32;
return NULL;
}
@ -204,13 +143,13 @@ static rcheevos_menuitem_t* rcheevos_menu_allocate(
{
rcheevos_locals->menuitem_capacity = 64;
rcheevos_locals->menuitems = (rcheevos_menuitem_t*)
malloc(rcheevos_locals->menuitem_capacity * sizeof(rcheevos_menuitem_t));
malloc(rcheevos_locals->menuitem_capacity * sizeof(rcheevos_menuitem_t));
if (!rcheevos_locals->menuitems)
{
/* malloc failed */
CHEEVOS_ERR(RCHEEVOS_TAG " could not allocate space for %u menu items\n",
rcheevos_locals->menuitem_capacity);
rcheevos_locals->menuitem_capacity);
rcheevos_locals->menuitem_capacity = 0;
return NULL;
}
@ -218,176 +157,94 @@ static rcheevos_menuitem_t* rcheevos_menu_allocate(
}
menuitem = &rcheevos_locals->menuitems[rcheevos_locals->menuitem_count++];
menuitem->cheevo = cheevo;
menuitem->state_label_idx = MSG_UNKNOWN;
memset(menuitem, 0, sizeof(*menuitem));
return menuitem;
}
static void rcheevos_menu_append_header(rcheevos_locals_t* rcheevos_locals,
enum msg_hash_enums label)
enum msg_hash_enums label, uint32_t subset_id)
{
rcheevos_menuitem_t* menuitem = rcheevos_menu_allocate(rcheevos_locals, NULL);
rcheevos_menuitem_t* menuitem = rcheevos_menu_allocate(rcheevos_locals);
if (menuitem)
{
menuitem->state_label_idx = label;
menuitem->subset_id = subset_id;
}
}
static void rcheevos_menu_update_badge(rcheevos_racheevo_t* cheevo)
static void rcheevos_menu_update_badge(rcheevos_menuitem_t* menuitem, bool download_if_missing)
{
const char* badge_name = "00000";
bool badge_grayscale = false;
switch (cheevo->menu_bucket)
if (menuitem->achievement)
badge_name = menuitem->achievement->badge_name;
switch (menuitem->state_label_idx)
{
case RCHEEVOS_MENUITEM_BUCKET_LOCKED:
case RCHEEVOS_MENUITEM_BUCKET_UNOFFICIAL:
case RCHEEVOS_MENUITEM_BUCKET_UNSUPPORTED:
case RCHEEVOS_MENUITEM_BUCKET_ALMOST_THERE:
case RCHEEVOS_MENUITEM_BUCKET_ACTIVE_CHALLENGE:
badge_grayscale = true;
break;
default:
break;
case MENU_ENUM_LABEL_VALUE_CHEEVOS_LOCKED_ENTRY:
case MENU_ENUM_LABEL_VALUE_CHEEVOS_UNOFFICIAL_ENTRY:
case MENU_ENUM_LABEL_VALUE_CHEEVOS_UNSUPPORTED_ENTRY:
case MENU_ENUM_LABEL_VALUE_CHEEVOS_ALMOST_THERE_ENTRY:
case MENU_ENUM_LABEL_VALUE_CHEEVOS_ACTIVE_CHALLENGES_ENTRY:
badge_grayscale = true;
break;
default:
badge_grayscale = false;
break;
}
if (!cheevo->menu_badge_texture || cheevo->menu_badge_grayscale != badge_grayscale)
if (!menuitem->menu_badge_texture || menuitem->menu_badge_grayscale != badge_grayscale)
{
uintptr_t new_badge_texture =
rcheevos_get_badge_texture(cheevo->badge, badge_grayscale);
rcheevos_get_badge_texture(badge_name, badge_grayscale, download_if_missing);
if (new_badge_texture)
{
if (cheevo->menu_badge_texture)
video_driver_texture_unload(&cheevo->menu_badge_texture);
if (menuitem->menu_badge_texture)
video_driver_texture_unload(&menuitem->menu_badge_texture);
cheevo->menu_badge_texture = new_badge_texture;
cheevo->menu_badge_grayscale = badge_grayscale;
menuitem->menu_badge_texture = new_badge_texture;
menuitem->menu_badge_grayscale = badge_grayscale;
}
/* menu_badge_grayscale is overloaded such
/* menu_badge_grayscale is overloaded such
* that any value greater than 1 indicates
* the server default image is being used */
else if (cheevo->menu_badge_grayscale < 2)
else if (menuitem->menu_badge_grayscale < 2)
{
if (cheevo->menu_badge_texture)
video_driver_texture_unload(&cheevo->menu_badge_texture);
if (menuitem->menu_badge_texture)
video_driver_texture_unload(&menuitem->menu_badge_texture);
/* requested badge is not available, check for server default */
cheevo->menu_badge_texture =
rcheevos_get_badge_texture("00000", false);
menuitem->menu_badge_texture =
rcheevos_get_badge_texture("00000", false, false);
if (cheevo->menu_badge_texture)
cheevo->menu_badge_grayscale = 2;
if (menuitem->menu_badge_texture)
menuitem->menu_badge_grayscale = 2;
}
}
}
static void rcheevos_menu_append_items(rcheevos_locals_t* rcheevos_locals,
enum rcheevos_menuitem_bucket bucket)
{
rcheevos_racheevo_t* cheevo = rcheevos_locals->game.achievements;
rcheevos_racheevo_t* stop = cheevo + rcheevos_locals->game.achievement_count;
const unsigned first_index = rcheevos_locals->menuitem_count;
while (cheevo < stop)
{
if (cheevo->menu_bucket == bucket)
{
rcheevos_menuitem_t* menuitem = rcheevos_menu_allocate(rcheevos_locals, cheevo);
if (!menuitem)
return;
switch (cheevo->menu_bucket)
{
case RCHEEVOS_MENUITEM_BUCKET_UNSUPPORTED:
menuitem->state_label_idx = MENU_ENUM_LABEL_VALUE_CHEEVOS_UNSUPPORTED_ENTRY;
break;
case RCHEEVOS_MENUITEM_BUCKET_RECENTLY_UNLOCKED:
{
/* insert the item such that the unlock times are descending */
unsigned entry_index = rcheevos_locals->menuitem_count - 1;
while (entry_index > first_index)
{
rcheevos_menuitem_t* prev_menuitem = menuitem - 1;
if (prev_menuitem->cheevo->unlock_time >= cheevo->unlock_time)
break;
memcpy(menuitem, prev_menuitem, sizeof(rcheevos_menuitem_t));
menuitem = prev_menuitem;
--entry_index;
}
menuitem->cheevo = cheevo;
}
/* fallthrough to RCHEEVOS_MENUITEM_BUCKET_UNLOCKED */
case RCHEEVOS_MENUITEM_BUCKET_UNLOCKED:
if (!(cheevo->active & RCHEEVOS_ACTIVE_HARDCORE))
menuitem->state_label_idx = MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ENTRY_HARDCORE;
else
menuitem->state_label_idx = MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ENTRY;
break;
case RCHEEVOS_MENUITEM_BUCKET_ALMOST_THERE:
{
/* insert the item such that the progresses are descending */
unsigned entry_index = rcheevos_locals->menuitem_count - 1;
while (entry_index > first_index)
{
rcheevos_menuitem_t* prev_menuitem = menuitem - 1;
if (prev_menuitem->cheevo->menu_progress >= cheevo->menu_progress)
break;
memcpy(menuitem, prev_menuitem, sizeof(rcheevos_menuitem_t));
menuitem = prev_menuitem;
--entry_index;
}
menuitem->cheevo = cheevo;
}
/* fallthrough to default */
default:
if (cheevo->active & RCHEEVOS_ACTIVE_UNOFFICIAL)
menuitem->state_label_idx = MENU_ENUM_LABEL_VALUE_CHEEVOS_UNOFFICIAL_ENTRY;
else if (!(cheevo->active & RCHEEVOS_ACTIVE_SOFTCORE))
menuitem->state_label_idx = MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ENTRY;
else
menuitem->state_label_idx = MENU_ENUM_LABEL_VALUE_CHEEVOS_LOCKED_ENTRY;
break;
}
if (cheevo->badge && cheevo->badge[0])
{
#ifndef HAVE_GFX_WIDGETS
const settings_t* settings = config_get_ptr();
if (settings && settings->bools.cheevos_badges_enable)
#endif
rcheevos_menu_update_badge(cheevo);
}
}
++cheevo;
}
}
uintptr_t rcheevos_menu_get_badge_texture(unsigned menu_offset)
{
const rcheevos_locals_t* rcheevos_locals = get_rcheevos_locals();
if (menu_offset < rcheevos_locals->menuitem_count)
{
rcheevos_racheevo_t* cheevo = rcheevos_locals->menuitems[menu_offset].cheevo;
if (cheevo)
{
/* if we're using the placeholder badge, check to see if the real badge
* has become available (do this roughly once a second) */
if (cheevo->menu_badge_grayscale >= 2)
{
if (++cheevo->menu_badge_grayscale >= MENU_BADGE_RETRY_RELOAD_FRAMES)
{
cheevo->menu_badge_grayscale = 2;
rcheevos_menu_update_badge(cheevo);
}
}
rcheevos_menuitem_t* menuitem = &rcheevos_locals->menuitems[menu_offset];
return cheevo->menu_badge_texture;
/* if we're using the placeholder badge, check to see if the real badge
* has become available (do this roughly once a second) */
if (menuitem->menu_badge_grayscale >= 2)
{
if (++menuitem->menu_badge_grayscale >= MENU_BADGE_RETRY_RELOAD_FRAMES)
{
menuitem->menu_badge_grayscale = 2;
rcheevos_menu_update_badge(menuitem, false);
}
}
return menuitem->menu_badge_texture;
}
return 0;
@ -400,218 +257,185 @@ void rcheevos_menu_populate_hardcore_pause_submenu(void* data)
const settings_t* settings = config_get_ptr();
const bool cheevos_hardcore_mode_enable = settings->bools.cheevos_hardcore_mode_enable;
if (cheevos_hardcore_mode_enable && rcheevos_locals->loaded)
if (cheevos_hardcore_mode_enable && rc_client_get_game_info(rcheevos_locals->client))
{
if (rcheevos_locals->hardcore_active)
if (rc_client_get_hardcore_enabled(rcheevos_locals->client))
{
menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_PAUSE_CANCEL),
msg_hash_to_str(MENU_ENUM_LABEL_ACHIEVEMENT_PAUSE_CANCEL),
MENU_ENUM_LABEL_ACHIEVEMENT_PAUSE_CANCEL,
MENU_SETTING_ACTION_CLOSE, 0, 0, NULL);
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_PAUSE_CANCEL),
msg_hash_to_str(MENU_ENUM_LABEL_ACHIEVEMENT_PAUSE_CANCEL),
MENU_ENUM_LABEL_ACHIEVEMENT_PAUSE_CANCEL,
MENU_SETTING_ACTION_CLOSE, 0, 0, NULL);
menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_PAUSE),
msg_hash_to_str(MENU_ENUM_LABEL_ACHIEVEMENT_PAUSE),
MENU_ENUM_LABEL_ACHIEVEMENT_PAUSE,
MENU_SETTING_ACTION_PAUSE_ACHIEVEMENTS, 0, 0, NULL);
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_PAUSE),
msg_hash_to_str(MENU_ENUM_LABEL_ACHIEVEMENT_PAUSE),
MENU_ENUM_LABEL_ACHIEVEMENT_PAUSE,
MENU_SETTING_ACTION_PAUSE_ACHIEVEMENTS, 0, 0, NULL);
}
else
{
menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_RESUME_CANCEL),
msg_hash_to_str(MENU_ENUM_LABEL_ACHIEVEMENT_RESUME_CANCEL),
MENU_ENUM_LABEL_ACHIEVEMENT_RESUME_CANCEL,
MENU_SETTING_ACTION_CLOSE, 0, 0, NULL);
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_RESUME_CANCEL),
msg_hash_to_str(MENU_ENUM_LABEL_ACHIEVEMENT_RESUME_CANCEL),
MENU_ENUM_LABEL_ACHIEVEMENT_RESUME_CANCEL,
MENU_SETTING_ACTION_CLOSE, 0, 0, NULL);
menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_RESUME),
msg_hash_to_str(MENU_ENUM_LABEL_ACHIEVEMENT_RESUME),
MENU_ENUM_LABEL_ACHIEVEMENT_RESUME,
MENU_SETTING_ACTION_RESUME_ACHIEVEMENTS, 0, 0, NULL);
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_RESUME),
msg_hash_to_str(MENU_ENUM_LABEL_ACHIEVEMENT_RESUME),
MENU_ENUM_LABEL_ACHIEVEMENT_RESUME,
MENU_SETTING_ACTION_RESUME_ACHIEVEMENTS, 0, 0, NULL);
}
}
}
void rcheevos_menu_populate(void* data)
{
menu_displaylist_info_t* info = (menu_displaylist_info_t*)data;
rcheevos_locals_t* rcheevos_locals = get_rcheevos_locals();
const settings_t* settings = config_get_ptr();
unsigned num_locked = 0;
unsigned num_unlocked = 0;
unsigned num_recently_unlocked = 0;
unsigned num_unsupported = 0;
unsigned num_active_challenges = 0;
unsigned num_almost_there = 0;
menu_displaylist_info_t* info = (menu_displaylist_info_t*)data;
rcheevos_locals_t* rcheevos_locals = get_rcheevos_locals();
const rc_client_game_t* game = rc_client_get_game_info(rcheevos_locals->client);
const settings_t* settings = config_get_ptr();
if (rcheevos_locals->loaded)
{
const retro_time_t now = cpu_features_get_time_usec();
const retro_time_t recent_unlock_time = now - (10 * 60 * 1000000); /* 10 minutes ago */
rcheevos_racheevo_t* cheevo = NULL;
rcheevos_racheevo_t* stop = NULL;
rc_client_achievement_list_t* list = rc_client_create_achievement_list(rcheevos_locals->client,
RC_CLIENT_ACHIEVEMENT_CATEGORY_CORE_AND_UNOFFICIAL,
RC_CLIENT_ACHIEVEMENT_LIST_GROUPING_PROGRESS);
uint32_t i, j;
/* first menu item is the Pause/Resume Hardcore option (unless hardcore is disabled) */
if (settings->bools.cheevos_enable && settings->bools.cheevos_hardcore_mode_enable)
{
if (rcheevos_locals->hardcore_active)
menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_PAUSE),
msg_hash_to_str(MENU_ENUM_LABEL_ACHIEVEMENT_PAUSE_MENU),
MENU_ENUM_LABEL_ACHIEVEMENT_PAUSE_MENU,
MENU_SETTING_ACTION_PAUSE_ACHIEVEMENTS, 0, 0, NULL);
else
menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_RESUME),
msg_hash_to_str(MENU_ENUM_LABEL_ACHIEVEMENT_PAUSE_MENU),
MENU_ENUM_LABEL_ACHIEVEMENT_PAUSE_MENU,
MENU_SETTING_ACTION_RESUME_ACHIEVEMENTS, 0, 0, NULL);
}
/* update the bucket for each achievement */
rcheevos_menu_update_buckets();
/* count items in each bucket */
cheevo = rcheevos_locals->game.achievements;
stop = cheevo + rcheevos_locals->game.achievement_count;
while (cheevo < stop)
{
switch (cheevo->menu_bucket)
{
case RCHEEVOS_MENUITEM_BUCKET_UNLOCKED:
if (cheevo->unlock_time && cheevo->unlock_time >= recent_unlock_time)
{
cheevo->menu_bucket = RCHEEVOS_MENUITEM_BUCKET_RECENTLY_UNLOCKED;
++num_recently_unlocked;
}
else
++num_unlocked;
break;
case RCHEEVOS_MENUITEM_BUCKET_LOCKED:
case RCHEEVOS_MENUITEM_BUCKET_UNOFFICIAL:
++num_locked;
break;
case RCHEEVOS_MENUITEM_BUCKET_UNSUPPORTED:
++num_unsupported;
break;
case RCHEEVOS_MENUITEM_BUCKET_ACTIVE_CHALLENGE:
++num_active_challenges;
break;
case RCHEEVOS_MENUITEM_BUCKET_ALMOST_THERE:
++num_almost_there;
break;
}
++cheevo;
}
if (!rcheevos_locals->menuitems)
{
/* reserve space for all achievements and up to 6 headers before we need to realloc */
rcheevos_locals->menuitem_capacity = rcheevos_locals->game.achievement_count + 6;
rcheevos_locals->menuitems = (rcheevos_menuitem_t*)
malloc(rcheevos_locals->menuitem_capacity * sizeof(rcheevos_menuitem_t));
if (!rcheevos_locals->menuitems)
rcheevos_locals->menuitem_capacity = 0;
}
}
/* reset menu */
rcheevos_menu_reset_badges();
rcheevos_locals->menuitem_count = 0;
/* active challenges */
if (num_active_challenges)
if (rcheevos_locals->client->state.disconnect)
{
rcheevos_menu_append_header(rcheevos_locals,
MENU_ENUM_LABEL_VALUE_CHEEVOS_ACTIVE_CHALLENGES_ENTRY);
rcheevos_menu_append_items(rcheevos_locals,
RCHEEVOS_MENUITEM_BUCKET_ACTIVE_CHALLENGE);
menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_SERVER_UNREACHABLE),
msg_hash_to_str(MENU_ENUM_SUBLABEL_ACHIEVEMENT_SERVER_UNREACHABLE),
MENU_ENUM_LABEL_ACHIEVEMENT_SERVER_UNREACHABLE,
MENU_INFO_ACHIEVEMENTS_SERVER_UNREACHABLE, 0, 0, NULL);
}
/* recently unlocked */
if (num_recently_unlocked)
if (game && game->id != 0)
{
rcheevos_menu_append_header(rcheevos_locals,
MENU_ENUM_LABEL_VALUE_CHEEVOS_RECENTLY_UNLOCKED_ENTRY);
rcheevos_menu_append_items(rcheevos_locals,
RCHEEVOS_MENUITEM_BUCKET_RECENTLY_UNLOCKED);
/* first menu item is the Pause/Resume Hardcore option (unless hardcore is completely disabled) */
if (settings->bools.cheevos_enable && settings->bools.cheevos_hardcore_mode_enable)
{
if (rc_client_get_hardcore_enabled(rcheevos_locals->client))
menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_PAUSE),
msg_hash_to_str(MENU_ENUM_LABEL_ACHIEVEMENT_PAUSE_MENU),
MENU_ENUM_LABEL_ACHIEVEMENT_PAUSE_MENU,
MENU_SETTING_ACTION_PAUSE_ACHIEVEMENTS, 0, 0, NULL);
else
menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_RESUME),
msg_hash_to_str(MENU_ENUM_LABEL_ACHIEVEMENT_PAUSE_MENU),
MENU_ENUM_LABEL_ACHIEVEMENT_PAUSE_MENU,
MENU_SETTING_ACTION_RESUME_ACHIEVEMENTS, 0, 0, NULL);
}
}
/* almost there */
if (num_almost_there)
for (i = 0; i < list->num_buckets; i++)
{
rcheevos_menu_append_header(rcheevos_locals,
MENU_ENUM_LABEL_VALUE_CHEEVOS_ALMOST_THERE_ENTRY);
if (list->num_buckets > 1)
{
enum msg_hash_enums label;
switch (list->buckets[i].bucket_type)
{
case RC_CLIENT_ACHIEVEMENT_BUCKET_LOCKED:
label = MENU_ENUM_LABEL_VALUE_CHEEVOS_LOCKED_ENTRY;
break;
case RC_CLIENT_ACHIEVEMENT_BUCKET_UNLOCKED:
label = MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ENTRY;
break;
case RC_CLIENT_ACHIEVEMENT_BUCKET_UNSUPPORTED:
label = MENU_ENUM_LABEL_VALUE_CHEEVOS_UNSUPPORTED_ENTRY;
break;
case RC_CLIENT_ACHIEVEMENT_BUCKET_UNOFFICIAL:
label = MENU_ENUM_LABEL_VALUE_CHEEVOS_UNOFFICIAL_ENTRY;
break;
case RC_CLIENT_ACHIEVEMENT_BUCKET_RECENTLY_UNLOCKED:
label = MENU_ENUM_LABEL_VALUE_CHEEVOS_RECENTLY_UNLOCKED_ENTRY;
break;
case RC_CLIENT_ACHIEVEMENT_BUCKET_ACTIVE_CHALLENGE:
label = MENU_ENUM_LABEL_VALUE_CHEEVOS_ACTIVE_CHALLENGES_ENTRY;
break;
case RC_CLIENT_ACHIEVEMENT_BUCKET_ALMOST_THERE:
label = MENU_ENUM_LABEL_VALUE_CHEEVOS_ALMOST_THERE_ENTRY;
break;
default:
continue;
}
rcheevos_menu_append_header(rcheevos_locals, label, list->buckets[i].subset_id);
}
rcheevos_menu_append_items(rcheevos_locals,
RCHEEVOS_MENUITEM_BUCKET_ALMOST_THERE);
for (j = 0; j < list->buckets[i].num_achievements; j++)
{
rcheevos_menuitem_t* menuitem = rcheevos_menu_allocate(rcheevos_locals);
if (!menuitem)
break;
menuitem->achievement = list->buckets[i].achievements[j];
switch (list->buckets[i].bucket_type)
{
case RC_CLIENT_ACHIEVEMENT_BUCKET_RECENTLY_UNLOCKED:
case RC_CLIENT_ACHIEVEMENT_BUCKET_UNLOCKED:
if (menuitem->achievement->unlocked & RC_CLIENT_ACHIEVEMENT_UNLOCKED_HARDCORE)
menuitem->state_label_idx = MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ENTRY_HARDCORE;
else
menuitem->state_label_idx = MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ENTRY;
break;
case RC_CLIENT_ACHIEVEMENT_BUCKET_UNSUPPORTED:
menuitem->state_label_idx = MENU_ENUM_LABEL_VALUE_CHEEVOS_UNSUPPORTED_ENTRY;
break;
case RC_CLIENT_ACHIEVEMENT_BUCKET_UNOFFICIAL:
menuitem->state_label_idx = MENU_ENUM_LABEL_VALUE_CHEEVOS_UNOFFICIAL_ENTRY;
break;
default:
menuitem->state_label_idx = MENU_ENUM_LABEL_VALUE_CHEEVOS_LOCKED_ENTRY;
break;
}
rcheevos_menu_update_badge(menuitem, true);
}
}
/* locked */
if (num_locked)
{
if (rcheevos_locals->menuitem_count > 0)
rcheevos_menu_append_header(rcheevos_locals,
MENU_ENUM_LABEL_VALUE_CHEEVOS_LOCKED_ENTRY);
rcheevos_menu_append_items(rcheevos_locals,
RCHEEVOS_MENUITEM_BUCKET_LOCKED);
rcheevos_menu_append_items(rcheevos_locals,
RCHEEVOS_MENUITEM_BUCKET_UNOFFICIAL);
}
/* unsupported */
if (num_unsupported)
{
if (rcheevos_locals->menuitem_count > 0)
rcheevos_menu_append_header(rcheevos_locals,
MENU_ENUM_LABEL_VALUE_CHEEVOS_UNSUPPORTED_ENTRY);
rcheevos_menu_append_items(rcheevos_locals,
RCHEEVOS_MENUITEM_BUCKET_UNSUPPORTED);
}
/* unlocked */
if (num_unlocked)
{
if (rcheevos_locals->menuitem_count > 0)
rcheevos_menu_append_header(rcheevos_locals,
MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ENTRY);
rcheevos_menu_append_items(rcheevos_locals,
RCHEEVOS_MENUITEM_BUCKET_UNLOCKED);
}
rc_client_destroy_achievement_list(list);
if (rcheevos_locals->menuitem_count > 0)
{
char buffer[128];
unsigned idx = 0;
unsigned idx = 0;
/* convert to menu entries */
rcheevos_menuitem_t* menuitem = rcheevos_locals->menuitems;
rcheevos_menuitem_t* stop = menuitem +
rcheevos_menuitem_t* stop = menuitem +
rcheevos_locals->menuitem_count;
do
{
if (menuitem->cheevo)
menu_entries_append(info->list, menuitem->cheevo->title,
menuitem->cheevo->description,
MENU_ENUM_LABEL_CHEEVOS_LOCKED_ENTRY,
MENU_SETTINGS_CHEEVOS_START + idx, 0, 0, NULL);
if (menuitem->achievement)
{
menu_entries_append(info->list, menuitem->achievement->title,
menuitem->achievement->description,
MENU_ENUM_LABEL_CHEEVOS_LOCKED_ENTRY,
MENU_SETTINGS_CHEEVOS_START + idx, 0, 0, NULL);
}
else
{
snprintf(buffer, sizeof(buffer), "----- %s -----",
if (menuitem->subset_id)
{
const rc_client_subset_t* subset =
rc_client_get_subset_info(rcheevos_locals->client, menuitem->subset_id);
snprintf(buffer, sizeof(buffer), "----- %s - %s -----",
subset ? subset->title : "Unknown Subset",
msg_hash_to_str(menuitem->state_label_idx));
}
else
snprintf(buffer, sizeof(buffer), "----- %s -----",
msg_hash_to_str(menuitem->state_label_idx));
menu_entries_append(info->list, buffer, "",
MENU_ENUM_LABEL_CHEEVOS_LOCKED_ENTRY,
MENU_SETTINGS_CHEEVOS_START + idx, 0, 0, NULL);
MENU_ENUM_LABEL_CHEEVOS_LOCKED_ENTRY,
MENU_SETTINGS_CHEEVOS_START + idx, 0, 0, NULL);
}
++idx;
@ -622,64 +446,133 @@ void rcheevos_menu_populate(void* data)
{
/* no achievements found */
if (!rcheevos_locals->core_supports)
{
menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CANNOT_ACTIVATE_ACHIEVEMENTS_WITH_THIS_CORE),
msg_hash_to_str(MENU_ENUM_LABEL_CANNOT_ACTIVATE_ACHIEVEMENTS_WITH_THIS_CORE),
MENU_ENUM_LABEL_CANNOT_ACTIVATE_ACHIEVEMENTS_WITH_THIS_CORE,
FILE_TYPE_NONE, 0, 0, NULL);
else if (rcheevos_locals->load_info.state == RCHEEVOS_LOAD_STATE_NETWORK_ERROR)
}
else if (!game)
{
int state = rc_client_get_load_game_state(rcheevos_locals->client);
enum msg_hash_enums msg = MENU_ENUM_LABEL_VALUE_UNKNOWN_GAME;
switch (state)
{
case RC_CLIENT_LOAD_GAME_STATE_IDENTIFYING_GAME:
msg = MENU_ENUM_LABEL_VALUE_CHEEVOS_IDENTIFYING_GAME;
break;
case RC_CLIENT_LOAD_GAME_STATE_AWAIT_LOGIN:
msg = MENU_ENUM_LABEL_VALUE_NOT_LOGGED_IN;
break;
case RC_CLIENT_LOAD_GAME_STATE_FETCHING_GAME_DATA:
msg = MENU_ENUM_LABEL_VALUE_CHEEVOS_FETCHING_GAME_DATA;
break;
case RC_CLIENT_LOAD_GAME_STATE_STARTING_SESSION:
msg = MENU_ENUM_LABEL_VALUE_CHEEVOS_STARTING_SESSION;
break;
case RC_CLIENT_LOAD_GAME_STATE_NONE:
if (!rc_client_get_user_info(rcheevos_locals->client))
msg = MENU_ENUM_LABEL_VALUE_NOT_LOGGED_IN;
break;
}
menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NETWORK_ERROR),
msg_hash_to_str(MENU_ENUM_LABEL_NETWORK_ERROR),
MENU_ENUM_LABEL_NETWORK_ERROR,
msg_hash_to_str(msg),
msg_hash_to_str(MENU_ENUM_LABEL_NO_ACHIEVEMENTS_TO_DISPLAY),
MENU_ENUM_LABEL_NO_ACHIEVEMENTS_TO_DISPLAY,
FILE_TYPE_NONE, 0, 0, NULL);
else if (!rcheevos_locals->game.id)
}
else if (!game->id)
{
char buffer[128];
snprintf(buffer, sizeof(buffer), "%s (%s)",
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_UNKNOWN_GAME), game->hash);
menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_UNKNOWN_GAME),
msg_hash_to_str(MENU_ENUM_LABEL_UNKNOWN_GAME),
MENU_ENUM_LABEL_UNKNOWN_GAME,
buffer,
msg_hash_to_str(MENU_ENUM_LABEL_NO_ACHIEVEMENTS_TO_DISPLAY),
MENU_ENUM_LABEL_NO_ACHIEVEMENTS_TO_DISPLAY,
FILE_TYPE_NONE, 0, 0, NULL);
else if (!rcheevos_locals->token[0])
}
else if (!rc_client_get_user_info(rcheevos_locals->client))
{
menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_LOGGED_IN),
msg_hash_to_str(MENU_ENUM_LABEL_NOT_LOGGED_IN),
MENU_ENUM_LABEL_NOT_LOGGED_IN,
FILE_TYPE_NONE, 0, 0, NULL);
}
else
{
menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_ACHIEVEMENTS_TO_DISPLAY),
msg_hash_to_str(MENU_ENUM_LABEL_NO_ACHIEVEMENTS_TO_DISPLAY),
MENU_ENUM_LABEL_NO_ACHIEVEMENTS_TO_DISPLAY,
FILE_TYPE_NONE, 0, 0, NULL);
}
}
}
#endif /* HAVE_MENU */
uintptr_t rcheevos_get_badge_texture(const char *badge, bool locked)
uintptr_t rcheevos_get_badge_texture(const char* badge, bool locked, bool download_if_missing)
{
if (badge)
size_t _len;
char badge_file[24];
char fullpath[PATH_MAX_LENGTH];
uintptr_t tex = 0;
if (!badge || !badge[0])
return 0;
#ifdef HAVE_THREADS
/* The OpenGL driver crashes if gfx_display_reset_textures_list is not called on the video thread.
* If threaded video is enabled, it'll automatically dispatch the request to the video thread.
* If threaded video is not enabled, just return null. The video thread should assume the image
* wasn't downloaded and check again in a few frames.
*/
if (!video_driver_is_threaded() && !task_is_on_main_thread())
return 0;
#endif
_len = strlcpy(badge_file, badge, sizeof(badge_file));
_len += strlcpy(badge_file + _len, locked ? "_lock" : "", sizeof(badge_file) - _len);
strlcpy(badge_file + _len, FILE_PATH_PNG_EXTENSION, sizeof(badge_file) - _len);
fill_pathname_application_special(fullpath, sizeof(fullpath),
APPLICATION_SPECIAL_DIRECTORY_THUMBNAILS_CHEEVOS_BADGES);
if (!gfx_display_reset_textures_list(badge_file, fullpath,
&tex, TEXTURE_FILTER_MIPMAP_LINEAR, NULL, NULL))
{
size_t _len;
char badge_file[24];
char fullpath[PATH_MAX_LENGTH];
uintptr_t tex = 0;
if (download_if_missing)
{
if (badge[0] == 'i')
{
/* rcheevos_client_download_game_badge expects a rc_client_game_t, not the badge name.
* call rc_api_init_fetch_image_request directly */
rc_api_fetch_image_request_t image_request;
rc_api_request_t request;
int result;
/* OpenGL driver crashes if gfx_display_reset_textures_list is called on a background thread */
retro_assert(task_is_on_main_thread());
memset(&image_request, 0, sizeof(image_request));
image_request.image_type = RC_IMAGE_TYPE_GAME;
image_request.image_name = &badge[1];
result = rc_api_init_fetch_image_request(&request, &image_request);
_len = strlcpy(badge_file, badge, sizeof(badge_file));
_len += strlcpy(badge_file + _len, locked ? "_lock" : "",
sizeof(badge_file) - _len);
strlcpy(badge_file + _len, FILE_PATH_PNG_EXTENSION,
sizeof(badge_file) - _len);
fill_pathname_application_special(fullpath, sizeof(fullpath),
APPLICATION_SPECIAL_DIRECTORY_THUMBNAILS_CHEEVOS_BADGES);
if (gfx_display_reset_textures_list(badge_file, fullpath,
&tex, TEXTURE_FILTER_MIPMAP_LINEAR, NULL, NULL))
return tex;
if (result == RC_OK)
rcheevos_client_download_badge_from_url(request.url, badge);
}
else
{
rcheevos_client_download_achievement_badge(badge, locked);
}
}
return 0;
}
return 0;
return tex;
}

View File

@ -7,7 +7,7 @@ Comment=Frontend for emulators, game engines and media players
Comment[ru]=Графический интерфейс для эмуляторов, игровых движков и медиаплееров
Comment[fr]=Interface graphique pour émulateurs, moteurs de jeu et lecteurs multimédia
Comment[de]=Front-End für Emulatoren, Spiel-Engines und Mediaplayer
Icon=retroarch
Icon=com.libretro.RetroArch
Exec=retroarch
Terminal=false
StartupNotify=false

View File

@ -2,7 +2,7 @@
<!-- Copyright 2019 Rob Loach <robloach@gmail.com> -->
<component type="desktop-application">
<id>com.libretro.RetroArch</id>
<launchable type="desktop-id">retroarch.desktop</launchable>
<launchable type="desktop-id">com.libretro.RetroArch.desktop</launchable>
<name>RetroArch</name>
<summary>Frontend for emulators, game engines and media players</summary>
<developer_name>libretro</developer_name>

414
command.c
View File

@ -18,6 +18,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <locale.h>
#ifdef HAVE_NETWORKING
#include <net/net_compat.h>
#include <net/net_socket.h>
@ -229,7 +230,7 @@ static void command_network_poll(command_t *handle)
command_t* command_network_new(uint16_t port)
{
struct addrinfo *res = NULL;
command_t *cmd = (command_t*)calloc(1, sizeof(command_t));
command_t *cmd = (command_t*)calloc(1, sizeof(*cmd));
command_network_t *netcmd = (command_network_t*)calloc(
1, sizeof(command_network_t));
int fd = socket_init(
@ -407,12 +408,15 @@ bool command_get_config_param(command_t *cmd, const char* arg)
input_driver_state_t *input_st = input_state_get_ptr();
value = value_dynamic;
value_dynamic[0] = '\0';
if(input_st->bsv_movie_state_handle)
snprintf(value_dynamic, sizeof(value_dynamic), "%lld %u",
(long long)(input_st->bsv_movie_state_handle->identifier),
input_st->bsv_movie_state.flags);
if(input_st->bsv_movie_state_handle) {
bsv_movie_t *movie = input_st->bsv_movie_state_handle;
snprintf(value_dynamic, sizeof(value_dynamic), "%lld %u %lld",
(long long)(movie->identifier),
input_st->bsv_movie_state.flags,
(long long)(movie->frame_counter));
}
else
snprintf(value_dynamic, sizeof(value_dynamic), "0 0");
strlcpy(value_dynamic, "0 0 0", sizeof(value_dynamic));
}
#endif
/* TODO: query any string */
@ -737,8 +741,8 @@ bool command_play_replay_slot(command_t *cmd, const char *arg)
{
input_driver_state_t *input_st = input_state_get_ptr();
task_queue_wait(NULL,NULL);
if(input_st->bsv_movie_state_handle)
snprintf(reply, sizeof(reply) - 1, "PLAY_REPLAY_SLOT %lld", (long long)(input_st->bsv_movie_state_handle->identifier));
if(input_st->bsv_movie_state_next_handle)
snprintf(reply, sizeof(reply) - 1, "PLAY_REPLAY_SLOT %lld", (long long)(input_st->bsv_movie_state_next_handle->identifier));
else
snprintf(reply, sizeof(reply) - 1, "PLAY_REPLAY_SLOT 0");
command_post_state_loaded();
@ -918,7 +922,6 @@ bool command_get_status(command_t *cmd, const char* arg)
{
/* add some content info */
runloop_state_t *runloop_st = runloop_state_get_ptr();
const char *status = "PLAYING";
const char *content_name = path_basename(path_get(RARCH_PATH_BASENAME)); /* filename only without ext */
int content_crc32 = content_get_crc();
const char* system_id = NULL;
@ -928,15 +931,20 @@ bool command_get_status(command_t *cmd, const char* arg)
core_info_get_current_core(&core_info);
if (runloop_st->flags & RUNLOOP_FLAG_PAUSED)
status = "PAUSED";
if (core_info)
system_id = core_info->system_id;
if (!system_id)
system_id = runloop_st->system.info.library_name;
_len = snprintf(reply, sizeof(reply), "GET_STATUS %s %s,%s,crc32=%x\n",
status, system_id, content_name, content_crc32);
_len = strlcpy(reply, "GET_STATUS ", sizeof(reply));
if (runloop_st->flags & RUNLOOP_FLAG_PAUSED)
_len += strlcpy(reply + _len, "PAUSED", sizeof(reply) - _len);
else
_len += strlcpy(reply + _len, "PLAYING", sizeof(reply) - _len);
_len += strlcpy(reply + _len, " ", sizeof(reply) - _len);
_len += strlcpy(reply + _len, system_id, sizeof(reply) - _len);
_len += strlcpy(reply + _len, ",", sizeof(reply) - _len);
_len += strlcpy(reply + _len, content_name, sizeof(reply) - _len);
_len += snprintf(reply + _len, sizeof(reply) - _len, ",crc32=%x\n", content_crc32);
}
else
_len = strlcpy(reply, "GET_STATUS CONTENTLESS", sizeof(reply));
@ -1166,11 +1174,23 @@ bool command_event_save_config(
const char *str = path_exists ? config_path :
path_get(RARCH_PATH_CONFIG);
/* Workaround for libdecor 0.2.0 setting unwanted locale */
#if defined(HAVE_WAYLAND) && defined(HAVE_DYNAMIC)
setlocale(LC_NUMERIC,"C");
#endif
if (path_exists && config_save_file(config_path))
{
#if IOS
char tmp[PATH_MAX_LENGTH] = {0};
fill_pathname_abbreviate_special(tmp, config_path, sizeof(tmp));
snprintf(s, len, "%s \"%s\".",
msg_hash_to_str(MSG_SAVED_NEW_CONFIG_TO),
tmp);
#else
snprintf(s, len, "%s \"%s\".",
msg_hash_to_str(MSG_SAVED_NEW_CONFIG_TO),
config_path);
#endif
RARCH_LOG("[Config]: %s\n", s);
return true;
}
@ -1253,9 +1273,7 @@ bool command_event_resize_windowed_scale(settings_t *settings,
return true;
}
bool command_event_save_auto_state(
bool savestate_auto_save,
const enum rarch_core_type current_core_type)
bool command_event_save_auto_state(void)
{
size_t _len;
runloop_state_t *runloop_st = runloop_state_get_ptr();
@ -1263,10 +1281,6 @@ bool command_event_save_auto_state(
if (runloop_st->entry_state_slot)
return false;
if (!savestate_auto_save)
return false;
if (current_core_type == CORE_TYPE_DUMMY)
return false;
if (!core_info_current_supports_savestate())
return false;
if (string_is_empty(path_basename(path_get(RARCH_PATH_BASENAME))))
@ -1279,7 +1293,7 @@ bool command_event_save_auto_state(
".auto",
sizeof(savestate_name_auto) - _len);
if (content_save_state((const char*)savestate_name_auto, true, true))
if (content_auto_save_state((const char*)savestate_name_auto))
RARCH_LOG("%s \"%s\" %s.\n",
msg_hash_to_str(MSG_AUTO_SAVE_STATE_TO),
savestate_name_auto, "succeeded");
@ -1408,27 +1422,43 @@ void command_event_load_auto_state(void)
savestate_name_auto, "failed");
}
void command_event_set_savestate_auto_index(settings_t *settings)
/**
* Scans existing states to determine which one should be loaded
* and which one can be deleted, using savestate wraparound if
* enabled.
*
* @param settings The usual RetroArch settings ptr.
* @param last_index Return value for load slot.
* @param file_to_delete Return value for file name that should be removed.
*/
static void scan_states(settings_t *settings,
unsigned *last_index, char *file_to_delete)
{
size_t i;
runloop_state_t *runloop_st = runloop_state_get_ptr();
bool show_hidden_files = settings->bools.show_hidden_files;
unsigned savestate_max_keep = settings->uints.savestate_max_keep;
int curr_state_slot = settings->ints.state_slot;
unsigned max_idx = 0;
unsigned loa_idx = 0;
unsigned gap_idx = UINT_MAX;
unsigned del_idx = UINT_MAX;
retro_bits_512_t slot_mapping_low = {0};
retro_bits_512_t slot_mapping_high = {0};
struct string_list *dir_list = NULL;
const char *savefile_root = NULL;
size_t savefile_root_length = 0;
size_t i, cnt = 0;
size_t cnt_in_range = 0;
char state_dir[DIR_MAX_LENGTH];
/* Base name of 128 may be too short for some (<<1%) of the
tosec-based file names, but in practice truncating will not
lead to mismatch */
char state_base[128];
char state_dir[PATH_MAX_LENGTH];
struct string_list *dir_list = NULL;
unsigned max_idx = 0;
runloop_state_t *runloop_st = runloop_state_get_ptr();
bool savestate_auto_index = settings->bools.savestate_auto_index;
bool show_hidden_files = settings->bools.show_hidden_files;
if (!savestate_auto_index)
return;
/* Find the file in the same directory as runloop_st->savestate_name
* with the largest numeral suffix.
*
* E.g. /foo/path/content.state, will try to find
* /foo/path/content.state%d, where %d is the largest number available.
*/
fill_pathname_basedir(state_dir, runloop_st->name.savestate,
sizeof(state_dir));
@ -1444,68 +1474,10 @@ void command_event_set_savestate_auto_index(settings_t *settings)
for (i = 0; i < dir_list->size; i++)
{
unsigned idx;
char elem_base[128] = {0};
const char *end = NULL;
const char *dir_elem = dir_list->elems[i].data;
fill_pathname_base(elem_base, dir_elem, sizeof(elem_base));
if (strstr(elem_base, state_base) != elem_base)
continue;
end = dir_elem + strlen(dir_elem);
while ((end > dir_elem) && ISDIGIT((int)end[-1]))
end--;
idx = (unsigned)strtoul(end, NULL, 0);
if (idx > max_idx)
max_idx = idx;
}
dir_list_free(dir_list);
configuration_set_int(settings, settings->ints.state_slot, max_idx);
RARCH_LOG("[State]: %s: #%d\n",
msg_hash_to_str(MSG_FOUND_LAST_STATE_SLOT),
max_idx);
}
void command_event_set_savestate_garbage_collect(
unsigned max_to_keep,
bool show_hidden_files
)
{
size_t i, cnt = 0;
char state_dir[PATH_MAX_LENGTH];
char state_base[128];
runloop_state_t *runloop_st = runloop_state_get_ptr();
struct string_list *dir_list = NULL;
unsigned min_idx = UINT_MAX;
const char *oldest_save = NULL;
/* Similar to command_event_set_savestate_auto_index(),
* this will find the lowest numbered save-state */
fill_pathname_basedir(state_dir, runloop_st->name.savestate,
sizeof(state_dir));
dir_list = dir_list_new_special(state_dir, DIR_LIST_PLAIN, NULL,
show_hidden_files);
if (!dir_list)
return;
fill_pathname_base(state_base, runloop_st->name.savestate,
sizeof(state_base));
for (i = 0; i < dir_list->size; i++)
{
unsigned idx;
char elem_base[128];
const char *ext = NULL;
const char *end = NULL;
const char *dir_elem = dir_list->elems[i].data;
char elem_base[128] = {0};
const char *ext = NULL;
const char *end = NULL;
const char *dir_elem = dir_list->elems[i].data;
if (string_is_empty(dir_elem))
continue;
@ -1524,44 +1496,218 @@ void command_event_set_savestate_garbage_collect(
if (!string_starts_with(elem_base, state_base))
continue;
/* This looks like a valid save */
cnt++;
/* This looks like a valid savestate */
/* Save filename root and length (once) */
if (savefile_root_length == 0)
{
savefile_root = dir_elem;
savefile_root_length = strlen(dir_elem);
}
/* > Get index */
/* Decode the savestate index */
end = dir_elem + strlen(dir_elem);
while ((end > dir_elem) && ISDIGIT((int)end[-1]))
{
end--;
if (savefile_root == dir_elem)
savefile_root_length--;
}
idx = string_to_unsigned(end);
/* > Check if this is the lowest index so far */
if (idx < min_idx)
/* Simple administration: max, total. */
if (idx > max_idx)
max_idx = idx;
cnt++;
if (idx <= savestate_max_keep)
cnt_in_range++;
/* Maintain a 2x512 bit map of occupied save states */
if (idx<512)
BIT512_SET(slot_mapping_low,idx);
else if (idx<1024)
BIT512_SET(slot_mapping_high,idx-512);
}
/* Next loop on the bitmap, since the file system may have presented the files in any order above */
for(i=0 ; i <= savestate_max_keep ; i++)
{
/* Unoccupied save slots */
if ((i < 512 && !BIT512_GET(slot_mapping_low, i)) ||
(i > 511 && !BIT512_GET(slot_mapping_high, i-512)) )
{
min_idx = idx;
oldest_save = dir_elem;
/* Gap index: lowest free slot in the wraparound range */
if (gap_idx == UINT_MAX)
gap_idx = (unsigned)i;
}
/* Occupied save slots */
else
{
/* Del index: first occupied slot in the wraparound range,
after gap index */
if (gap_idx < UINT_MAX &&
del_idx == UINT_MAX)
del_idx = (unsigned)i;
}
}
/* Special cases of wraparound */
/* No previous savestate - set to end, so that first save
goes to 0 */
if (cnt_in_range == 0)
{
if (cnt == 0)
loa_idx = savestate_max_keep;
/* Transient: nothing in current range, but something is present
* higher up -> load that */
else
loa_idx = max_idx;
gap_idx = savestate_max_keep;
del_idx = savestate_max_keep;
}
/* No gap was found - deduct from current index or default
and set (missing) gap index to be deleted */
else if (gap_idx == UINT_MAX)
{
/* Transient: no gap, and max is higher than currently
* allowed -> load that, but wrap around so that next
* time gap will be present */
if (max_idx > savestate_max_keep)
{
loa_idx = max_idx;
gap_idx = 1;
}
/* Current index is in range, so let's assume it is correct */
else if ( (unsigned)curr_state_slot < savestate_max_keep)
{
loa_idx = curr_state_slot;
gap_idx = curr_state_slot + 1;
}
else
{
loa_idx = savestate_max_keep;
gap_idx = 0;
}
del_idx = gap_idx;
}
/* Gap was found */
else
{
/* No candidate to delete */
if (del_idx == UINT_MAX)
{
/* Either gap is at the end of the range: wraparound.
or there is no better idea than the lowest index */
del_idx = 0;
}
/* Adjust load index */
if (gap_idx == 0)
loa_idx = savestate_max_keep;
else
loa_idx = gap_idx - 1;
}
RARCH_DBG("[State]: savestate scanning finished, used slots (in range): "
"%d (%d), max:%d, load index %d, gap index %d, delete index %d\n",
cnt, cnt_in_range, max_idx, loa_idx, gap_idx, del_idx);
if (last_index != NULL)
{
*last_index = loa_idx;
}
if (file_to_delete != NULL && cnt_in_range >= savestate_max_keep)
{
strlcpy(file_to_delete, savefile_root, savefile_root_length + 1);
/* ".state0" is just ".state" instead, so don't print that. */
if (del_idx > 0)
snprintf(file_to_delete+savefile_root_length, 5, "%d", del_idx);
}
dir_list_free(dir_list);
}
/**
* Determines next savestate slot in case of auto-increment,
* i.e. save state scanning was done already earlier.
* Logic moved here so that all save state wraparound code is
* in this file.
*
* @param settings The usual RetroArch settings ptr.
* @return \c The next savestate slot.
*/
int command_event_get_next_savestate_auto_index(settings_t *settings)
{
unsigned savestate_max_keep = settings->uints.savestate_max_keep;
int new_state_slot = settings->ints.state_slot + 1;
/* If previous save was above the wraparound range, or it overflows,
return to the start of the range. */
if( savestate_max_keep > 0 && (unsigned)new_state_slot > savestate_max_keep)
new_state_slot = 0;
return new_state_slot;
}
/**
* Determines most recent savestate slot in case of content load.
*
* @param settings The usual RetroArch settings ptr.
* @return \c The most recent savestate slot.
*/
void command_event_set_savestate_auto_index(settings_t *settings)
{
unsigned max_idx = 0;
bool savestate_auto_index = settings->bools.savestate_auto_index;
if (!savestate_auto_index)
return;
scan_states(settings, &max_idx, NULL);
configuration_set_int(settings, settings->ints.state_slot, max_idx);
RARCH_LOG("[State]: %s: #%d\n",
msg_hash_to_str(MSG_FOUND_LAST_STATE_SLOT),
max_idx);
}
/**
* Deletes the oldest save state and its thumbnail, if needed.
*
* @param settings The usual RetroArch settings ptr.
*/
static void command_event_set_savestate_garbage_collect(settings_t *settings)
{
char state_to_delete[PATH_MAX_LENGTH] = {0};
size_t i;
scan_states(settings, NULL, state_to_delete);
/* Only delete one save state per save action
* > Conservative behaviour, designed to minimise
* the risk of deleting multiple incorrect files
* in case of accident */
if (!string_is_empty(oldest_save) && (cnt > max_to_keep))
filestream_delete(oldest_save);
dir_list_free(dir_list);
if (!string_is_empty(state_to_delete))
{
filestream_delete(state_to_delete);
RARCH_DBG("[State]: garbage collect, deleting \"%s\" \n",state_to_delete);
/* Construct the save state thumbnail name
* and delete that one as well. */
i = strlen(state_to_delete);
strlcpy(state_to_delete + i,".png",STRLEN_CONST(".png")+1);
filestream_delete(state_to_delete);
RARCH_DBG("[State]: garbage collect, deleting \"%s\" \n",state_to_delete);
}
}
void command_event_set_replay_auto_index(settings_t *settings)
{
size_t i;
char state_base[128];
char state_dir[PATH_MAX_LENGTH];
char state_dir[DIR_MAX_LENGTH];
struct string_list *dir_list = NULL;
unsigned max_idx = 0;
runloop_state_t *runloop_st = runloop_state_get_ptr();
bool replay_auto_index = settings->bools.replay_auto_index;
bool replay_auto_index = settings->bools.replay_auto_index;
bool show_hidden_files = settings->bools.show_hidden_files;
if (!replay_auto_index)
@ -1610,9 +1756,10 @@ void command_event_set_replay_auto_index(settings_t *settings)
configuration_set_int(settings, settings->ints.replay_slot, max_idx);
RARCH_LOG("[Replay]: %s: #%d\n",
msg_hash_to_str(MSG_FOUND_LAST_REPLAY_SLOT),
max_idx);
if (max_idx)
RARCH_LOG("[Replay]: %s: #%d\n",
msg_hash_to_str(MSG_FOUND_LAST_REPLAY_SLOT),
max_idx);
}
void command_event_set_replay_garbage_collect(
@ -1622,7 +1769,7 @@ void command_event_set_replay_garbage_collect(
{
/* TODO: debugme */
size_t i, cnt = 0;
char state_dir[PATH_MAX_LENGTH];
char state_dir[DIR_MAX_LENGTH];
char state_base[128];
runloop_state_t *runloop_st = runloop_state_get_ptr();
@ -1729,9 +1876,9 @@ bool command_event_save_core_config(
const char *rarch_path_config)
{
char msg[128];
char config_name[255];
char config_path[PATH_MAX_LENGTH];
char config_dir[PATH_MAX_LENGTH];
char config_name[NAME_MAX_LENGTH];
char config_dir[DIR_MAX_LENGTH];
bool new_path_available = false;
bool overrides_active = false;
const char *core_path = NULL;
@ -1770,12 +1917,14 @@ bool command_event_save_core_config(
for (i = 0; i < 16; i++)
{
size_t _len = strlcpy(tmp, config_path, sizeof(tmp));
if (i)
_len += snprintf(tmp + _len, sizeof(tmp) - _len, "-%u", i);
strlcpy(tmp + _len, ".cfg", sizeof(tmp) - _len);
if (!path_is_valid(tmp))
{
strlcpy(config_path, tmp, sizeof(config_path));
new_path_available = true;
break;
}
@ -1850,7 +1999,7 @@ void command_event_save_current_config(enum override_type type)
case OVERRIDE_CORE:
case OVERRIDE_CONTENT_DIR:
{
int8_t ret = config_save_overrides(type, &runloop_st->system, false);
int8_t ret = config_save_overrides(type, &runloop_st->system, false, NULL);
char msg[256];
msg[0] = '\0';
@ -1904,7 +2053,7 @@ void command_event_remove_current_config(enum override_type type)
msg[0] = '\0';
if (config_save_overrides(type, &runloop_st->system, true))
if (config_save_overrides(type, &runloop_st->system, true, NULL))
strlcpy(msg, msg_hash_to_str(MSG_OVERRIDES_REMOVED_SUCCESSFULLY), sizeof(msg));
else
strlcpy(msg, msg_hash_to_str(MSG_OVERRIDES_ERROR_REMOVING), sizeof(msg));
@ -1961,7 +2110,7 @@ bool command_event_main_state(unsigned cmd)
case CMD_EVENT_SAVE_STATE_TO_RAM:
{
/* TODO: Saving state during recording should associate the state with the replay. */
video_driver_state_t *video_st =
video_driver_state_t *video_st =
video_state_get_ptr();
bool savestate_auto_index =
settings->bools.savestate_auto_index;
@ -1971,16 +2120,13 @@ bool command_event_main_state(unsigned cmd)
settings->bools.frame_time_counter_reset_after_save_state;
if (cmd == CMD_EVENT_SAVE_STATE)
content_save_state(state_path, true, false);
content_save_state(state_path, true);
else
content_save_state_to_ram();
/* Clean up excess savestates if necessary */
if (savestate_auto_index && (savestate_max_keep > 0))
command_event_set_savestate_garbage_collect(
settings->uints.savestate_max_keep,
settings->bools.show_hidden_files
);
command_event_set_savestate_garbage_collect(settings);
if (frame_time_counter_reset_after_save_state)
video_st->frame_time_count = 0;
@ -2088,15 +2234,15 @@ void command_event_reinit(const int flags)
bool adaptive_vsync = settings->bools.video_adaptive_vsync;
unsigned swap_interval_config = settings->uints.video_swap_interval;
#endif
enum input_game_focus_cmd_type
enum input_game_focus_cmd_type
game_focus_cmd = GAME_FOCUS_CMD_REAPPLY;
const input_device_driver_t
const input_device_driver_t
*joypad = input_st->primary_joypad;
#ifdef HAVE_MFI
const input_device_driver_t
const input_device_driver_t
*sec_joypad = input_st->secondary_joypad;
#else
const input_device_driver_t
const input_device_driver_t
*sec_joypad = NULL;
#endif

View File

@ -88,6 +88,8 @@ enum event_command
CMD_EVENT_REWIND_DEINIT,
/* Initializes rewind. */
CMD_EVENT_REWIND_INIT,
/* Reinitializes rewind (primarily if the state size changes). */
CMD_EVENT_REWIND_REINIT,
/* Toggles rewind. */
CMD_EVENT_REWIND_TOGGLE,
/* Initializes autosave. */
@ -267,7 +269,9 @@ enum event_command
CMD_EVENT_MICROPHONE_REINIT,
#endif
/* Deprecated */
CMD_EVENT_SEND_DEBUG_INFO
CMD_EVENT_SEND_DEBUG_INFO,
/* Add a playlist entry to another playlist. */
CMD_EVENT_ADD_TO_PLAYLIST
};
enum cmd_source_t
@ -347,9 +351,7 @@ void command_event_set_mixer_volume(
bool command_event_resize_windowed_scale(settings_t *settings,
unsigned window_scale);
bool command_event_save_auto_state(
bool savestate_auto_save,
const enum rarch_core_type current_core_type);
bool command_event_save_auto_state(void);
/**
* event_set_volume:
@ -379,10 +381,8 @@ void command_event_load_auto_state(void);
void command_event_set_savestate_auto_index(
settings_t *settings);
void command_event_set_savestate_garbage_collect(
unsigned max_to_keep,
bool show_hidden_files
);
int command_event_get_next_savestate_auto_index(
settings_t *settings);
void command_event_set_replay_auto_index(
settings_t *settings);

View File

@ -69,6 +69,14 @@
#define DEFAULT_ASPECT_RATIO 1.3333f
#endif
#define DEFAULT_VIEWPORT_BIAS_X 0.5
#define DEFAULT_VIEWPORT_BIAS_Y 0.5
#if defined(RARCH_MOBILE)
#define DEFAULT_VIEWPORT_BIAS_PORTRAIT_X 0.5
#define DEFAULT_VIEWPORT_BIAS_PORTRAIT_Y 0.0
#endif
#if defined(GEKKO)
#define DEFAULT_MOUSE_SCALE 1
#endif
@ -177,6 +185,12 @@
#define DEFAULT_GAMEMODE_ENABLE true
#ifdef HAVE_LAKKA_SWITCH
#define DEFAULT_SWITCH_OC false
#define DEFAULT_SWITCH_CEC true
#define DEFAULT_BLUETOOTH_ERTM false
#endif
#if (defined(_WIN32) && !defined(_XBOX)) || (defined(__linux) && !defined(ANDROID) && !defined(HAVE_LAKKA)) || (defined(__MACH__) && !defined(IOS)) || defined(EMSCRIPTEN)
#define DEFAULT_MOUSE_ENABLE true
#else
@ -231,12 +245,13 @@
/* Do not use windowed mode for WinRT and Winapi Family builds on the Xbox UWP with fixed resolution shrinks the image into the left top corner of the screen with some libretro cores */
#define DEFAULT_WINDOWED_FULLSCREEN false
#else
#define DEFAULT_WINDOWED_FULLSCREEN true
#endif
#define DEFAULT_WINDOWED_FULLSCREEN true
#endif
/* Enable automatic switching of the screen refresh rate when using the specified screen mode(s),
* based on running core/content */
#define DEFAULT_AUTOSWITCH_REFRESH_RATE AUTOSWITCH_REFRESH_RATE_EXCLUSIVE_FULLSCREEN
#define DEFAULT_AUTOSWITCH_PAL_THRESHOLD 54.50f
/* Which monitor to prefer. 0 is any monitor, 1 and up selects
* specific monitors, 1 being the first monitor. */
@ -310,7 +325,7 @@
/* Number of threads to use for video recording */
#define DEFAULT_VIDEO_RECORD_THREADS 2
#if defined(RARCH_CONSOLE) || defined(__APPLE__)
#if defined(RARCH_CONSOLE)
#define DEFAULT_LOAD_DUMMY_ON_CORE_SHUTDOWN false
#else
#define DEFAULT_LOAD_DUMMY_ON_CORE_SHUTDOWN true
@ -353,6 +368,8 @@
/* Vulkan specific */
#define DEFAULT_MAX_SWAPCHAIN_IMAGES 3
#define MINIMUM_MAX_SWAPCHAIN_IMAGES 2
#define MAXIMUM_MAX_SWAPCHAIN_IMAGES 4
/* D3D1x specific */
#if defined(__WINRT__) || defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
@ -376,21 +393,41 @@
* 2: Etc ...
*/
#define DEFAULT_HARD_SYNC_FRAMES 0
#define MINIMUM_HARD_SYNC_FRAMES 0
#define MAXIMUM_HARD_SYNC_FRAMES 3
/* Sets how many milliseconds to delay after VSync before running the core.
* Can reduce latency at cost of higher risk of stuttering.
*/
#define DEFAULT_FRAME_DELAY 0
#define MAXIMUM_FRAME_DELAY 19
#define MAXIMUM_FRAME_DELAY 99
#define DEFAULT_FRAME_DELAY_AUTO false
/* Duplicates frames for the purposes of running Shaders at a higher framerate
* than content framerate. Requires running screen at multiple of 60hz, and
* don't combine with Swap_interval > 1, or BFI. (Though BFI can be done in a shader
* with multi-frame shaders.)
*/
#define DEFAULT_SHADER_SUBFRAMES 1
/* Divides implements basic rolling scanning of sub frames - does this simply by scrolling a
* a scissor rect down the screen according to how many sub frames there are
*/
#define DEFAULT_SCAN_SUBFRAMES false
/* Inserts black frame(s) inbetween frames.
* Useful for Higher Hz monitors (set to multiples of 60 Hz) who want to play 60 Hz
* material with eliminated ghosting. video_refresh_rate should still be configured
* as if it is a 60 Hz monitor (divide refresh rate by multiple of 60 Hz).
* Useful for Higher Hz monitors (set to multiples of 60 Hz) who want to play 60 Hz
* material with CRT-like motion clarity.
*/
#define DEFAULT_BLACK_FRAME_INSERTION 0
/* Black Frame Insertion Dark Frames.
* Increase for more clarity at the cost of lower brightness. Adjusting can also eliminate
* any temporary image retention if noticed. Only useful at 180hz or higher 60hz multiples,
* as 120hz only has one total extra frame for BFI to work with.
*/
#define DEFAULT_BFI_DARK_FRAMES 1
/* Uses a custom swap interval for VSync.
* Set this to effectively halve monitor refresh rate.
*/
@ -471,7 +508,7 @@
/* Should we expand the colour gamut when using hdr */
#define DEFAULT_VIDEO_HDR_EXPAND_GAMUT true
/* When presets are saved they will be saved using the #reference
/* When presets are saved they will be saved using the #reference
* directive by default */
#define DEFAULT_VIDEO_SHADER_PRESET_SAVE_REFERENCE_ENABLE true
@ -483,7 +520,8 @@
* Overscale rounds up instead of down, default is downscale.
*/
#define DEFAULT_SCALE_INTEGER false
#define DEFAULT_SCALE_INTEGER_OVERSCALE false
#define DEFAULT_SCALE_INTEGER_AXIS 0
#define DEFAULT_SCALE_INTEGER_SCALING 0
/* Controls aspect ratio handling. */
@ -579,6 +617,24 @@
#define DEFAULT_INPUT_OVERLAY_AUTO_SCALE false
#endif
#if defined(RARCH_MOBILE)
#define DEFAULT_INPUT_OVERLAY_POINTER_ENABLE true
#else
#define DEFAULT_INPUT_OVERLAY_POINTER_ENABLE false
#endif
#define DEFAULT_INPUT_OVERLAY_LIGHTGUN_PORT -1
#define DEFAULT_INPUT_OVERLAY_LIGHTGUN_TRIGGER_ON_TOUCH true
#define DEFAULT_INPUT_OVERLAY_LIGHTGUN_TRIGGER_DELAY 1
#define DEFAULT_INPUT_OVERLAY_LIGHTGUN_MULTI_TOUCH_INPUT 0
#define DEFAULT_INPUT_OVERLAY_LIGHTGUN_ALLOW_OFFSCREEN true
#define DEFAULT_INPUT_OVERLAY_MOUSE_SPEED 1.0f
#define DEFAULT_INPUT_OVERLAY_MOUSE_HOLD_TO_DRAG true
#define DEFAULT_INPUT_OVERLAY_MOUSE_HOLD_MSEC 200
#define DEFAULT_INPUT_OVERLAY_MOUSE_DTAP_TO_DRAG false
#define DEFAULT_INPUT_OVERLAY_MOUSE_DTAP_MSEC 200
#define DEFAULT_INPUT_OVERLAY_MOUSE_SWIPE_THRESHOLD 1.0f
#ifdef UDEV_TOUCH_SUPPORT
#define DEFAULT_INPUT_TOUCH_VMOUSE_POINTER true
#define DEFAULT_INPUT_TOUCH_VMOUSE_MOUSE true
@ -643,6 +699,7 @@
#define DEFAULT_QUICK_MENU_SHOW_UNDO_SAVE_LOAD_STATE true
#define DEFAULT_QUICK_MENU_SHOW_REPLAY false
#define DEFAULT_QUICK_MENU_SHOW_ADD_TO_FAVORITES true
#define DEFAULT_QUICK_MENU_SHOW_ADD_TO_PLAYLIST false
#define DEFAULT_QUICK_MENU_SHOW_START_RECORDING true
#define DEFAULT_QUICK_MENU_SHOW_START_STREAMING true
#define DEFAULT_QUICK_MENU_SHOW_SET_CORE_ASSOCIATION true
@ -689,8 +746,10 @@
#ifdef HAVE_MIST
#define DEFAULT_MENU_SHOW_CORE_MANAGER_STEAM true
#endif
#if 0
/* Thumbnailpack removal */
#define DEFAULT_MENU_SHOW_LEGACY_THUMBNAIL_UPDATER false
#endif
#define DEFAULT_MENU_SHOW_SUBLABELS true
#define DEFAULT_MENU_DYNAMIC_WALLPAPER_ENABLE true
#define DEFAULT_MENU_SCROLL_FAST false
@ -766,7 +825,7 @@
#define DEFAULT_XMB_TITLE_MARGIN 5
#define DEFAULT_XMB_TITLE_MARGIN_HORIZONTAL_OFFSET 0
#define MAXIMUM_XMB_TITLE_MARGIN 12
#define DEFAULT_XMB_ALPHA_FACTOR 75
#define DEFAULT_XMB_ALPHA_FACTOR 90
#define DEFAULT_MENU_FONT_COLOR_RED 255
#define DEFAULT_MENU_FONT_COLOR_GREEN 255
@ -787,7 +846,7 @@
#endif
#define DEFAULT_MENU_FRAMEBUFFER_OPACITY 0.900f
#define DEFAULT_MENU_WALLPAPER_OPACITY 0.300f
#define DEFAULT_MENU_WALLPAPER_OPACITY 0.900f
#define DEFAULT_MENU_FOOTER_OPACITY 1.000f
#define DEFAULT_MENU_HEADER_OPACITY 1.000f
@ -830,11 +889,12 @@
#define DEFAULT_GAME_SPECIFIC_OPTIONS true
#define DEFAULT_AUTO_OVERRIDES_ENABLE true
#define DEFAULT_AUTO_REMAPS_ENABLE true
#define DEFAULT_INITIAL_DISK_CHANGE_ENABLE true
#define DEFAULT_GLOBAL_CORE_OPTIONS false
#define DEFAULT_AUTO_SHADERS_ENABLE true
#define DEFAULT_SORT_SAVEFILES_ENABLE false
#define DEFAULT_SORT_SAVESTATES_ENABLE false
#define DEFAULT_SORT_SAVEFILES_ENABLE true
#define DEFAULT_SORT_SAVESTATES_ENABLE true
#define DEFAULT_SORT_SAVEFILES_BY_CONTENT_ENABLE false
#define DEFAULT_SORT_SAVESTATES_BY_CONTENT_ENABLE false
#define DEFAULT_SORT_SCREENSHOTS_BY_CONTENT_ENABLE false
@ -844,7 +904,7 @@
#define DEFAULT_SYSTEMFILES_IN_CONTENT_DIR false
#define DEFAULT_SCREENSHOTS_IN_CONTENT_DIR false
#if defined(RS90) || defined(RETROFW) || defined(MIYOO)
#if defined(RS90) || defined(RETROFW) || defined(MIYOO) || defined(SWITCH) || defined(ORBIS) || defined(__WINRT__)
#define DEFAULT_MENU_TOGGLE_GAMEPAD_COMBO INPUT_COMBO_START_SELECT
#elif defined(_XBOX1) || defined(__PS3__) || defined(_XBOX360) || defined(DINGUX)
#define DEFAULT_MENU_TOGGLE_GAMEPAD_COMBO INPUT_COMBO_L3_R3
@ -852,8 +912,6 @@
#define DEFAULT_MENU_TOGGLE_GAMEPAD_COMBO INPUT_COMBO_HOLD_START
#elif defined(VITA)
#define DEFAULT_MENU_TOGGLE_GAMEPAD_COMBO INPUT_COMBO_L1_R1_START_SELECT
#elif defined(SWITCH) || defined(ORBIS)
#define DEFAULT_MENU_TOGGLE_GAMEPAD_COMBO INPUT_COMBO_START_SELECT
#elif TARGET_OS_TV
#define DEFAULT_MENU_TOGGLE_GAMEPAD_COMBO INPUT_COMBO_DOWN_Y_L_R
#else
@ -1032,7 +1090,7 @@
#define DEFAULT_NOTIFICATION_SHOW_CHEATS_APPLIED true
/* Display a notification when applying an
* IPS/BPS/UPS patch file */
* IPS/BPS/UPS/Xdelta patch file */
#define DEFAULT_NOTIFICATION_SHOW_PATCH_APPLIED true
/* Display a notification when loading an
@ -1047,6 +1105,12 @@
* at launch the last used disk of multi-disk content */
#define DEFAULT_NOTIFICATION_SHOW_SET_INITIAL_DISK true
/* Display disc control notifications */
#define DEFAULT_NOTIFICATION_SHOW_DISK_CONTROL true
/* Display save state notifications */
#define DEFAULT_NOTIFICATION_SHOW_SAVE_STATE true
/* Display a notification when fast forwarding
* content */
#define DEFAULT_NOTIFICATION_SHOW_FAST_FORWARD true
@ -1058,7 +1122,7 @@
/*Desired duration of the screenshot notification*/
#define DEFAULT_NOTIFICATION_SHOW_SCREENSHOT_DURATION 0
/* Display a white flashing effect with the desired
/* Display a white flashing effect with the desired
* duration when taking a screenshot*/
#define DEFAULT_NOTIFICATION_SHOW_SCREENSHOT_FLASH 0
#endif
@ -1088,6 +1152,9 @@
#elif defined(_3DS) || defined(RETROFW)
#define DEFAULT_OUTPUT_RATE 32730
#define DEFAULT_INPUT_RATE 32730
#elif defined(EMSCRIPTEN)
#define DEFAULT_OUTPUT_RATE 44100
#define DEFAULT_INPUT_RATE 44100
#else
#define DEFAULT_OUTPUT_RATE 48000
#define DEFAULT_INPUT_RATE 48000
@ -1136,7 +1203,12 @@
#define DEFAULT_WASAPI_EXCLUSIVE_MODE false
#define DEFAULT_WASAPI_FLOAT_FORMAT false
/* Automatic shared mode buffer */
#define DEFAULT_WASAPI_SH_BUFFER_LENGTH -16
#define DEFAULT_WASAPI_SH_BUFFER_LENGTH 0
#endif
#if TARGET_OS_IOS
/* Respect silent mode (false will render audio in silent mode) */
#define DEFAULT_AUDIO_RESPECT_SILENT_MODE true
#endif
/* Automatically mute audio when fast forward
@ -1191,9 +1263,9 @@
#if defined(RETROFW) || defined(MIYOO)
/*RETROFW jz4760 has signficant slowdown with default settings */
/*RETROFW jz4760 has significant slowdown with default settings */
#define DEFAULT_REWIND_BUFFER_SIZE (1 << 20)
#define DEFAULT_REWIND_BUFFER_SIZE_STEP 1
#define DEFAULT_REWIND_BUFFER_SIZE_STEP 1
#define DEFAULT_REWIND_GRANULARITY 6
#else
/* The buffer size for the rewind buffer. This needs to be about
@ -1356,8 +1428,6 @@
/* Hide warning messages when using the Run Ahead feature. */
#define DEFAULT_RUN_AHEAD_HIDE_WARNINGS false
/* Hide warning messages when using Preemptive Frames. */
#define DEFAULT_PREEMPT_HIDE_WARNINGS false
/* Enable stdin/network command interface. */
#define DEFAULT_NETWORK_CMD_ENABLE false
@ -1412,13 +1482,15 @@
#define DEFAULT_PLAYLIST_SUBLABEL_RUNTIME_TYPE PLAYLIST_RUNTIME_PER_CORE
/* Specifies time/date display format for runtime 'last played' data */
#define DEFAULT_PLAYLIST_SUBLABEL_LAST_PLAYED_STYLE PLAYLIST_LAST_PLAYED_STYLE_YMD_HMS
#define DEFAULT_PLAYLIST_SUBLABEL_LAST_PLAYED_STYLE PLAYLIST_LAST_PLAYED_STYLE_YMD_HM
#define DEFAULT_PLAYLIST_ENTRY_REMOVE_ENABLE PLAYLIST_ENTRY_REMOVE_ENABLE_ALL
#endif
#define DEFAULT_SCAN_WITHOUT_CORE_MATCH false
#define DEFAULT_SCAN_SERIAL_AND_CRC false
#ifdef __WINRT__
/* Be paranoid about WinRT file I/O performance, and leave this disabled by
* default */
@ -1437,13 +1509,19 @@
#define DEFAULT_PLAYLIST_PORTABLE_PATHS false
#define DEFAULT_PLAYLIST_USE_FILENAME false
#define DEFAULT_PLAYLIST_ALLOW_NON_PNG false
/* Show Menu start-up screen on boot. */
#define DEFAULT_MENU_SHOW_START_SCREEN true
/* Default scale factor for non-frambuffer-based display
/* Default scale factor for non-framebuffer-based display
* drivers and display widgets */
#if defined(VITA)
#define DEFAULT_MENU_SCALE_FACTOR 1.5f
#elif defined(__ANDROID__)
#define DEFAULT_MENU_SCALE_FACTOR 0.75f
#else
#define DEFAULT_MENU_SCALE_FACTOR 1.0f
#endif
@ -1488,6 +1566,21 @@
#define DEFAULT_TURBO_DUTY_CYCLE 3
#define DEFAULT_TURBO_MODE 0
#define DEFAULT_TURBO_DEFAULT_BTN RETRO_DEVICE_ID_JOYPAD_B
#define DEFAULT_ALLOW_TURBO_DPAD false
/* Enable automatic mouse grab by default
* only on Android */
#if defined(ANDROID)
#define DEFAULT_INPUT_AUTO_MOUSE_GRAB true
#else
#define DEFAULT_INPUT_AUTO_MOUSE_GRAB false
#endif
#if TARGET_OS_IPHONE
#define DEFAULT_INPUT_KEYBOARD_GAMEPAD_ENABLE false
#else
#define DEFAULT_INPUT_KEYBOARD_GAMEPAD_ENABLE true
#endif
/* Enable input auto-detection. Will attempt to autoconfigure
* gamepads, plug-and-play style. */
@ -1518,14 +1611,16 @@
#define DEFAULT_INPUT_MAX_USERS 8
#endif
#define DEFAULT_INPUT_BIND_TIMEOUT 5
#define DEFAULT_INPUT_BIND_HOLD 2
#define DEFAULT_INPUT_BIND_TIMEOUT 3
#define DEFAULT_INPUT_BIND_HOLD 0
#define DEFAULT_INPUT_POLL_TYPE_BEHAVIOR 2
#define DEFAULT_INPUT_HOTKEY_BLOCK_DELAY 5
#define DEFAULT_INPUT_HOTKEY_DEVICE_MERGE false
#define DEFAULT_GFX_THUMBNAILS_DEFAULT 3
#define DEFAULT_MENU_LEFT_THUMBNAILS_DEFAULT 0
#define DEFAULT_MENU_ICON_THUMBNAILS_DEFAULT 0
#define DEFAULT_GFX_THUMBNAIL_UPSCALE_THRESHOLD 0
@ -1570,7 +1665,7 @@
#define DEFAULT_CONTENT_RUNTIME_LOG true
#endif
/* Keep track of how long each content has been running
/* Keep track of how long each content has been running
* for over time (ignores core) */
#define DEFAULT_CONTENT_RUNTIME_LOG_AGGREGATE false
@ -1578,7 +1673,7 @@
#if defined(__QNX__) || defined(_XBOX1) || defined(_XBOX360) || (defined(__MACH__) && defined(IOS)) || defined(ANDROID) || defined(WIIU) || defined(HAVE_NEON) || defined(GEKKO) || defined(__ARM_NEON__) || defined(__PS3__)
#define DEFAULT_AUDIO_RESAMPLER_QUALITY_LEVEL RESAMPLER_QUALITY_LOWER
#elif defined(PSP) || defined(_3DS) || defined(VITA) || defined(PS2) || defined(DINGUX)
#elif defined(PSP) || defined(_3DS) || defined(VITA) || defined(PS2) || defined(DINGUX) || defined(EMSCRIPTEN)
#define DEFAULT_AUDIO_RESAMPLER_QUALITY_LEVEL RESAMPLER_QUALITY_LOWEST
#else
#define DEFAULT_AUDIO_RESAMPLER_QUALITY_LEVEL RESAMPLER_QUALITY_NORMAL
@ -1601,13 +1696,17 @@
/* Only applies to Android 7.0 (API 24) and up */
#define DEFAULT_SUSTAINED_PERFORMANCE_MODE false
#if defined(ANDROID)
#if defined(ANDROID) || defined(IOS)
#define DEFAULT_VIBRATE_ON_KEYPRESS true
#else
#define DEFAULT_VIBRATE_ON_KEYPRESS false
#endif
#if defined(IOS)
#define DEFAULT_ENABLE_DEVICE_VIBRATION true
#else
#define DEFAULT_ENABLE_DEVICE_VIBRATION false
#endif
/* Defines the strength of rumble effects
* on OpenDingux devices */
@ -1635,6 +1734,8 @@
#if defined(HAKCHI)
#define DEFAULT_BUILDBOT_SERVER_URL "http://hakchicloud.com/Libretro_Cores/"
#elif defined(WEBOS)
#define DEFAULT_BUILDBOT_SERVER_URL "http://retroarch-cores.webosbrew.org/armv7a/"
#elif defined(ANDROID)
#if defined(ANDROID_ARM_V7)
#define DEFAULT_BUILDBOT_SERVER_URL "http://buildbot.libretro.com/nightly/android/latest/armeabi-v7a/"
@ -1655,11 +1756,19 @@
#define DEFAULT_BUILDBOT_SERVER_URL "http://buildbot.libretro.com/nightly/apple/ios/latest/"
#elif defined(OSX)
#if defined(__x86_64__)
#if defined(HAVE_SSL)
#define DEFAULT_BUILDBOT_SERVER_URL "https://buildbot.libretro.com/nightly/apple/osx/x86_64/latest/"
#else
#define DEFAULT_BUILDBOT_SERVER_URL "http://buildbot.libretro.com/nightly/apple/osx/x86_64/latest/"
#endif
#elif defined(__i386__) || defined(__i486__) || defined(__i686__)
#define DEFAULT_BUILDBOT_SERVER_URL "http://bot.libretro.com/nightly/apple/osx/x86/latest/"
#elif defined(__aarch64__)
#if defined(HAVE_SSL)
#define DEFAULT_BUILDBOT_SERVER_URL "https://buildbot.libretro.com/nightly/apple/osx/arm64/latest/"
#else
#define DEFAULT_BUILDBOT_SERVER_URL "http://buildbot.libretro.com/nightly/apple/osx/arm64/latest/"
#endif
#else
#define DEFAULT_BUILDBOT_SERVER_URL "http://buildbot.libretro.com/nightly/apple/osx/ppc/latest/"
#endif

View File

@ -201,9 +201,8 @@ static const struct retro_keybind retro_keybinds_1[] = {
{
NULL, NULL,
AXIS_NONE, AXIS_NONE, AXIS_NONE,
RARCH_LIGHTGUN_RELOAD,
MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_RELOAD, RETROK_UNKNOWN,
NO_BTN, NO_BTN, 0,
RARCH_LIGHTGUN_RELOAD, RETRO_DEVICE_ID_MOUSE_RIGHT, NO_BTN, 0,
true
},
{
@ -838,7 +837,7 @@ static const struct retro_keybind retro_keybinds_1[] = {
NULL, NULL,
AXIS_NONE, AXIS_NONE, AXIS_NONE,
MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_RELOAD, RETROK_UNKNOWN,
RARCH_LIGHTGUN_RELOAD, NO_BTN, NO_BTN, 0,
RARCH_LIGHTGUN_RELOAD, RETRO_DEVICE_ID_MOUSE_RIGHT, NO_BTN, 0,
true
},
{
@ -1473,7 +1472,7 @@ static const struct retro_keybind retro_keybinds_1[] = {
NULL, NULL,
AXIS_NONE, AXIS_NONE, AXIS_NONE,
MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_RELOAD, RETROK_UNKNOWN,
RARCH_LIGHTGUN_RELOAD, NO_BTN, NO_BTN, 0,
RARCH_LIGHTGUN_RELOAD, RETRO_DEVICE_ID_MOUSE_RIGHT, NO_BTN, 0,
true
},
{
@ -2122,7 +2121,7 @@ static const struct retro_keybind retro_keybinds_rest[] = {
NULL, NULL,
AXIS_NONE, AXIS_NONE, AXIS_NONE,
MENU_ENUM_LABEL_VALUE_INPUT_LIGHTGUN_RELOAD, RETROK_UNKNOWN,
RARCH_LIGHTGUN_RELOAD, NO_BTN, NO_BTN, 0,
RARCH_LIGHTGUN_RELOAD, RETRO_DEVICE_ID_MOUSE_RIGHT, NO_BTN, 0,
true
},
{

File diff suppressed because it is too large Load Diff

View File

@ -40,31 +40,31 @@
#define configuration_set_float(settings, var, newvar) \
{ \
settings->modified = true; \
var = newvar; \
settings->flags |= SETTINGS_FLG_MODIFIED; \
var = newvar; \
}
#define configuration_set_bool(settings, var, newvar) \
{ \
settings->modified = true; \
var = newvar; \
settings->flags |= SETTINGS_FLG_MODIFIED; \
var = newvar; \
}
#define configuration_set_uint(settings, var, newvar) \
{ \
settings->modified = true; \
var = newvar; \
settings->flags |= SETTINGS_FLG_MODIFIED; \
var = newvar; \
}
#define configuration_set_int(settings, var, newvar) \
{ \
settings->modified = true; \
var = newvar; \
settings->flags |= SETTINGS_FLG_MODIFIED; \
var = newvar; \
}
#define configuration_set_string(settings, var, newvar) \
{ \
settings->modified = true; \
settings->flags |= SETTINGS_FLG_MODIFIED; \
strlcpy(var, newvar, sizeof(var)); \
}
@ -82,11 +82,18 @@ enum crt_switch_type
enum override_type
{
OVERRIDE_NONE = 0,
OVERRIDE_AS,
OVERRIDE_CORE,
OVERRIDE_CONTENT_DIR,
OVERRIDE_GAME
};
enum settings_glob_flags
{
SETTINGS_FLG_MODIFIED = (1 << 0),
SETTINGS_FLG_SKIP_WINDOW_POSITIONS = (1 << 1)
};
typedef struct settings
{
struct
@ -105,7 +112,6 @@ typedef struct settings
int location_update_interval_distance;
int state_slot;
int replay_slot;
int audio_wasapi_sh_buffer_length;
int crt_switch_center_adjust;
int crt_switch_porch_adjust;
#ifdef HAVE_VULKAN
@ -134,6 +140,9 @@ typedef struct settings
#ifdef HAVE_XMB
int menu_xmb_title_margin;
int menu_xmb_title_margin_horizontal_offset;
#endif
#ifdef HAVE_OVERLAY
int input_overlay_lightgun_port;
#endif
} ints;
@ -148,6 +157,7 @@ typedef struct settings
unsigned input_libretro_device[MAX_USERS];
unsigned input_analog_dpad_mode[MAX_USERS];
unsigned input_device_reservation_type[MAX_USERS];
unsigned input_remap_ports[MAX_USERS];
unsigned input_remap_ids[MAX_USERS][RARCH_CUSTOM_BIND_LIST_END];
@ -160,12 +170,18 @@ typedef struct settings
unsigned audio_block_frames;
unsigned audio_latency;
#ifdef HAVE_WASAPI
unsigned audio_wasapi_sh_buffer_length;
#endif
#ifdef HAVE_MICROPHONE
unsigned microphone_sample_rate;
unsigned microphone_block_frames;
unsigned microphone_latency;
unsigned microphone_wasapi_sh_buffer_length;
unsigned microphone_resampler_quality;
#ifdef HAVE_WASAPI
unsigned microphone_wasapi_sh_buffer_length;
#endif
#endif
unsigned fps_update_interval;
@ -226,6 +242,8 @@ typedef struct settings
unsigned video_fullscreen_x;
unsigned video_fullscreen_y;
unsigned video_scale;
unsigned video_scale_integer_axis;
unsigned video_scale_integer_scaling;
unsigned video_max_swapchain_images;
unsigned video_max_frame_latency;
unsigned video_swap_interval;
@ -264,6 +282,7 @@ typedef struct settings
unsigned menu_timedate_date_separator;
unsigned gfx_thumbnails;
unsigned menu_left_thumbnails;
unsigned menu_icon_thumbnails;
unsigned gfx_thumbnail_upscale_threshold;
unsigned menu_rgui_thumbnail_downscaler;
unsigned menu_rgui_thumbnail_delay;
@ -313,6 +332,12 @@ typedef struct settings
unsigned input_overlay_show_inputs_port;
unsigned input_overlay_dpad_diagonal_sensitivity;
unsigned input_overlay_abxy_diagonal_sensitivity;
unsigned input_overlay_lightgun_trigger_delay;
unsigned input_overlay_lightgun_two_touch_input;
unsigned input_overlay_lightgun_three_touch_input;
unsigned input_overlay_lightgun_four_touch_input;
unsigned input_overlay_mouse_hold_msec;
unsigned input_overlay_mouse_dtap_msec;
#endif
unsigned run_ahead_frames;
@ -336,6 +361,8 @@ typedef struct settings
unsigned core_updater_auto_backup_history_size;
unsigned video_black_frame_insertion;
unsigned video_bfi_dark_frames;
unsigned video_shader_subframes;
unsigned video_autoswitch_refresh_rate;
unsigned quit_on_close_content;
@ -357,7 +384,14 @@ typedef struct settings
{
float placeholder;
float video_aspect_ratio;
float video_viewport_bias_x;
float video_viewport_bias_y;
#if defined(RARCH_MOBILE)
float video_viewport_bias_portrait_x;
float video_viewport_bias_portrait_y;
#endif
float video_refresh_rate;
float video_autoswitch_pal_threshold;
float crt_video_refresh_rate;
float video_font_size;
float video_msg_pos_x;
@ -406,6 +440,9 @@ typedef struct settings
float input_overlay_x_offset_portrait;
float input_overlay_y_offset_portrait;
float input_overlay_mouse_speed;
float input_overlay_mouse_swipe_threshold;
float slowmotion_ratio;
float fastforward_ratio;
float input_analog_deadzone;
@ -427,12 +464,11 @@ typedef struct settings
char wifi_driver[32];
char led_driver[32];
char location_driver[32];
char cloud_sync_driver[32];
char menu_driver[32];
char cheevos_username[32];
char cheevos_password[256];
char cheevos_token[32];
char cheevos_leaderboards_enable[32];
char cheevos_custom_host[64];
char video_context_driver[32];
char audio_driver[32];
char audio_resampler[32];
@ -441,24 +477,37 @@ typedef struct settings
char midi_driver[32];
char midi_input[32];
char midi_output[32];
char input_keyboard_layout[64];
#ifdef HAVE_LAKKA
char cpu_main_gov[32];
char cpu_menu_gov[32];
#endif
#ifdef HAVE_MICROPHONE
char microphone_driver[32];
char microphone_resampler[32];
char microphone_device[255];
#endif
char input_keyboard_layout[64];
char cheevos_custom_host[64];
#ifdef HAVE_LAKKA
char timezone[TIMEZONE_LENGTH];
#endif
char cheevos_password[NAME_MAX_LENGTH];
#ifdef HAVE_MICROPHONE
char microphone_device[NAME_MAX_LENGTH];
#endif
#ifdef ANDROID
char input_android_physical_keyboard[255];
char input_android_physical_keyboard[NAME_MAX_LENGTH];
#endif
char audio_device[NAME_MAX_LENGTH];
char camera_device[NAME_MAX_LENGTH];
char netplay_mitm_server[NAME_MAX_LENGTH];
char webdav_url[NAME_MAX_LENGTH];
char webdav_username[NAME_MAX_LENGTH];
char webdav_password[NAME_MAX_LENGTH];
char audio_device[255];
char camera_device[255];
char netplay_mitm_server[255];
char translation_service_url[2048];
char crt_switch_timings[NAME_MAX_LENGTH];
char input_reserved_devices[MAX_USERS][NAME_MAX_LENGTH];
char youtube_stream_key[PATH_MAX_LENGTH];
char twitch_stream_key[PATH_MAX_LENGTH];
@ -466,12 +515,7 @@ typedef struct settings
char discord_app_id[PATH_MAX_LENGTH];
char ai_service_url[PATH_MAX_LENGTH];
char crt_switch_timings[255];
#ifdef HAVE_LAKKA
char timezone[TIMEZONE_LENGTH];
char cpu_main_gov[32];
char cpu_menu_gov[32];
#endif
char translation_service_url[2048]; /* TODO/FIXME - check size */
} arrays;
struct
@ -483,21 +527,52 @@ typedef struct settings
char netplay_password[128];
char netplay_spectate_password[128];
char netplay_server[255];
char netplay_custom_mitm_server[255];
char network_buildbot_url[255];
char network_buildbot_assets_url[255];
char streaming_title[512]; /* TODO/FIXME - check size */
char browse_url[4096];
char netplay_server[NAME_MAX_LENGTH];
char netplay_custom_mitm_server[NAME_MAX_LENGTH];
char network_buildbot_url[NAME_MAX_LENGTH];
char network_buildbot_assets_url[NAME_MAX_LENGTH];
char menu_content_show_settings_password[NAME_MAX_LENGTH];
char kiosk_mode_password[NAME_MAX_LENGTH];
char path_stream_url[8192];
char bundle_assets_dst_subdir[DIR_MAX_LENGTH];
char directory_audio_filter[DIR_MAX_LENGTH];
char directory_autoconfig[DIR_MAX_LENGTH];
char directory_video_filter[DIR_MAX_LENGTH];
char directory_video_shader[DIR_MAX_LENGTH];
char directory_libretro[DIR_MAX_LENGTH];
char directory_input_remapping[DIR_MAX_LENGTH];
char directory_overlay[DIR_MAX_LENGTH];
char directory_osk_overlay[DIR_MAX_LENGTH];
char directory_screenshot[DIR_MAX_LENGTH];
char directory_system[DIR_MAX_LENGTH];
char directory_cache[DIR_MAX_LENGTH];
char directory_playlist[DIR_MAX_LENGTH];
char directory_content_favorites[DIR_MAX_LENGTH];
char directory_content_history[DIR_MAX_LENGTH];
char directory_content_image_history[DIR_MAX_LENGTH];
char directory_content_music_history[DIR_MAX_LENGTH];
char directory_content_video_history[DIR_MAX_LENGTH];
char directory_runtime_log[DIR_MAX_LENGTH];
char directory_core_assets[DIR_MAX_LENGTH];
char directory_assets[DIR_MAX_LENGTH];
char directory_dynamic_wallpapers[DIR_MAX_LENGTH];
char directory_thumbnails[DIR_MAX_LENGTH];
char directory_menu_config[DIR_MAX_LENGTH];
char directory_menu_content[DIR_MAX_LENGTH];
#ifdef _3DS
char directory_bottom_assets[DIR_MAX_LENGTH];
#endif
char log_dir[DIR_MAX_LENGTH];
#ifdef HAVE_TEST_DRIVERS
char test_input_file_joypad[PATH_MAX_LENGTH];
char test_input_file_general[PATH_MAX_LENGTH];
#endif
char bundle_assets_src[PATH_MAX_LENGTH];
char bundle_assets_dst[PATH_MAX_LENGTH];
char bundle_assets_dst_subdir[PATH_MAX_LENGTH];
char path_menu_xmb_font[PATH_MAX_LENGTH];
char menu_content_show_settings_password[PATH_MAX_LENGTH];
char kiosk_mode_password[PATH_MAX_LENGTH];
char path_cheat_database[PATH_MAX_LENGTH];
char path_content_database[PATH_MAX_LENGTH];
char path_overlay[PATH_MAX_LENGTH];
@ -517,40 +592,12 @@ typedef struct settings
char path_cheat_settings[PATH_MAX_LENGTH];
char path_font[PATH_MAX_LENGTH];
char path_rgui_theme_preset[PATH_MAX_LENGTH];
char app_icon[PATH_MAX_LENGTH];
char directory_audio_filter[PATH_MAX_LENGTH];
char directory_autoconfig[PATH_MAX_LENGTH];
char directory_video_filter[PATH_MAX_LENGTH];
char directory_video_shader[PATH_MAX_LENGTH];
char directory_libretro[PATH_MAX_LENGTH];
char directory_input_remapping[PATH_MAX_LENGTH];
char directory_overlay[PATH_MAX_LENGTH];
char directory_osk_overlay[PATH_MAX_LENGTH];
char directory_resampler[PATH_MAX_LENGTH];
char directory_screenshot[PATH_MAX_LENGTH];
char directory_system[PATH_MAX_LENGTH];
char directory_cache[PATH_MAX_LENGTH];
char directory_playlist[PATH_MAX_LENGTH];
char directory_content_favorites[PATH_MAX_LENGTH];
char directory_content_history[PATH_MAX_LENGTH];
char directory_content_image_history[PATH_MAX_LENGTH];
char directory_content_music_history[PATH_MAX_LENGTH];
char directory_content_video_history[PATH_MAX_LENGTH];
char directory_runtime_log[PATH_MAX_LENGTH];
char directory_core_assets[PATH_MAX_LENGTH];
char directory_assets[PATH_MAX_LENGTH];
char directory_dynamic_wallpapers[PATH_MAX_LENGTH];
char directory_thumbnails[PATH_MAX_LENGTH];
char directory_menu_config[PATH_MAX_LENGTH];
char directory_menu_content[PATH_MAX_LENGTH];
char streaming_title[PATH_MAX_LENGTH];
#ifdef _3DS
char directory_bottom_assets[PATH_MAX_LENGTH];
#endif
char log_dir[PATH_MAX_LENGTH];
char browse_url[4096]; /* TODO/FIXME - check size */
char path_stream_url[8192]; /* TODO/FIXME - check size */
} paths;
bool modified;
struct
{
@ -572,11 +619,11 @@ typedef struct settings
bool video_aspect_ratio_auto;
bool video_dingux_ipu_keep_aspect;
bool video_scale_integer;
bool video_scale_integer_overscale;
bool video_shader_enable;
bool video_shader_watch_files;
bool video_shader_remember_last_dir;
bool video_shader_preset_save_reference_enable;
bool video_scan_subframes;
bool video_threaded;
bool video_font_enable;
bool video_disable_composition;
@ -612,10 +659,16 @@ typedef struct settings
bool audio_enable_menu_scroll;
bool audio_sync;
bool audio_rate_control;
bool audio_wasapi_exclusive_mode;
bool audio_wasapi_float_format;
bool audio_fastforward_mute;
bool audio_fastforward_speedup;
#ifdef IOS
bool audio_respect_silent_mode;
#endif
#ifdef HAVE_WASAPI
bool audio_wasapi_exclusive_mode;
bool audio_wasapi_float_format;
#endif
#ifdef HAVE_MICROPHONE
/* Microphone */
@ -628,6 +681,7 @@ typedef struct settings
/* Input */
bool input_remap_binds_enable;
bool input_remap_sort_by_controller_enable;
bool input_autodetect_enable;
bool input_sensors_enable;
bool input_overlay_enable;
@ -639,6 +693,11 @@ typedef struct settings
bool input_overlay_auto_rotate;
bool input_overlay_auto_scale;
bool input_osk_overlay_auto_scale;
bool input_overlay_pointer_enable;
bool input_overlay_lightgun_trigger_on_touch;
bool input_overlay_lightgun_allow_offscreen;
bool input_overlay_mouse_hold_to_drag;
bool input_overlay_mouse_dtap_to_drag;
bool input_descriptor_label_show;
bool input_descriptor_hide_unbound;
bool input_all_users_control_menu;
@ -649,6 +708,8 @@ typedef struct settings
bool input_small_keyboard_enable;
bool input_keyboard_gamepad_enable;
bool input_auto_mouse_grab;
bool input_allow_turbo_dpad;
bool input_hotkey_device_merge;
#if defined(HAVE_DINPUT) || defined(HAVE_WINRAWINPUT)
bool input_nowinkey_enable;
#endif
@ -675,6 +736,8 @@ typedef struct settings
bool notification_show_remap_load;
bool notification_show_config_override_load;
bool notification_show_set_initial_disk;
bool notification_show_disk_control;
bool notification_show_save_state;
bool notification_show_fast_forward;
#ifdef HAVE_SCREENSHOTS
bool notification_show_screenshot;
@ -694,13 +757,11 @@ typedef struct settings
bool menu_core_enable;
bool menu_show_sublabels;
bool menu_dynamic_wallpaper_enable;
bool menu_throttle;
bool menu_mouse_enable;
bool menu_pointer_enable;
bool menu_navigation_wraparound_enable;
bool menu_navigation_browser_filter_supported_extensions_enable;
bool menu_show_advanced_settings;
bool menu_throttle_framerate;
bool menu_linear_filter;
bool menu_horizontal_animation;
bool menu_scroll_fast;
@ -726,7 +787,10 @@ typedef struct settings
bool menu_show_latency;
bool menu_show_rewind;
bool menu_show_overlays;
#if 0
/* Thumbnailpack removal */
bool menu_show_legacy_thumbnail_updater;
#endif
bool menu_materialui_icons_enable;
bool menu_materialui_playlist_icons_enable;
bool menu_materialui_switch_icons;
@ -764,6 +828,8 @@ typedef struct settings
bool menu_unified_controls;
bool menu_disable_info_button;
bool menu_disable_search_button;
bool menu_disable_left_analog;
bool menu_disable_right_analog;
bool menu_ticker_smooth;
bool settings_show_drivers;
bool settings_show_video;
@ -799,6 +865,7 @@ typedef struct settings
bool quick_menu_show_replay;
bool quick_menu_show_undo_save_load_state;
bool quick_menu_show_add_to_favorites;
bool quick_menu_show_add_to_playlist;
bool quick_menu_show_start_recording;
bool quick_menu_show_start_streaming;
bool quick_menu_show_set_core_association;
@ -899,6 +966,14 @@ typedef struct settings
bool steam_rich_presence_enable;
#endif
/* Cloud Sync */
bool cloud_sync_enable;
bool cloud_sync_destructive;
bool cloud_sync_sync_saves;
bool cloud_sync_sync_configs;
bool cloud_sync_sync_thumbs;
bool cloud_sync_sync_system;
/* Misc. */
bool discord_enable;
bool threaded_data_runloop_enable;
@ -909,13 +984,13 @@ typedef struct settings
bool rewind_enable;
bool fastforward_frameskip;
bool vrr_runloop_enable;
bool menu_throttle_framerate;
bool apply_cheats_after_toggle;
bool apply_cheats_after_load;
bool run_ahead_enabled;
bool run_ahead_secondary_instance;
bool run_ahead_hide_warnings;
bool preemptive_frames_enable;
bool preemptive_frames_hide_warnings;
bool pause_nonactive;
bool pause_on_disconnect;
bool block_sram_overwrite;
@ -943,6 +1018,7 @@ typedef struct settings
bool game_specific_options;
bool auto_overrides_enable;
bool auto_remaps_enable;
bool initial_disk_change_enable;
bool global_core_options;
bool auto_shaders_enable;
@ -961,6 +1037,11 @@ typedef struct settings
bool screenshots_in_content_dir;
bool systemfiles_in_content_dir;
bool ssh_enable;
#ifdef HAVE_LAKKA_SWITCH
bool switch_oc;
bool switch_cec;
bool bluetooth_ertm_disable;
#endif
bool samba_enable;
bool bluetooth_enable;
bool localap_enable;
@ -980,6 +1061,8 @@ typedef struct settings
bool playlist_show_entry_idx;
bool playlist_fuzzy_archive_match;
bool playlist_portable_paths;
bool playlist_use_filename;
bool playlist_allow_non_png;
bool quit_press_twice;
bool vibrate_on_keypress;
@ -993,6 +1076,7 @@ typedef struct settings
bool log_to_file_timestamp;
bool scan_without_core_match;
bool scan_serial_and_crc;
bool ai_service_enable;
bool ai_service_pause;
@ -1007,11 +1091,13 @@ typedef struct settings
bool android_input_disconnect_workaround;
#endif
#if defined(HAVE_COCOATOUCH) && defined(TARGET_OS_TV)
#if defined(HAVE_COCOATOUCH)
bool gcdwebserver_alert;
#endif
} bools;
uint8_t flags;
} settings_t;
/**
@ -1166,6 +1252,16 @@ bool config_unload_override(void);
bool config_load_remap(const char *directory_input_remapping,
void *data);
/**
* config_get_autoconf_profile_filename:
* @device_name : Input device name
* @user : Controller number to save
* Fills buf with the autoconf profile file name (including driver dir if needed).
**/
void config_get_autoconf_profile_filename(
const char *device_name, unsigned user,
char *buf, size_t len_buf);
/**
* config_save_autoconf_profile:
* @device_name : Input device name
@ -1192,7 +1288,8 @@ bool config_save_file(const char *path);
*
* Returns: true (1) on success, (-1) if nothing to write, otherwise returns false (0).
**/
int8_t config_save_overrides(enum override_type type, void *data, bool remove);
int8_t config_save_overrides(enum override_type type,
void *data, bool remove, const char *path);
/* Replaces currently loaded configuration file with
* another one. Will load a dummy core to flush state

View File

@ -39,12 +39,6 @@ typedef struct content_ctx_info
int argc; /* Argument count. */
} content_ctx_info_t;
/* Load a RAM state from disk to memory. */
bool content_load_ram_file(unsigned slot);
/* Save a RAM state from memory to disk. */
bool content_save_ram_file(unsigned slot, bool compress);
/* Load a state from memory. */
bool content_load_state_from_ram(void);
@ -58,7 +52,10 @@ bool content_ram_state_to_file(const char *path);
bool content_load_state(const char* path, bool load_to_backup_buffer, bool autoload);
/* Save a state from memory to disk. */
bool content_save_state(const char *path, bool save_to_disk, bool autosave);
bool content_save_state(const char *path, bool save_to_disk);
/* Save an automatic savestate to disk. */
bool content_auto_save_state(const char *path);
/* Check a ram state write to disk. */
bool content_ram_state_pending(void);

View File

@ -51,9 +51,9 @@ static bool core_backup_get_backup_dir(
const char *core_filename,
char *backup_dir, size_t len)
{
char *last_underscore = NULL;
char core_file_id[PATH_MAX_LENGTH];
char tmp[PATH_MAX_LENGTH];
char core_file_id[NAME_MAX_LENGTH];
char *last_underscore = NULL;
/* Extract core file 'ID' (name without extension + suffix)
* from core path */
@ -86,7 +86,7 @@ static bool core_backup_get_backup_dir(
* core directory as a base */
fill_pathname_join_special(tmp,
string_is_empty(dir_core_assets)
? dir_libretro
? dir_libretro
: dir_core_assets,
"core_backups", sizeof(tmp));
@ -120,8 +120,8 @@ bool core_backup_get_backup_path(
time_t current_time;
struct tm time_info;
const char *core_filename = NULL;
char core_dir[PATH_MAX_LENGTH];
char backup_dir[PATH_MAX_LENGTH];
char core_dir[DIR_MAX_LENGTH];
char backup_dir[DIR_MAX_LENGTH];
char backup_filename[PATH_MAX_LENGTH];
backup_dir[0] = '\0';
@ -174,11 +174,9 @@ bool core_backup_get_backup_path(
/* Returns detected type of specified core backup file */
enum core_backup_type core_backup_get_backup_type(const char *backup_path)
{
char core_ext[16];
const char *backup_ext = NULL;
struct string_list *metadata_list = NULL;
char core_ext[255];
core_ext[0] = '\0';
if (string_is_empty(backup_path) || !path_is_valid(backup_path))
goto error;
@ -224,7 +222,7 @@ enum core_backup_type core_backup_get_backup_type(const char *backup_path)
string_list_free(metadata_list);
metadata_list = NULL;
return CORE_BACKUP_TYPE_ARCHIVE;
}
@ -246,11 +244,11 @@ error:
* Returns true if successful */
bool core_backup_get_backup_crc(char *backup_path, uint32_t *crc)
{
struct string_list *metadata_list = NULL;
enum core_backup_type backup_type;
struct string_list *metadata_list = NULL;
if (string_is_empty(backup_path) || !crc)
goto error;
return false;
/* Get backup type */
backup_type = core_backup_get_backup_type(backup_path);
@ -342,69 +340,64 @@ enum core_backup_type core_backup_get_core_path(
char *core_path, size_t len)
{
const char *backup_filename = NULL;
char *core_filename = NULL;
enum core_backup_type backup_type = CORE_BACKUP_TYPE_INVALID;
if (string_is_empty(backup_path) || string_is_empty(dir_libretro))
return backup_type;
return CORE_BACKUP_TYPE_INVALID;
backup_filename = path_basename(backup_path);
if (string_is_empty(backup_filename))
return backup_type;
/* Check backup type */
switch (core_backup_get_backup_type(backup_path))
if (!string_is_empty(backup_filename))
{
case CORE_BACKUP_TYPE_ARCHIVE:
{
char *period = NULL;
/* Check backup type */
switch (core_backup_get_backup_type(backup_path))
{
case CORE_BACKUP_TYPE_ARCHIVE:
{
/* This is an archived backup with timestamp/crc
* metadata in the filename */
char *core_filename = strdup(backup_filename);
/* Find the location of the second period */
char *period = strchr(core_filename, '.');
if (!period || (*(++period) == '\0'))
{
free(core_filename);
break;
}
/* This is an archived backup with timestamp/crc
* metadata in the filename */
core_filename = strdup(backup_filename);
if (!(period = strchr(period, '.')))
{
free(core_filename);
break;
}
/* Find the location of the second period */
period = strchr(core_filename, '.');
if (!period || (*(++period) == '\0'))
break;
/* Trim everything after (and including) the
* second period */
*period = '\0';
period = strchr(period, '.');
if (!period)
break;
if (string_is_empty(core_filename))
{
free(core_filename);
break;
}
/* Trim everything after (and including) the
* second period */
*period = '\0';
if (string_is_empty(core_filename))
break;
/* All good - build core path */
/* All good - build core path */
fill_pathname_join_special(core_path, dir_libretro,
core_filename, len);
free(core_filename);
}
return CORE_BACKUP_TYPE_ARCHIVE;
case CORE_BACKUP_TYPE_LIB:
/* This is a plain dynamic library file */
fill_pathname_join_special(core_path, dir_libretro,
core_filename, len);
backup_type = CORE_BACKUP_TYPE_ARCHIVE;
}
break;
case CORE_BACKUP_TYPE_LIB:
/* This is a plain dynamic library file */
fill_pathname_join_special(core_path, dir_libretro,
backup_filename, len);
backup_type = CORE_BACKUP_TYPE_LIB;
break;
default:
/* Backup is invalid */
break;
backup_filename, len);
return CORE_BACKUP_TYPE_LIB;
default:
/* Backup is invalid */
break;
}
}
if (core_filename)
{
free(core_filename);
core_filename = NULL;
}
return backup_type;
return CORE_BACKUP_TYPE_INVALID;
}
/*************************/
@ -428,7 +421,7 @@ static bool core_backup_add_entry(core_backup_list_t *backup_list,
|| string_is_empty(core_filename)
|| string_is_empty(backup_path)
|| (backup_list->size >= backup_list->capacity))
goto error;
return false;
backup_filename = strdup(path_basename(backup_path));
@ -484,10 +477,10 @@ core_backup_list_t *core_backup_list_init(
struct string_list *dir_list = NULL;
core_backup_list_t *backup_list = NULL;
core_backup_list_entry_t *entries = NULL;
char core_dir[PATH_MAX_LENGTH];
char backup_dir[PATH_MAX_LENGTH];
char core_dir[DIR_MAX_LENGTH];
char backup_dir[DIR_MAX_LENGTH];
core_dir[0] = '\0';
core_dir[0] = '\0';
backup_dir[0] = '\0';
/* Get core filename and parent directory */
@ -531,9 +524,7 @@ core_backup_list_t *core_backup_list_init(
dir_list_sort(dir_list, true);
/* Create core backup list */
backup_list = (core_backup_list_t*)malloc(sizeof(*backup_list));
if (!backup_list)
if (!(backup_list = (core_backup_list_t*)malloc(sizeof(*backup_list))))
goto error;
backup_list->entries = NULL;
@ -544,10 +535,8 @@ core_backup_list_t *core_backup_list_init(
* (Note: Set this to the full size of the directory
* list - this may be larger than we need, but saves
* many inefficiencies later) */
entries = (core_backup_list_entry_t*)
calloc(dir_list->size, sizeof(*entries));
if (!entries)
if (!(entries = (core_backup_list_entry_t*)
calloc(dir_list->size, sizeof(*entries))))
goto error;
backup_list->entries = entries;
@ -697,48 +686,3 @@ bool core_backup_list_get_crc(
return false;
}
/* Fetches a string representation of a backup
* list entry timestamp.
* Returns false in the event of an error */
bool core_backup_list_get_entry_timestamp_str(
const core_backup_list_entry_t *entry,
enum core_backup_date_separator_type date_separator,
char *timestamp, size_t len)
{
const char *format_str = "%04u-%02u-%02u %02u:%02u:%02u";
if (!entry || (len < 20))
return false;
/* Get time format string */
if (date_separator == CORE_BACKUP_DATE_SEPARATOR_SLASH)
format_str = "%04u/%02u/%02u %02u:%02u:%02u";
else if (date_separator == CORE_BACKUP_DATE_SEPARATOR_PERIOD)
format_str = "%04u.%02u.%02u %02u:%02u:%02u";
snprintf(timestamp, len,
format_str,
entry->date.year,
entry->date.month,
entry->date.day,
entry->date.hour,
entry->date.minute,
entry->date.second);
return true;
}
/* Fetches a string representation of a backup
* list entry crc value.
* Returns false in the event of an error */
bool core_backup_list_get_entry_crc_str(
const core_backup_list_entry_t *entry,
char *crc, size_t len)
{
if (!entry || (len < 9))
return false;
snprintf(crc, len, "%08lx", (unsigned long)entry->crc);
return true;
}

View File

@ -157,21 +157,6 @@ bool core_backup_list_get_crc(
uint32_t crc, enum core_backup_mode backup_mode,
const core_backup_list_entry_t **entry);
/* Fetches a string representation of a backup
* list entry timestamp.
* Returns false in the event of an error */
bool core_backup_list_get_entry_timestamp_str(
const core_backup_list_entry_t *entry,
enum core_backup_date_separator_type date_separator,
char *timestamp, size_t len);
/* Fetches a string representation of a backup
* list entry crc value.
* Returns false in the event of an error */
bool core_backup_list_get_entry_crc_str(
const core_backup_list_entry_t *entry,
char *crc, size_t len);
RETRO_END_DECLS
#endif

View File

@ -104,153 +104,158 @@ static bool CCJSONObjectMemberHandler(void *context,
{
CCJSONContext *pCtx = (CCJSONContext *)context;
if ( (pCtx->object_depth == 2)
&& (pCtx->array_depth == 1)
&& length)
if (length)
{
pCtx->current_string_val = NULL;
pCtx->current_string_list_val = NULL;
pCtx->current_entry_uint_val = NULL;
pCtx->current_entry_bool_val = NULL;
pCtx->to_core_file_id = false;
pCtx->to_firmware = false;
switch (pValue[0])
switch (pCtx->array_depth)
{
case 'a':
if (string_is_equal(pValue, "authors"))
case 0:
if (pCtx->object_depth == 1)
{
pCtx->current_string_val = &pCtx->core_info->authors;
pCtx->current_string_list_val = &pCtx->core_info->authors_list;
pCtx->current_string_val = NULL;
if (string_is_equal(pValue, "version"))
pCtx->current_string_val = &pCtx->core_info_cache_list->version;
}
break;
case 'c':
if (string_is_equal(pValue, "categories"))
case 1:
if (pCtx->object_depth == 2)
{
pCtx->current_string_val = &pCtx->core_info->categories;
pCtx->current_string_list_val = &pCtx->core_info->categories_list;
pCtx->current_string_val = NULL;
pCtx->current_string_list_val = NULL;
pCtx->current_entry_uint_val = NULL;
pCtx->current_entry_bool_val = NULL;
pCtx->to_core_file_id = false;
pCtx->to_firmware = false;
switch (pValue[0])
{
case 'a':
if (string_is_equal(pValue, "authors"))
{
pCtx->current_string_val = &pCtx->core_info->authors;
pCtx->current_string_list_val = &pCtx->core_info->authors_list;
}
break;
case 'c':
if (string_is_equal(pValue, "categories"))
{
pCtx->current_string_val = &pCtx->core_info->categories;
pCtx->current_string_list_val = &pCtx->core_info->categories_list;
}
else if (string_is_equal(pValue, "core_name"))
pCtx->current_string_val = &pCtx->core_info->core_name;
else if (string_is_equal(pValue, "core_file_id"))
pCtx->to_core_file_id = true;
break;
case 'd':
if (string_is_equal(pValue, "display_name"))
pCtx->current_string_val = &pCtx->core_info->display_name;
else if (string_is_equal(pValue, "display_version"))
pCtx->current_string_val = &pCtx->core_info->display_version;
else if (string_is_equal(pValue, "databases"))
{
pCtx->current_string_val = &pCtx->core_info->databases;
pCtx->current_string_list_val = &pCtx->core_info->databases_list;
}
else if (string_is_equal(pValue, "description"))
pCtx->current_string_val = &pCtx->core_info->description;
else if (string_is_equal(pValue, "database_match_archive_member"))
pCtx->current_entry_bool_val = &pCtx->core_info->database_match_archive_member;
break;
case 'f':
if (string_is_equal(pValue, "firmware"))
pCtx->to_firmware = true;
break;
case 'h':
if (string_is_equal(pValue, "has_info"))
pCtx->current_entry_bool_val = &pCtx->core_info->has_info;
break;
case 'l':
if (string_is_equal(pValue, "licenses"))
{
pCtx->current_string_val = &pCtx->core_info->licenses;
pCtx->current_string_list_val = &pCtx->core_info->licenses_list;
}
else if (string_is_equal(pValue, "is_experimental"))
pCtx->current_entry_bool_val = &pCtx->core_info->is_experimental;
break;
case 'n':
if (string_is_equal(pValue, "notes"))
{
pCtx->current_string_val = &pCtx->core_info->notes;
pCtx->current_string_list_val = &pCtx->core_info->note_list;
}
break;
case 'p':
if (string_is_equal(pValue, "permissions"))
{
pCtx->current_string_val = &pCtx->core_info->permissions;
pCtx->current_string_list_val = &pCtx->core_info->permissions_list;
}
break;
case 'r':
if (string_is_equal(pValue, "required_hw_api"))
{
pCtx->current_string_val = &pCtx->core_info->required_hw_api;
pCtx->current_string_list_val = &pCtx->core_info->required_hw_api_list;
}
break;
case 's':
if (string_is_equal(pValue, "system_manufacturer"))
pCtx->current_string_val = &pCtx->core_info->system_manufacturer;
else if (string_is_equal(pValue, "systemname"))
pCtx->current_string_val = &pCtx->core_info->systemname;
else if (string_is_equal(pValue, "system_id"))
pCtx->current_string_val = &pCtx->core_info->system_id;
else if (string_is_equal(pValue, "supported_extensions"))
{
pCtx->current_string_val = &pCtx->core_info->supported_extensions;
pCtx->current_string_list_val = &pCtx->core_info->supported_extensions_list;
}
else if (string_is_equal(pValue, "supports_no_game"))
pCtx->current_entry_bool_val = &pCtx->core_info->supports_no_game;
else if (string_is_equal(pValue, "single_purpose"))
pCtx->current_entry_bool_val = &pCtx->core_info->single_purpose;
else if (string_is_equal(pValue, "savestate_support_level"))
pCtx->current_entry_uint_val = &pCtx->core_info->savestate_support_level;
break;
}
}
else if (string_is_equal(pValue, "core_name"))
pCtx->current_string_val = &pCtx->core_info->core_name;
else if (string_is_equal(pValue, "core_file_id"))
pCtx->to_core_file_id = true;
break;
case 'd':
if (string_is_equal(pValue, "display_name"))
pCtx->current_string_val = &pCtx->core_info->display_name;
else if (string_is_equal(pValue, "display_version"))
pCtx->current_string_val = &pCtx->core_info->display_version;
else if (string_is_equal(pValue, "databases"))
else if (pCtx->object_depth == 3)
{
pCtx->current_string_val = &pCtx->core_info->databases;
pCtx->current_string_list_val = &pCtx->core_info->databases_list;
}
else if (string_is_equal(pValue, "description"))
pCtx->current_string_val = &pCtx->core_info->description;
else if (string_is_equal(pValue, "database_match_archive_member"))
pCtx->current_entry_bool_val = &pCtx->core_info->database_match_archive_member;
break;
case 'f':
if (string_is_equal(pValue, "firmware"))
pCtx->to_firmware = true;
break;
case 'h':
if (string_is_equal(pValue, "has_info"))
pCtx->current_entry_bool_val = &pCtx->core_info->has_info;
break;
case 'l':
if (string_is_equal(pValue, "licenses"))
{
pCtx->current_string_val = &pCtx->core_info->licenses;
pCtx->current_string_list_val = &pCtx->core_info->licenses_list;
}
else if (string_is_equal(pValue, "is_experimental"))
pCtx->current_entry_bool_val = &pCtx->core_info->is_experimental;
break;
case 'n':
if (string_is_equal(pValue, "notes"))
{
pCtx->current_string_val = &pCtx->core_info->notes;
pCtx->current_string_list_val = &pCtx->core_info->note_list;
pCtx->current_string_val = NULL;
pCtx->current_entry_uint_val = NULL;
if (pCtx->to_core_file_id)
{
if (string_is_equal(pValue, "str"))
pCtx->current_string_val = &pCtx->core_info->core_file_id.str;
else if (string_is_equal(pValue, "hash"))
pCtx->current_entry_uint_val = &pCtx->core_info->core_file_id.hash;
}
}
break;
case 'p':
if (string_is_equal(pValue, "permissions"))
case 2:
if (pCtx->object_depth == 3)
{
pCtx->current_string_val = &pCtx->core_info->permissions;
pCtx->current_string_list_val = &pCtx->core_info->permissions_list;
pCtx->current_string_val = NULL;
pCtx->current_entry_bool_val = NULL;
if (pCtx->to_firmware && (pCtx->core_info->firmware_count > 0))
{
size_t firmware_idx = pCtx->core_info->firmware_count - 1;
if (string_is_equal(pValue, "path"))
pCtx->current_string_val = &pCtx->core_info->firmware[firmware_idx].path;
else if (string_is_equal(pValue, "desc"))
pCtx->current_string_val = &pCtx->core_info->firmware[firmware_idx].desc;
else if (string_is_equal(pValue, "optional"))
pCtx->current_entry_bool_val = &pCtx->core_info->firmware[firmware_idx].optional;
}
}
break;
case 'r':
if (string_is_equal(pValue, "required_hw_api"))
{
pCtx->current_string_val = &pCtx->core_info->required_hw_api;
pCtx->current_string_list_val = &pCtx->core_info->required_hw_api_list;
}
break;
case 's':
if (string_is_equal(pValue, "system_manufacturer"))
pCtx->current_string_val = &pCtx->core_info->system_manufacturer;
else if (string_is_equal(pValue, "systemname"))
pCtx->current_string_val = &pCtx->core_info->systemname;
else if (string_is_equal(pValue, "system_id"))
pCtx->current_string_val = &pCtx->core_info->system_id;
else if (string_is_equal(pValue, "supported_extensions"))
{
pCtx->current_string_val = &pCtx->core_info->supported_extensions;
pCtx->current_string_list_val = &pCtx->core_info->supported_extensions_list;
}
else if (string_is_equal(pValue, "supports_no_game"))
pCtx->current_entry_bool_val = &pCtx->core_info->supports_no_game;
else if (string_is_equal(pValue, "single_purpose"))
pCtx->current_entry_bool_val = &pCtx->core_info->single_purpose;
else if (string_is_equal(pValue, "savestate_support_level"))
pCtx->current_entry_uint_val = &pCtx->core_info->savestate_support_level;
break;
}
}
else if ( (pCtx->object_depth == 3)
&& (pCtx->array_depth == 1)
&& length)
{
pCtx->current_string_val = NULL;
pCtx->current_entry_uint_val = NULL;
if (pCtx->to_core_file_id)
{
if (string_is_equal(pValue, "str"))
pCtx->current_string_val = &pCtx->core_info->core_file_id.str;
else if (string_is_equal(pValue, "hash"))
pCtx->current_entry_uint_val = &pCtx->core_info->core_file_id.hash;
}
}
else if ( (pCtx->object_depth == 3)
&& (pCtx->array_depth == 2)
&& length)
{
pCtx->current_string_val = NULL;
pCtx->current_entry_bool_val = NULL;
if (pCtx->to_firmware && (pCtx->core_info->firmware_count > 0))
{
size_t firmware_idx = pCtx->core_info->firmware_count - 1;
if (string_is_equal(pValue, "path"))
pCtx->current_string_val = &pCtx->core_info->firmware[firmware_idx].path;
else if (string_is_equal(pValue, "desc"))
pCtx->current_string_val = &pCtx->core_info->firmware[firmware_idx].desc;
else if (string_is_equal(pValue, "optional"))
pCtx->current_entry_bool_val = &pCtx->core_info->firmware[firmware_idx].optional;
}
}
else if ( (pCtx->object_depth == 1)
&& (pCtx->array_depth == 0)
&& length)
{
pCtx->current_string_val = NULL;
if (string_is_equal(pValue, "version"))
pCtx->current_string_val = &pCtx->core_info_cache_list->version;
}
return true;
@ -261,8 +266,8 @@ static bool CCJSONStringHandler(void *context,
{
CCJSONContext *pCtx = (CCJSONContext*)context;
if ( pCtx->current_string_val
&& length
if ( pCtx->current_string_val
&& length
&& !string_is_empty(pValue))
{
if (*pCtx->current_string_val)
@ -273,7 +278,7 @@ static bool CCJSONStringHandler(void *context,
{
if (*pCtx->current_string_list_val)
string_list_free(*pCtx->current_string_list_val);
*pCtx->current_string_list_val =
*pCtx->current_string_list_val =
string_split(*pCtx->current_string_val, "|");
}
}
@ -315,56 +320,60 @@ static bool CCJSONStartObjectHandler(void *context)
pCtx->object_depth++;
if ( (pCtx->object_depth == 1)
&& (pCtx->array_depth == 0))
switch (pCtx->array_depth)
{
if (pCtx->core_info_cache_list)
return false;
if (!(pCtx->core_info_cache_list = core_info_cache_list_new()))
return false;
}
else if ((pCtx->object_depth == 2)
&& (pCtx->array_depth == 1))
{
if (pCtx->core_info)
{
core_info_free(pCtx->core_info);
free(pCtx->core_info);
pCtx->core_info = NULL;
}
case 0:
if (pCtx->object_depth == 1)
{
if (pCtx->core_info_cache_list)
return false;
if (!(pCtx->core_info_cache_list = core_info_cache_list_new()))
return false;
}
break;
case 1:
if (pCtx->object_depth == 2)
{
if (pCtx->core_info)
{
core_info_free(pCtx->core_info);
free(pCtx->core_info);
pCtx->core_info = NULL;
}
if (!(pCtx->core_info = (core_info_t*)calloc(1, sizeof(core_info_t))))
return false;
if (!(pCtx->core_info = (core_info_t*)calloc(1, sizeof(core_info_t))))
return false;
/* Assume all cores have 'full' savestate support
* by default */
pCtx->core_info->savestate_support_level =
CORE_INFO_SAVESTATE_DETERMINISTIC;
}
else if ((pCtx->object_depth == 3)
&& (pCtx->array_depth == 2))
{
if (pCtx->to_firmware)
{
size_t new_idx = pCtx->core_info->firmware_count;
core_info_firmware_t *tmp = (core_info_firmware_t*)
/* Assume all cores have 'full' savestate support
* by default */
pCtx->core_info->savestate_support_level =
CORE_INFO_SAVESTATE_DETERMINISTIC;
}
break;
case 2:
if (pCtx->object_depth == 3 && pCtx->to_firmware)
{
size_t new_idx = pCtx->core_info->firmware_count;
core_info_firmware_t *tmp = (core_info_firmware_t*)
realloc(pCtx->core_info->firmware,
(pCtx->core_info->firmware_count + 1)
(pCtx->core_info->firmware_count + 1)
* sizeof(core_info_firmware_t));
if (!tmp)
return false;
if (!tmp)
return false;
tmp[new_idx].path = NULL;
tmp[new_idx].desc = NULL;
tmp[new_idx].missing = false;
tmp[new_idx].optional = false;
tmp[new_idx].path = NULL;
tmp[new_idx].desc = NULL;
tmp[new_idx].missing = false;
tmp[new_idx].optional = false;
pCtx->core_info->firmware = tmp;
pCtx->core_info->firmware_count++;
}
pCtx->core_info->firmware = tmp;
pCtx->core_info->firmware_count++;
}
break;
}
return true;
}
@ -372,18 +381,26 @@ static bool CCJSONEndObjectHandler(void *context)
{
CCJSONContext *pCtx = (CCJSONContext*)context;
if ( (pCtx->object_depth == 2)
&& (pCtx->array_depth == 1)
&& (pCtx->core_info))
if (pCtx->array_depth == 1)
{
core_info_cache_add(
pCtx->core_info_cache_list, pCtx->core_info, true);
free(pCtx->core_info);
pCtx->core_info = NULL;
switch (pCtx->object_depth)
{
case 2:
if (pCtx->core_info)
{
core_info_cache_add(
pCtx->core_info_cache_list, pCtx->core_info, true);
free(pCtx->core_info);
pCtx->core_info = NULL;
}
break;
case 3:
pCtx->to_core_file_id = false;
break;
default:
break;
}
}
else if ((pCtx->object_depth == 3)
&& (pCtx->array_depth == 1))
pCtx->to_core_file_id = false;
pCtx->object_depth--;
@ -465,7 +482,7 @@ static void core_info_copy(core_info_t *src, core_info_t *dst)
dst->firmware_count = 0;
}
dst->core_file_id.str = src->core_file_id.str
dst->core_file_id.str = src->core_file_id.str
? strdup(src->core_file_id.str) : NULL;
dst->core_file_id.hash = src->core_file_id.hash;
@ -670,7 +687,7 @@ static void core_info_cache_add(
#ifdef HAVE_CORE_INFO_CACHE
static core_info_cache_list_t *core_info_cache_list_new(void)
{
core_info_cache_list_t *core_info_cache_list =
core_info_cache_list_t *core_info_cache_list =
(core_info_cache_list_t *)malloc(sizeof(*core_info_cache_list));
if (!core_info_cache_list)
return NULL;
@ -737,7 +754,7 @@ static core_info_cache_list_t *core_info_cache_read(const char *info_dir)
/* Parse info cache file */
if (!(parser = rjson_open_stream(file)))
{
RARCH_ERR("[Core Info] Failed to create JSON parser\n");
RARCH_ERR("[Core Info]: Failed to create JSON parser.\n");
goto end;
}
@ -759,14 +776,14 @@ static core_info_cache_list_t *core_info_cache_read(const char *info_dir)
NULL) /* Unused null handler */
!= RJSON_DONE)
{
RARCH_WARN("[Core Info] Error parsing chunk:\n---snip---\n%.*s\n---snip---\n",
RARCH_WARN("[Core Info]: Error parsing chunk:\n---snip---\n%.*s\n---snip---\n",
rjson_get_source_context_len(parser),
rjson_get_source_context_buf(parser));
RARCH_WARN("[Core Info] Error: Invalid JSON at line %d, column %d - %s.\n",
RARCH_WARN("[Core Info]: Error: Invalid JSON at line %d, column %d - %s.\n",
(int)rjson_get_source_line(parser),
(int)rjson_get_source_column(parser),
(*rjson_get_error(parser)
? rjson_get_error(parser)
(*rjson_get_error(parser)
? rjson_get_error(parser)
: "format error"));
/* Info cache is corrupt - discard it */
@ -795,8 +812,8 @@ static core_info_cache_list_t *core_info_cache_read(const char *info_dir)
|| !string_is_equal(core_info_cache_list->version,
CORE_INFO_CACHE_VERSION))
{
RARCH_WARN("[Core Info] Core info cache has invalid version"
" - forcing refresh (required v%s, found v%s)\n",
RARCH_WARN("[Core Info]: Core info cache has invalid version"
" - forcing refresh (required v%s, found v%s).\n",
CORE_INFO_CACHE_VERSION,
core_info_cache_list->version);
@ -842,14 +859,14 @@ static bool core_info_cache_write(core_info_cache_list_t *list, const char *info
if (!file)
{
RARCH_ERR("[Core Info] Failed to write to core info cache file: %s\n", file_path);
RARCH_ERR("[Core Info]: Failed to write core info cache file: \"%s\".\n", file_path);
return false;
}
/* Write info cache */
if (!(writer = rjsonwriter_open_stream(file)))
{
RARCH_ERR("[Core Info] Failed to create JSON writer\n");
RARCH_ERR("[Core Info]: Failed to create JSON writer.\n");
goto end;
}
@ -1172,7 +1189,7 @@ static bool core_info_cache_write(core_info_cache_list_t *list, const char *info
rjsonwriter_raw(writer, "\n", 1);
rjsonwriter_free(writer);
RARCH_LOG("[Core Info] Wrote to cache file: %s\n", file_path);
RARCH_LOG("[Core Info]: Wrote to cache file: \"%s\".\n", file_path);
success = true;
/* Remove 'force refresh' file, if required */
@ -1368,7 +1385,7 @@ static core_path_list_t *core_info_path_list_new(const char *core_dir,
calloc(1, sizeof(*path_list->standalone_exempt_list));
if ( !path_list->dir_list
|| !path_list->core_list
|| !path_list->core_list
|| !path_list->lock_list
|| !path_list->standalone_exempt_list)
goto error;
@ -1421,7 +1438,7 @@ static core_path_list_t *core_info_path_list_new(const char *core_dir,
sizeof(*path_list->standalone_exempt_list->list));
if ( !path_list->core_list->list
|| !path_list->lock_list->list
|| !path_list->lock_list->list
|| !path_list->standalone_exempt_list->list)
goto error;
@ -1552,6 +1569,15 @@ static bool core_info_get_file_id(const char *core_filename,
/* > Remove extension */
strlcpy(core_file_id, core_filename, len);
path_remove_extension(core_file_id);
#if defined(IOS) || defined(OSX)
/* iOS framework names, to quote Apple:
* "must contain only alphanumerics, dots, hyphens and must not end with a dot."
*
* Since core names include underscore, which is not allowed, but not dot,
* which is, we change underscore to dot. Here, we need to change it back.
*/
string_replace_all_chars(core_file_id, '.', '_');
#endif
/* > Remove suffix */
last_underscore = (char*)strrchr(core_file_id, '_');
@ -1890,12 +1916,13 @@ static void core_info_list_resolve_all_extensions(
for (i = 0; i < core_info_list->count; i++)
{
size_t _len;
if (!core_info_list->list[i].supported_extensions)
continue;
strlcat(core_info_list->all_ext,
_len = strlcat(core_info_list->all_ext,
core_info_list->list[i].supported_extensions, all_ext_len);
strlcat(core_info_list->all_ext, "|", all_ext_len);
strlcpy(core_info_list->all_ext + _len, "|", all_ext_len - _len);
}
#ifdef HAVE_7ZIP
strlcat(core_info_list->all_ext, "7z|", all_ext_len);
@ -2005,8 +2032,7 @@ static core_info_list_t *core_info_list_new(const char *path,
/* Read core info cache, if enabled */
if (enable_cache)
{
core_info_cache_list = core_info_cache_read(info_dir);
if (!core_info_cache_list)
if (!(core_info_cache_list = core_info_cache_read(info_dir)))
goto error;
}
#endif
@ -2181,13 +2207,23 @@ static bool core_info_does_support_any_file(const core_info_t *core,
static bool core_info_does_support_file(
const core_info_t *core, const char *path)
{
const char *basename, *ext;
if (!core || !core->supported_extensions_list)
return false;
if (string_is_empty(path))
return false;
basename = path_basename(path);
/* if a core has / in its list of supported extensions, the core
supports loading of directories on the host file system */
if (string_is_empty(basename))
return string_list_find_elem(core->supported_extensions_list, "/");
ext = strrchr(basename, '.');
return string_list_find_elem_prefix(
core->supported_extensions_list, ".", path_get_extension(path));
core->supported_extensions_list, ".", (ext ? ext + 1 : ""));
}
/* qsort_r() is not in standard C, sadly. */
@ -2327,8 +2363,8 @@ bool core_info_init_list(
core_info_state_t *p_coreinfo = &core_info_st;
if (!(p_coreinfo->curr_list = core_info_list_new(
dir_cores,
!string_is_empty(path_info)
? path_info
!string_is_empty(path_info)
? path_info
: dir_cores,
exts,
dir_show_hidden_files,
@ -2426,10 +2462,19 @@ void core_info_list_get_supported_cores(core_info_list_t *core_info_list,
struct string_list *list = NULL;
#endif
core_info_state_t *p_coreinfo = &core_info_st;
char dir_path[PATH_MAX_LENGTH];
if (!core_info_list)
return;
if (path_is_directory(path))
{
/* Add a slash so core_info_does_support_file can know it is
a directory without having to check the file system again. */
fill_pathname_join_special(dir_path, path, "", sizeof(dir_path));
path = dir_path;
}
p_coreinfo->tmp_path = path;
#ifdef HAVE_COMPRESSION
@ -2472,7 +2517,7 @@ void core_info_list_get_supported_cores(core_info_list_t *core_info_list,
*
* e.g.:
* snes9x_libretro.dll and snes9x_libretro_android.so are matched
* snes9x__2005_libretro.dll and snes9x_libretro_android.so are
* snes9x__2005_libretro.dll and snes9x_libretro_android.so are
* NOT matched
*/
bool core_info_core_file_id_is_equal(const char *core_path_a,
@ -2585,7 +2630,7 @@ bool core_info_list_get_display_name(
info = core_info_find_internal(
core_info_list, core_path);
if ( s
if ( s
&& info
&& !string_is_empty(info->display_name))
{
@ -2604,7 +2649,7 @@ bool core_info_list_get_display_name(
core_updater_info_t *core_info_get_core_updater_info(
const char *info_path)
{
struct config_entry_list
struct config_entry_list
*entry = NULL;
bool tmp_bool = false;
core_updater_info_t *info = NULL;
@ -2696,7 +2741,7 @@ static int core_info_qsort_func_display_name(const core_info_t *a,
{
if ( !a
|| !b
|| string_is_empty(a->display_name)
|| string_is_empty(a->display_name)
|| string_is_empty(b->display_name))
return 0;
return strcasecmp(a->display_name, b->display_name);
@ -2707,7 +2752,7 @@ static int core_info_qsort_func_core_name(const core_info_t *a,
{
if ( !a
|| !b
|| string_is_empty(a->core_name)
|| string_is_empty(a->core_name)
|| string_is_empty(b->core_name))
return 0;
return strcasecmp(a->core_name, b->core_name);
@ -2719,7 +2764,7 @@ static int core_info_qsort_func_system_name(const core_info_t *a,
if (
!a
|| !b
|| string_is_empty(a->systemname)
|| string_is_empty(a->systemname)
|| string_is_empty(b->systemname))
return 0;
return strcasecmp(a->systemname, b->systemname);

View File

@ -443,7 +443,7 @@ struct retro_core_options_v2 *core_option_manager_convert_v2_intl(
options_v2_us->categories[i].desc : local_desc;
option_v2_cats[i].info = string_is_empty(local_info) ?
options_v2_us->categories[i].info : local_info;
}
/* Loop through options... */
@ -1404,7 +1404,7 @@ bool core_option_manager_get_category_visible(core_option_manager_t *opt,
nested_list_item_t *category_item = NULL;
nested_list_t *option_list = NULL;
if ( !opt
if ( !opt
|| string_is_empty(key))
return false;
@ -1649,7 +1649,7 @@ const char *core_option_manager_get_val_label(core_option_manager_t *opt,
{
struct core_option *option = NULL;
if ( !opt
if ( !opt
|| (idx >= opt->size))
return NULL;

View File

@ -330,35 +330,61 @@ bool core_updater_list_get_core(
static bool core_updater_list_set_date(
core_updater_list_entry_t *entry, const char *date_str)
{
struct string_list date_list = {0};
char *tok, *save;
char *elem0 = NULL;
char *elem1 = NULL;
char *elem2 = NULL;
unsigned list_size = 0;
char *date_str_cpy = NULL;
if (!entry || string_is_empty(date_str))
goto error;
return false;
date_str_cpy = strdup(date_str);
/* Split date string into component values */
string_list_initialize(&date_list);
if (!string_split_noalloc(&date_list, date_str, "-"))
goto error;
if ((tok = strtok_r(date_str_cpy, "-", &save)))
{
elem0 = strdup(tok);
list_size++;
}
if ((tok = strtok_r(NULL, "-", &save)))
{
elem1 = strdup(tok);
list_size++;
}
if ((tok = strtok_r(NULL, "-", &save)))
{
elem2 = strdup(tok);
list_size++;
}
free(date_str_cpy);
/* Date string must have 3 values:
* [year] [month] [day] */
if (date_list.size < 3)
goto error;
if (list_size < 3)
{
if (elem0)
free(elem0);
if (elem1)
free(elem1);
if (elem2)
free(elem2);
return false;
}
/* Convert date string values */
entry->date.year = string_to_unsigned(date_list.elems[0].data);
entry->date.month = string_to_unsigned(date_list.elems[1].data);
entry->date.day = string_to_unsigned(date_list.elems[2].data);
entry->date.year = string_to_unsigned(elem0);
entry->date.month = string_to_unsigned(elem1);
entry->date.day = string_to_unsigned(elem2);
/* Clean up */
string_list_deinitialize(&date_list);
free(elem0);
free(elem1);
free(elem2);
return true;
error:
string_list_deinitialize(&date_list);
return false;
}
/* Parses crc string and adds value to
@ -656,32 +682,13 @@ static void core_updater_list_add_entry(
const char *path_dir_libretro,
const char *path_libretro_info,
const char *network_buildbot_url,
struct string_list *network_core_entry_list)
const char *date_str,
const char *crc_str,
const char *filename_str)
{
const char *date_str = NULL;
const char *crc_str = NULL;
const char *filename_str = NULL;
const core_updater_list_entry_t *search_entry = NULL;
core_updater_list_entry_t entry = {0};
if (!core_list || !network_core_entry_list)
goto error;
/* > Listings must have 3 entries:
* [date] [crc] [filename] */
if (network_core_entry_list->size < 3)
goto error;
/* Get handles of the individual listing strings */
date_str = network_core_entry_list->elems[0].data;
crc_str = network_core_entry_list->elems[1].data;
filename_str = network_core_entry_list->elems[2].data;
if ( string_is_empty(date_str)
|| string_is_empty(crc_str)
|| string_is_empty(filename_str))
goto error;
/* Check whether core file is already included
* in the list (this is *not* an error condition,
* it just means we can skip the current listing) */
@ -777,13 +784,13 @@ bool core_updater_list_parse_network_data(
const char *network_buildbot_url,
const char *data, size_t len)
{
size_t i;
char *data_buf = NULL;
struct string_list network_core_list = {0};
char *tok, *save;
unsigned list_size = 0;
char *data_buf = NULL;
/* Sanity check */
if (!core_list || string_is_empty(data) || (len < 1))
goto error;
return false;
/* We're populating a list 'from scratch' - remove
* any existing entries */
@ -792,55 +799,73 @@ bool core_updater_list_parse_network_data(
/* Input data string is not terminated - have
* to copy it to a temporary buffer... */
if (!(data_buf = (char*)malloc((len + 1) * sizeof(char))))
goto error;
return false;
memcpy(data_buf, data, len * sizeof(char));
data_buf[len] = '\0';
/* Split network listing request into lines */
string_list_initialize(&network_core_list);
if (!string_split_noalloc(&network_core_list, data_buf, "\n"))
goto error;
list_size = string_count_occurrences_single_character(data_buf, '\n');
if (network_core_list.size < 1)
goto error;
if (list_size < 1)
{
free(data_buf);
return false;
}
/* Split network listing request into lines */
/* Loop over lines */
for (tok = strtok_r(data_buf, "\n", &save); tok;
tok = strtok_r(NULL, "\n", &save))
{
char *tok2, *save2;
char *elem0 = NULL;
char *elem1 = NULL;
char *elem2 = NULL;
char *line_cpy = NULL;
const char *line = tok;
if (string_is_empty(line))
continue;
line_cpy = strdup(line);
/* Split line into listings info components */
if ((tok2 = strtok_r(line_cpy, " ", &save2)))
elem0 = strdup(tok2); /* date */
if ((tok2 = strtok_r(NULL, " ", &save2)))
elem1 = strdup(tok2); /* crc */
if ((tok2 = strtok_r(NULL, " ", &save2)))
elem2 = strdup(tok2); /* filename */
free(line_cpy);
/* Parse listings info and add to core updater
* list */
/* > Listings must have 3 entries:
* [date] [crc] [filename] */
if ( !string_is_empty(elem0)
&& !string_is_empty(elem1)
&& !string_is_empty(elem2))
core_updater_list_add_entry(
core_list,
path_dir_libretro,
path_libretro_info,
network_buildbot_url,
elem0, elem1, elem2);
/* Clean up */
free(elem0);
free(elem1);
free(elem2);
}
/* Temporary data buffer is no longer required */
free(data_buf);
data_buf = NULL;
/* Loop over lines */
for (i = 0; i < network_core_list.size; i++)
{
struct string_list network_core_entry_list = {0};
const char *line = network_core_list.elems[i].data;
if (string_is_empty(line))
continue;
string_list_initialize(&network_core_entry_list);
/* Split line into listings info components */
string_split_noalloc(&network_core_entry_list, line, " ");
/* Parse listings info and add to core updater
* list */
core_updater_list_add_entry(
core_list,
path_dir_libretro,
path_libretro_info,
network_buildbot_url,
&network_core_entry_list);
/* Clean up */
string_list_deinitialize(&network_core_entry_list);
}
/* Sanity check */
if (RBUF_LEN(core_list->entries) < 1)
goto error;
/* Clean up */
string_list_deinitialize(&network_core_list);
return false;
/* Sort completed list */
core_updater_list_qsort(core_list);
@ -849,14 +874,6 @@ bool core_updater_list_parse_network_data(
core_list->type = CORE_UPDATER_LIST_TYPE_BUILDBOT;
return true;
error:
string_list_deinitialize(&network_core_list);
if (data_buf)
free(data_buf);
return false;
}
/* Parses a single play feature delivery core

View File

@ -86,6 +86,10 @@ void libretro_dummy_retro_init(void)
case RGUI_ASPECT_RATIO_16_10_CENTRE:
frame_buf_width = 384;
break;
case RGUI_ASPECT_RATIO_21_9:
case RGUI_ASPECT_RATIO_21_9_CENTRE:
frame_buf_width = 560;
break;
default:
/* 4:3 */
frame_buf_width = 320;
@ -95,8 +99,12 @@ void libretro_dummy_retro_init(void)
#endif
dummy_frame_buf = (uint16_t*)calloc(frame_buf_width * frame_buf_height, sizeof(uint16_t));
for (i = 0; i < (unsigned)(frame_buf_width * frame_buf_height); i++)
dummy_frame_buf[i] = 4 << 5;
if (dummy_frame_buf)
{
for (i = 0; i < (unsigned)(frame_buf_width * frame_buf_height); i++)
dummy_frame_buf[i] = 4 << 5;
}
}
void libretro_dummy_retro_deinit(void)

View File

@ -65,6 +65,8 @@ extern "C" {
s ##_version() >> 8 & 0xFF, \
s ##_version() & 0xFF);
#define HAVE_CH_LAYOUT (LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(57, 28, 100))
static bool reset_triggered;
static bool libretro_supports_bitmasks = false;
@ -366,7 +368,7 @@ void CORE_PREFIX(retro_reset)(void)
reset_triggered = true;
}
static void print_ffmpeg_version()
static void print_ffmpeg_version(void)
{
PRINT_VERSION(avformat)
PRINT_VERSION(avcodec)
@ -489,7 +491,7 @@ static void check_variables(bool firststart)
}
else
{
sw_decoder_threads = strtoul(sw_threads_var.value, NULL, 0);
sw_decoder_threads = (unsigned)strtoul(sw_threads_var.value, NULL, 0);
}
/* Scale the sws threads based on core count but use at least 2 and at most 4 threads */
sw_sws_threads = MIN(MAX(2, sw_decoder_threads / 2), 4);
@ -613,7 +615,7 @@ void CORE_PREFIX(retro_run)(void)
static bool last_l;
static bool last_r;
double min_pts;
int16_t audio_buffer[2048];
int16_t audio_buffer[media.sample_rate / 20];
bool left, right, up, down, l, r;
int16_t ret = 0;
size_t to_read_frames = 0;
@ -875,7 +877,7 @@ void CORE_PREFIX(retro_run)(void)
if (!temporal_interpolation)
mix_factor = 1.0f;
glBindFramebuffer(GL_FRAMEBUFFER, hw_render.get_current_framebuffer());
glBindFramebuffer(GL_FRAMEBUFFER, (GLuint)hw_render.get_current_framebuffer());
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
glViewport(0, 0, media.width, media.height);
@ -980,7 +982,7 @@ void CORE_PREFIX(retro_run)(void)
#if ENABLE_HW_ACCEL
/*
* Try to initialize a specific HW decoder defined by type.
* Optionaly tests the pixel format list for a compatible pixel format.
* Optionally tests the pixel format list for a compatible pixel format.
*/
static enum AVPixelFormat init_hw_decoder(struct AVCodecContext *ctx,
const enum AVHWDeviceType type,
@ -1726,8 +1728,14 @@ static void decode_thread(void *data)
{
swr[i] = swr_alloc();
#if HAVE_CH_LAYOUT
AVChannelLayout out_chlayout = AV_CHANNEL_LAYOUT_STEREO;
av_opt_set_chlayout(swr[i], "in_chlayout", &actx[i]->ch_layout, 0);
av_opt_set_chlayout(swr[i], "out_chlayout", &out_chlayout, 0);
#else
av_opt_set_int(swr[i], "in_channel_layout", actx[i]->channel_layout, 0);
av_opt_set_int(swr[i], "out_channel_layout", AV_CH_LAYOUT_STEREO, 0);
#endif
av_opt_set_int(swr[i], "in_sample_rate", actx[i]->sample_rate, 0);
av_opt_set_int(swr[i], "out_sample_rate", media.sample_rate, 0);
av_opt_set_int(swr[i], "in_sample_fmt", actx[i]->sample_fmt, 0);
@ -1742,7 +1750,7 @@ static void decode_thread(void *data)
if (video_stream_index >= 0)
{
frame_size = av_image_get_buffer_size(AV_PIX_FMT_RGB32, media.width, media.height, 1);
video_buffer = video_buffer_create(4, frame_size, media.width, media.height);
video_buffer = video_buffer_create(4, (int)frame_size, media.width, media.height);
tpool = tpool_create(sw_sws_threads);
log_cb(RETRO_LOG_INFO, "[FFMPEG] Configured worker threads: %d\n", sw_sws_threads);
}

View File

@ -34,7 +34,7 @@ typedef struct packet_buffer packet_buffer_t;
*
* Returns: A packet buffer.
*/
packet_buffer_t *packet_buffer_create();
packet_buffer_t *packet_buffer_create(void);
/**
* packet_buffer_destroy:

View File

@ -56,7 +56,7 @@ static mpv_render_context *mpv_gl;
/* Save the current playback time for context changes */
static int64_t playback_time = 0;
/* filepath required globaly as mpv is reopened on context change */
/* filepath required globally as mpv is reopened on context change */
static char *filepath = NULL;
static volatile int frame_queue = 0;

File diff suppressed because it is too large Load Diff

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