Compare commits

...

111 Commits

Author SHA1 Message Date
5a38c5f190 cheats: Use global cheat engine 2023-07-31 23:39:21 +03:00
80033b84cb renderer_software: Fix screen rendering (#6664) 2023-07-06 17:15:59 -07:00
cf9bb90ae3 code: Use std::span where appropriate (#6658)
* code: Use std::span when possible

* code: Prefix memcpy and memcmp with std::
2023-07-07 01:52:40 +03:00
4ccd9f24fb Merge pull request #6638 from GPUCode/new-log
common: Backport yuzu log improvements
2023-07-06 23:44:54 +03:00
753b36c6ef act: Use correct service session limit. (#6670) 2023-07-06 13:16:46 -07:00
c00768d6d0 nfc: Use existing secrets infrastructure for amiibo encryption. (#6652) 2023-07-06 11:45:46 -07:00
4383f6d80a Port yuzu-emu/yuzu#5229: "yuzu/main: Add basic command line arguments" (#5696)
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
2023-07-06 20:44:35 +02:00
dc5ca96c0f service: nfc: Use official names (#6672) 2023-07-06 20:25:05 +02:00
9d4609e29a build: Bundle libraries in-place as well on MSVC. (#6665) 2023-07-06 02:37:06 +02:00
df9cc1b84c ci: Fix CI builds being marked as dirty. (#6656) 2023-07-04 21:02:33 -07:00
13a8969824 build: Clear out remaining compile warnings. (#6662) 2023-07-04 21:00:24 -07:00
d7b4260389 common: Address feedback 2023-07-03 17:13:00 +03:00
2126c240cd core: backport some ResultCode updates (#6645)
Co-authored-by: Lioncash <mathew1800@gmail.com>
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
2023-07-03 02:23:53 +02:00
0b37c1da57 shader_jit/tests: Add additional shader-jit tests (#6648)
* shader_jit/tests: Add support for multiple inputs

Allows for multiple `Vec4f` inputs for each run

* shader_jit/tests: Add additional shader-jit tests

Add some more expansive tests for each of the shader-instructions for
regression-testing.  `MAD`/`MADI` is not added due to an upstream bug in
nihstro:

https://github.com/neobrain/nihstro/issues/68
2023-07-03 02:44:56 +03:00
9527bfffed common: Remove dependency from core 2023-07-03 02:18:37 +03:00
ba98bf058a logging: Address some issues 2023-07-03 02:18:35 +03:00
c88acf7405 Android: Gradle updates (#6653)
* android: Migrate to Kotlin DSL

Includes updates to all android dependencies/ndk (minus billing) and adds support for Kotlin, Android 13, and view binding.

* android: Remove unused tests

* android: Remove unused dependencies
2023-07-02 01:08:27 -07:00
71aea7e571 shader/jit: Use xbyak::util::Cpu for Host capabilities (#6643)
Xbyak has a complete utility-class for determining the host-processor's
ISA-features such as SSE4.1, AVX, AVX2, AVX512{F,VL,DQ,VBMI,etc}, and so
on for further potential optimizations.
2023-07-02 08:05:07 +05:30
3d0a3c2c45 service: nfc: Implement amiibo encryption and appdata (#6340) 2023-06-30 22:15:58 +02:00
9c3e2d0f50 externals: Update boost
* To include stack traces
2023-06-30 12:15:52 +03:00
0ddb095273 logging: Make use of bounded queue 2023-06-30 12:15:52 +03:00
52b9007fcf common: Reduce unused includes 2023-06-30 12:15:52 +03:00
e112421db8 backend: Ensure backend_thread is destructed before message_queue
Ensures that stop_token signals that stop has been requested before destruction of conditional_variable
2023-06-30 12:15:52 +03:00
ae6fda8638 logging: Convert backend_thread into an std::jthread
Was getting an unhandled `invalid_argument` [exception](https://en.cppreference.com/w/cpp/thread/thread/join) during
shutdown on my linux machine. This removes the need for a `StopBackendThread` function entirely since `jthread`
[automatically handles both checking if the thread is joinable and stopping the token before attempting to join](https://en.cppreference.com/w/cpp/thread/jthread/~jthread) in the case that `StartBackendThread` was never called.
2023-06-30 12:15:52 +03:00
197c1adcba Refactor Logging Impl
Loop on stop_token and remove final_entry in Entry.
Move Backend thread out of Impl Constructor to its own function.
Add Start function for backend thread.
Use stop token in PopWait and check if entry filename is nullptr before logging.
2023-06-30 12:15:52 +03:00
fe027a96fb common: Replace lock_guard with scoped_lock 2023-06-30 12:15:52 +03:00
637ade3b25 threadsafe_queue: Fix deadlock
This fixes a lost wakeup in SPSCQueue. If the reader is in just the right position, the writer's notification will be lost and this will be a problem if the writer then does something to wait on the reader.

This was discovered to affect my upcoming stacktrace PR. I don't think any performance decrease will be noticeable because an uncontended mutex is smart enough to skip the syscall. This PR might also resolve some rare deadlocks but I don't know of any examples.
2023-06-30 12:15:52 +03:00
a1443356f1 threadsafe_queue: Add std::stop_token overload to PopWait
Useful for jthreads which make use of the threadsafe queues.
2023-06-30 12:15:52 +03:00
aa39430e2c common/logging: Reduce scope of fmt include 2023-06-30 12:15:52 +03:00
8f51dd9513 common/logging: Move Log::Entry declaration to a separate header
This reduces the load of requiring to include std::chrono in all files which include log.h
2023-06-30 12:15:52 +03:00
98e9f4c32e logging: Fix log filter during initialization
The log filter was being ignored on initialization due to the logging instance being initialized before the config instance, so the log filter was set to its default value.

This fixes that oversight, along with using descriptive exceptions instead of abort() calls.
2023-06-30 12:15:51 +03:00
a8340395a3 logging: Display backtrace on crash
This implements backtraces so we don't have to tell users how to use gdb anymore.

This prints a backtrace after abort or segfault is detected. It also fixes the log getting cut off with the last line containing only a bracket. This change lets us know what caused a crash not just what happened the few seconds before it.

I only know how to add support for Linux with GCC. Also this doesn't work outside of C/C++ such as in dynarmic or certain parts of graphics drivers. The good thing is that it'll try and just crash again but the stack frames are still there so the core dump will work just like before.
2023-06-30 12:15:51 +03:00
3641b9891d logging: Simplify and make thread-safe
This simplifies the logging system.

This also fixes some lost messages on startup.

The simplification is simple. I removed unused functions and moved most things in the .h to the .cpp. I replaced the unnecessary linked list with its contents laid out as three member variables. Anything that went through the linked list now directly accesses the backends. Generic functions are replaced with those for each specific use case and there aren't many. This change increases coupling but we gain back more KISS and encapsulation.

With those changes it was easy to make it thread-safe. I just removed the mutex and turned a boolean atomic. I was planning to use this thread-safety in my next PR about stacktraces. It was actually async-signal-safety at first but I ended up using a different approach. Anyway getting rid of the linked list is important for that because have the list of backends constantly changing complicates things.
2023-06-30 12:15:51 +03:00
8e8ca7d9d0 common: logging: backend: Close the file after exceeding the write limit
There's no point in keeping the file open after the write limit is exceeded. This allows the file to be committed to the disk shortly after it is closed and avoids redundantly checking whether or not the write limit is exceeded.
2023-06-30 12:15:51 +03:00
b57773b1cf common: logging: Restructure backend code 2023-06-30 12:15:51 +03:00
b559c078bc common: logging: backend: Wrap IOFile in a unique_ptr
Allows us to forward declare FileUtil::IOFile.
2023-06-30 12:15:51 +03:00
5c86147ef4 log/backend: Use in-class initializer for FileBackend
We can also avoid redundant constructions of the same string repeatedly.
2023-06-30 12:15:51 +03:00
399f3d4e32 log/backend: Make use of erase_if
Same behavior, but less verbose.
2023-06-30 12:15:51 +03:00
173b84c8ff log/backend: Correct order of const in copy constructor
Follows our predominant coding style. Also explicitly specifies the move
constructor/assignment operator as well.
2023-06-30 12:15:51 +03:00
b4c38372d1 common/log: Move Log namespace into the Common namespace
Forgot to move this over when I moved the rest of the source files with
lacking namespaces over.
2023-06-30 12:15:51 +03:00
4fd0cbebdb logging/backend: Make use of designated initializers
Same behavior, less code.
2023-06-30 12:15:36 +03:00
ca2d87e5e3 renderer_opengl: Add debug scopes to logging (#6650) 2023-06-30 02:16:54 +03:00
d26dcc8e31 ci: Run clang-format and transifex in linux-fresh image. (#6649)
* ci: Run clang-format and transifex in linux-fresh image.

* build: Only add bundle targets for enabled outputs.
2023-06-29 00:44:13 -07:00
0d516f6da5 frontend: Added Hybrid Screen screen layout option (#4542) (#6600)
Signed-off-by: elim <e_sliwka@tuta.io>
2023-06-29 01:42:57 +03:00
2d6aca4563 build: Rework CI and move all bundling into new build target. (#6556)
* build: Rework CI and move all bundling into new build target.

* ci: Use "mingw" in msys2 release names for compatibility.

* ci: Use "osx" in macOS release names for compatibility.

* ci: Disable macOS upload.

Will be moved to a separate PR for canary merge.
2023-06-26 17:42:00 -07:00
2e479fcec5 renderer_vulkan: Add shader generators (#6630) 2023-06-26 16:22:51 +02:00
7edc86a9bc code: Remove outdated comment style (#6640) 2023-06-25 15:22:41 +05:30
9b82de6b24 Refactor software renderer (#6621) 2023-06-24 00:59:18 +02:00
7198243319 android: Update UI strings to reflect desktop counterpart (#6608)
* android: Update UI strings to reflect desktop counterpart

Quick edit to the UI strings to bring the text up to parity with Citra desktop, plus some small QoL changes.

* Update strings.xml
2023-06-23 23:45:49 +01:00
6b8a06e7b4 gl_rasterizer: Reset normal map flag each draw (#6636)
* Fixes normal maps leaking draws
2023-06-24 00:30:16 +03:00
eb118b2a4c Merge pull request #6613 from t895/buncha-adjustments
citra_android: String adjustments
2023-06-23 15:35:54 +01:00
7616496456 video_core: Add debug scopes (#6634) 2023-06-23 03:37:13 +02:00
89663e0db8 build: Fix generating build info using unified source archive. (#6628) 2023-06-20 09:44:20 -07:00
d8db0af1b2 Port yuzu-emu/yuzu#10575: "issue_template: Add link to website, Getting Log Files" (#6629)
Co-authored-by: bm01 <1279721+bm01@users.noreply.github.com>
2023-06-20 15:24:04 +02:00
08970e7ba0 update graphics api button indicator (#6625)
* update graphics api button indicator

This tiny pull request
* update the graphics button indicator when launching or closing a game (graphics button doesn't update with per game configuration)

* Disable graphics button indicator click while in game

* fix crash

* It fixed crash when opening configure dialog in game if the graphics api for the game is different of the global graphics api
2023-06-20 15:27:36 +03:00
d735f5c458 renderer_vulkan: Add vulkan initialization code (#6620)
* common: Move dynamic library to common

* This is so that video_core can use it

* logging: Add vulkan log target

* common: Allow defered library loading

* Also add some comments to the functions

* renderer_vulkan: Add vulkan initialization code

* renderer_vulkan: Address feedback
2023-06-20 15:24:24 +03:00
70225e92f7 externals: Move library headers CMake logic to Citra. (#6627) 2023-06-19 17:08:11 -07:00
bfb6a5b5de common: Add C++ version of Apple authorization logic. (#6616) 2023-06-19 15:50:26 -07:00
03dbdfc12f video_core: Reduce nihstro includes in headers. (#6626) 2023-06-19 15:49:22 -07:00
3faddd5e03 video_core: Add vulkan shaders (#6619) 2023-06-19 17:02:18 +03:00
7c11b9b689 Remove AppImage Themeing (#6618) 2023-06-18 10:24:11 -07:00
35d1b67fd4 Merge pull request #6602 from SachinVin/wall
Chore: enable `-Werror` on GCC and clang
2023-06-18 22:37:39 +05:30
4c8a98a321 common\string_util.cpp: switch to boost::locale::conv for UTF16ToUTF8() and UTF8ToUTF16() (#6623) 2023-06-18 20:00:00 +03:00
982c60c67c common\dynamic_library\ffmpeg.{cpp, h}: fix version check for av_opt_child_class_iterate 2023-06-17 21:24:20 +05:30
7e134421d5 common, input_common, network: fix warnings 2023-06-17 21:24:20 +05:30
946a32d793 android + common: fix warnings 2023-06-17 21:24:20 +05:30
8eb89c260d core: fix warnings 2023-06-17 21:23:58 +05:30
796e8a9f24 video_core:fix warnings 2023-06-17 21:23:58 +05:30
c66594caf8 Enable warnings as errors
cpp-jwt: supress OpenSSL deprecation warnings
2023-06-17 21:23:58 +05:30
06db4ffb17 Merge pull request #6508 from SachinVin/not-the-cia
Android: Offload CIA installation to background thread
2023-06-17 20:44:20 +05:30
7f1ffa2a04 hle: Reduce Y2R stub warnings to debug logs. (#6617) 2023-06-17 01:03:37 -07:00
38435e9b3e Dynamically load FFmpeg and libfdk-aac if available. (#6570) 2023-06-17 02:06:18 +03:00
d807cdfe62 Qt: Fix intermittent crash on exit (#6612)
* Fix null pointer deref on exit

* Fix from review
2023-06-16 22:28:00 +05:30
318d55252f CiaInstallWorker.java: cleanup magic numbers 2023-06-16 22:23:34 +05:30
4d666b88b7 citra_android: Add headers for clock and plugin loader 2023-06-15 03:35:30 -04:00
819d2a33c7 citra_android: Make strings more consistent 2023-06-15 03:35:10 -04:00
c074460f60 android: Bump to gradle 8.0 2023-06-12 18:39:42 +05:30
f5bb17c82e Android: Offload CIA installation to background thread 2023-06-12 18:39:40 +05:30
ccb2a7cbea android: minor refactor disk shadercache 2023-06-10 21:05:14 +05:30
238a574645 qt: Add support for building for iOS. (#6594) 2023-06-07 20:40:53 -07:00
d9bf4fd8a2 externals: Update dynarmic to 6.4.8 (#6596) 2023-06-07 20:25:28 -07:00
54c499ed5b Prepare for Vulkan backend (#6595)
* externals: Add libraries required for vulkan

* build: Add support for downloading bundled MoltenVK.

* ci: Install tools needed for Vulkan.

* citra_qt: Add API status indicator

---------

Co-authored-by: GPUCode <geoster3d@gmail.com>
2023-06-05 07:29:05 -07:00
5b7cc76ba3 Add warning popup when loading save states for the first time (#6565)
* citra_qt: Remove global state usage in GMainWindow

* citra_qt: Add warning when loadings saves for the first time

* citra_qt: Focus window when launching game from cmdline

* citra_qt: Cleanup nullptr checks

* citra_qt: Move setting to UISettings

* renderer_opengl: Remove header
2023-06-05 10:06:00 +03:00
52f88f8fb4 chore: Fix GCC 13 compilation and SoundTouch libraries being installed. (#6593) 2023-06-02 23:11:17 -07:00
abd949fea1 qt: Add NCCH secure 1/2 to keys needed for system titles download. (#6586) 2023-06-02 19:16:48 -07:00
f1ece7c56f audio_core: Fix FDK and FFmpeg compile errors. (#6591) 2023-06-02 19:00:09 -07:00
c67c648c1a mmpx: Fix GLES crashes. (#6588) 2023-06-01 20:52:57 +05:30
723b662604 core: Update minimal system title set. (#6573) 2023-05-31 17:34:31 -07:00
0f5ff64ae6 build: Fix Qt download commands working directory. (#6579) 2023-05-31 15:42:13 -07:00
e33a8a9b26 input_common: sdl: Port yuzu sdl fixes (#6577) 2023-05-31 13:01:46 +03:00
b91fbf3f8e ci: Fix macOS bundle validity issues. (#6572)
* ci: Fix improper copying of macOS artifacts.

* ci: Resign universal macOS app after combining.
2023-05-31 13:01:12 +03:00
4ddb2116bf qt: Allow toggling whether to enter system setup on home menu boot. (#6574) 2023-05-31 11:56:35 +03:00
691e09473e video_core: Add MMPX texture filter (#6564)
* video_core: Add MMPX texture shader

* mmpx: Apply mix to mask alpha edge artifacting

* mmpx: Do not use deprecated texture fuction.
2023-05-31 11:55:46 +03:00
b45c7188c7 chore: Fix some compiler warnings. (#6578) 2023-05-30 12:36:12 -07:00
a1d265325a Merge pull request #6561 from SachinVin/audio
audio_core/hle: Refactor Binary Pipe data structures
2023-05-30 19:02:37 +05:30
1ede2f5b5a audio_core\hle\decoder.h: Minor correction in docs 2023-05-29 08:16:05 +05:30
b452b61e58 audio_core/hle/{fdk, ffmpeg}_decoder:fix typos. (#4) 2023-05-26 07:28:17 +05:30
848116b5be audio_core: Dispose of current audio sink before opening new one. (#6567) 2023-05-26 00:44:56 +02:00
5311c939a2 tests/audio_core: add sanity test cases for LLE vs HLE 2023-05-25 20:23:21 +05:30
8cada619b3 audio_core/hle: Refactor Binary Pipe data structures
audio_core\hle\ffmpeg_decoder.cpp: renames
2023-05-25 20:23:19 +05:30
72b82ef6ed Enable web services on Android in Github build (#6555)
* Enable web services in android

* Fix web services build on android

* clang-format

* Remove unnecessary line

* Set telemetry to be disabled by default on all platforms
2023-05-23 21:36:14 +05:30
2281bf5b0b Add range check for renderer config (#6560) 2023-05-21 19:01:26 -07:00
5c45c97ff9 Implement/Fix more SOC related functions (#6267)
* Implement SOC_U::GetHostByName and partial SOC_U::GetNetworkOpt

* Implement AC::GetWifiStatus, and get proper network interface.

* Minor fixes

* More minor fixes

* Even more fixes

* Fix Get/Set SockOpt

* Implement SendToOther

* Apply suggestions and fix timer advance

* Fix variable name

* Add more sockopt values and fix send/recv flags.

* Fix dontwait logic

* Add missing header for linux

* Remove TCP_STDURG

* Fix poll and add more 3ds <-> platform conversions

* Finish implementing all platform <-> 3ds conversion.

* Disable UDP connreset and fix poll again.

* Fix compile issues

* Apply suggestions

* Fix compiler issues

* Fix compiler errors (again)

* Fix GetAddrInfo

* Use IPC::MakeHeader instead of raw hardcoded value.
2023-05-21 19:01:08 -07:00
975ee15635 audiocore/{hle, lle}: remove dependence on static core timing 2023-05-20 21:27:22 +05:30
fa8c530e10 Debian 11 fix (#6543) 2023-05-19 11:34:17 -07:00
7d6c14e584 dumper: Fix pixel format for filters when passed in via encoder options. (#6553) 2023-05-19 10:58:05 -07:00
40962c4479 sdl: Enable cpuinfo detection. (#6554) 2023-05-19 15:48:30 +02:00
110063aa56 externals: update cubeb (#6548) 2023-05-19 00:24:43 +02:00
a12058ea37 ci: Only pack and upload AppImage builds. (#6545) 2023-05-16 13:01:21 -07:00
b89f5278ac Revive: dumping/ffmpeg_backend: Various fixes (#6528)
* dumping/ffmpeg_backend: Add FPS filter

So that the recorded video can be at 60FPS (which is supported by most encoders) while still maintaining correct speed.

* dumping/ffmpeg_backend: Add HW context support

Required for some HW acceled encoders. Not tested as my devices don't seem to require this.

* CMake: Copy avfilter dll for MSVC

* CMakeLists: Require FFmpeg 4.0

* ffmpeg: Fix dumper compile error on MSVC.

* ffmpeg: Address review comments.

---------

Co-authored-by: zhupengfei <zhupf321@gmail.com>
2023-05-16 02:28:21 -07:00
0768bd8ce0 audio_core: Fix FDK AAC decoding. (#6530) 2023-05-14 19:50:07 -07:00
452 changed files with 20241 additions and 7401 deletions

View File

@ -5,7 +5,10 @@ export NDK_CCACHE=$(which ccache)
BUILD_FLAVOR=canary ||
BUILD_FLAVOR=nightly
ccache -s
if [ ! -z "${ANDROID_KEYSTORE_B64}" ]; then
export ANDROID_KEYSTORE_FILE="${GITHUB_WORKSPACE}/ks.jks"
base64 --decode <<< "${ANDROID_KEYSTORE_B64}" > "${ANDROID_KEYSTORE_FILE}"
fi
cd src/android
chmod +x ./gradlew
@ -13,3 +16,7 @@ chmod +x ./gradlew
./gradlew bundle${BUILD_FLAVOR}Release
ccache -s
if [ ! -z "${ANDROID_KEYSTORE_B64}" ]; then
rm "${ANDROID_KEYSTORE_FILE}"
fi

View File

@ -1,23 +0,0 @@
#!/bin/bash -ex
. ./.ci/common/pre-upload.sh
REV_NAME="citra-android-${GITDATE}-${GITREV}"
[ "${GITHUB_REPOSITORY}" = "citra-emu/citra-canary" ] &&
BUILD_FLAVOR=canary ||
BUILD_FLAVOR=nightly
cp src/android/app/build/outputs/apk/${BUILD_FLAVOR}/release/app-${BUILD_FLAVOR}-release.apk \
"artifacts/${REV_NAME}.apk"
cp src/android/app/build/outputs/bundle/${BUILD_FLAVOR}Release/app-${BUILD_FLAVOR}-release.aab \
"artifacts/${REV_NAME}.aab"
if [ ! -z "${ANDROID_KEYSTORE_B64}" ]
then
echo "Signing apk..."
base64 --decode <<< "${ANDROID_KEYSTORE_B64}" > ks.jks
apksigner sign --ks ks.jks \
--ks-key-alias "${ANDROID_KEY_ALIAS}" \
--ks-pass env:ANDROID_KEYSTORE_PASS "artifacts/${REV_NAME}.apk"
fi

View File

@ -1,28 +0,0 @@
#!/bin/bash -ex
# Copy documentation
cp license.txt "$REV_NAME"
cp README.md "$REV_NAME"
# Copy cross-platform scripting support
cp -r dist/scripting "$REV_NAME"
tar $COMPRESSION_FLAGS "$ARCHIVE_NAME" "$REV_NAME"
# Find out what release we are building
if [[ "$GITHUB_REF_NAME" =~ ^canary- ]] || [[ "$GITHUB_REF_NAME" =~ ^nightly- ]]; then
RELEASE_NAME=$(echo $GITHUB_REF_NAME | cut -d- -f1)
if [ "$NAME" = "linux-mingw" ]; then
RELEASE_NAME="${RELEASE_NAME}-mingw"
fi
else
RELEASE_NAME=head
fi
mv "$REV_NAME" $RELEASE_NAME
7z a "$REV_NAME.7z" $RELEASE_NAME
# move the compiled archive into the artifacts directory to be uploaded by travis releases
mv "$ARCHIVE_NAME" artifacts/
mv "$REV_NAME.7z" artifacts/

View File

@ -1,6 +0,0 @@
#!/bin/bash -ex
GITDATE="`git show -s --date=short --format='%ad' | sed 's/-//g'`"
GITREV="`git show -s --format='%h'`"
mkdir -p artifacts

View File

@ -1,3 +0,0 @@
#!/bin/bash -ex
mkdir -p "$HOME/.ccache"
docker run -v $(pwd):/citra -v "$HOME/.ccache":/root/.ccache citraemu/build-environments:linux-appimage /bin/bash -ex /citra/.ci/linux/docker.sh

View File

@ -1,21 +0,0 @@
#!/bin/bash
#Building Citra
mkdir build
cd build
cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ -DENABLE_QT_TRANSLATION=ON -DCITRA_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DUSE_DISCORD_PRESENCE=ON -DENABLE_FFMPEG_VIDEO_DUMPER=ON
ninja
ctest -VV -C Release
#Building AppDir
DESTDIR="./AppDir" ninja install
mv ./AppDir/usr/local/bin ./AppDir/usr
mv ./AppDir/usr/local/share ./AppDir/usr
rm -rf ./AppDir/usr/local
#Circumvent missing LibFuse in Docker, by extracting the AppImage
export APPIMAGE_EXTRACT_AND_RUN=1
#Build AppImage
QMAKE=/usr/lib/qt6/bin/qmake DEPLOY_PLATFORM_THEMES=1 /linuxdeploy-x86_64.AppImage --appdir AppDir --plugin qt --output appimage

View File

@ -1,5 +0,0 @@
#!/bin/bash -ex
. .ci/common/pre-upload.sh
REV_NAME="citra-linux-${GITDATE}-${GITREV}"
mv build/Citra*.AppImage "${GITHUB_WORKSPACE}"/artifacts/${REV_NAME}.AppImage

View File

@ -1,3 +0,0 @@
#!/bin/bash -ex
mkdir -p "$HOME/.ccache"
docker run -v $(pwd):/citra -v "$HOME/.ccache":/root/.ccache citraemu/build-environments:linux-clang-format /bin/bash -ex /citra/.ci/clang-format/docker.sh

View File

@ -1,4 +0,0 @@
#!/bin/bash -ex
# Run clang-format
./.ci/linux-clang-format/script.sh

View File

@ -1,3 +0,0 @@
#!/bin/bash -ex
mkdir -p "$HOME/.ccache"
docker run -v $(pwd):/citra -v "$HOME/.ccache":/root/.ccache citraemu/build-environments:linux-fresh /bin/bash -ex /citra/.ci/linux/docker.sh

View File

@ -1,7 +0,0 @@
#!/bin/bash -ex
mkdir build && cd build
cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ -DENABLE_QT_TRANSLATION=ON -DCITRA_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DUSE_DISCORD_PRESENCE=ON -DENABLE_FFMPEG_VIDEO_DUMPER=ON
ninja
ctest -VV -C Release

View File

@ -1,19 +0,0 @@
#!/bin/bash -ex
. .ci/common/pre-upload.sh
REV_NAME="citra-linux-${GITDATE}-${GITREV}"
ARCHIVE_NAME="${REV_NAME}.tar.xz"
COMPRESSION_FLAGS="-cJvf"
mkdir "$REV_NAME"
cp build/bin/Release/citra "$REV_NAME"
cp build/bin/Release/citra-room "$REV_NAME"
cp build/bin/Release/citra-qt "$REV_NAME"
# We need icons on Linux for .desktop entries
mkdir "$REV_NAME/dist"
cp dist/icon.png "$REV_NAME/dist/citra.png"
. .ci/common/post-upload.sh

View File

@ -1,3 +0,0 @@
#!/bin/bash -ex
mkdir -p "$HOME/.ccache"
docker run -v $(pwd):/citra -v "$HOME/.ccache":/root/.ccache citraemu/build-environments:linux-frozen /bin/bash -ex /citra/.ci/linux-frozen/docker.sh

View File

@ -1,15 +0,0 @@
#!/bin/bash -ex
mkdir -p ~/bin/gold
echo '#!/bin/bash' > ~/bin/gold/ld
echo 'gold "$@"' >> ~/bin/gold/ld
chmod a+x ~/bin/gold/ld
export CFLAGS="-B$HOME/bin/gold $CFLAGS"
export CXXFLAGS="-B$HOME/bin/gold $CXXFLAGS"
mkdir build && cd build
cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++
ninja
ctest -VV -C Release

View File

@ -1,52 +0,0 @@
#!/usr/bin/python
import sys
import re
import subprocess
from launchpadlib.launchpad import Launchpad
if sys.version_info[0] > 2:
xrange = range
cachedir = '/.launchpadlib/cache/'
launchpad = Launchpad.login_anonymously(
'grab build info', 'production', cachedir, version='devel')
processed_packages = []
deb_file_list = []
def get_url(pkg, distro):
build_ref = launchpad.archives.getByReference(reference='ubuntu').getPublishedBinaries(
binary_name=pkg[0], distro_arch_series='https://api.launchpad.net/devel/ubuntu/' + distro + '/amd64', version=pkg[1], exact_match=True, order_by_date=True).entries[0]
build_link = build_ref['build_link']
deb_name = '{}_{}_{}.deb'.format(pkg[0], pkg[1], 'amd64' if build_ref['architecture_specific'] else 'all')
deb_link = build_link + '/+files/' + deb_name
return [deb_link, deb_name]
def list_dependencies(deb_file):
t = subprocess.check_output(
['bash', '-c', '(dpkg -I {} | grep -oP "^ Depends\: \K.*$") || true'.format(deb_file)])
deps = [i.strip() for i in t.split(',')]
equals_re = re.compile(r'^(.*) \(= (.*)\)$')
return [equals_re.sub(r'\1=\2', i).split('=') for i in filter(equals_re.match, deps)]
def get_package(pkg, distro):
if pkg in processed_packages:
return
print('Getting {}...'.format(pkg[0]))
url = get_url(pkg, distro)
subprocess.check_call(['wget', '--quiet', url[0], '-O', url[1]])
for dep in list_dependencies(url[1]):
get_package(dep, distro)
processed_packages.append(pkg)
deb_file_list.append('./' + url[1])
for i in xrange(1, len(sys.argv), 3):
get_package([sys.argv[i], sys.argv[i + 1]], sys.argv[i + 2])
subprocess.check_call(
['apt-get', 'install', '-y', '--force-yes'] + deb_file_list)

View File

@ -1,3 +0,0 @@
#!/bin/bash -ex
mkdir "$HOME/.ccache" || true
docker run -v $(pwd):/citra -v "$HOME/.ccache":/root/.ccache citraemu/build-environments:linux-mingw /bin/bash -ex /citra/.ci/linux-mingw/docker.sh

View File

@ -1,30 +0,0 @@
#!/bin/bash -ex
# override CI ccache size
mkdir -p "$HOME/.ccache/"
echo 'max_size = 3.0G' > "$HOME/.ccache/ccache.conf"
mkdir build && cd build
cmake .. -G Ninja -DCMAKE_TOOLCHAIN_FILE="$(pwd)/../CMakeModules/MinGWCross.cmake" -DCITRA_USE_CCACHE=ON -DCMAKE_BUILD_TYPE=Release -DENABLE_QT_TRANSLATION=ON -DCITRA_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DUSE_DISCORD_PRESENCE=ON -DENABLE_MF=ON -DENABLE_FFMPEG_VIDEO_DUMPER=ON -DCMAKE_NO_SYSTEM_FROM_IMPORTED=TRUE -DCOMPILE_WITH_DWARF=OFF
ninja
echo "Tests skipped"
#ctest -VV -C Release
ccache -s
echo 'Prepare binaries...'
cd ..
mkdir package
QT_PLATFORM_DLL_PATH='/usr/x86_64-w64-mingw32/lib/qt6/plugins/platforms/'
find build/ -name "citra*.exe" -exec cp {} 'package' \;
# copy Qt plugins
mkdir package/platforms
cp "${QT_PLATFORM_DLL_PATH}/qwindows.dll" package/platforms/
cp -rv "${QT_PLATFORM_DLL_PATH}/../multimedia/" package/
cp -rv "${QT_PLATFORM_DLL_PATH}/../imageformats/" package/
cp -rv "${QT_PLATFORM_DLL_PATH}/../styles/" package/
python3 .ci/linux-mingw/scan_dll.py package/*.exe package/imageformats/*.dll "package/"

View File

@ -1,122 +0,0 @@
try:
import lief
except ImportError:
import pefile
import sys
import re
import os
import queue
import shutil
# constant definitions
KNOWN_SYS_DLLS = ['WINMM.DLL', 'MSVCRT.DLL', 'VERSION.DLL', 'MPR.DLL',
'DWMAPI.DLL', 'UXTHEME.DLL', 'DNSAPI.DLL', 'IPHLPAPI.DLL']
# below is for Ubuntu 18.04 with specified PPA enabled, if you are using
# other distro or different repositories, change the following accordingly
DLL_PATH = [
'/usr/x86_64-w64-mingw32/bin/',
'/usr/x86_64-w64-mingw32/lib/',
'/usr/lib/gcc/x86_64-w64-mingw32/9.3-posix/'
]
missing = []
def parse_imports_lief(filename):
results = []
pe = lief.parse(filename)
for entry in pe.imports:
name = entry.name
if name.upper() not in KNOWN_SYS_DLLS and not re.match(string=name, pattern=r'.*32\.DLL'):
results.append(name)
return results
def parse_imports(file_name):
if globals().get('lief'):
return parse_imports_lief(file_name)
results = []
pe = pefile.PE(file_name, fast_load=True)
pe.parse_data_directories()
for entry in pe.DIRECTORY_ENTRY_IMPORT:
current = entry.dll.decode()
current_u = current.upper() # b/c Windows is often case insensitive
# here we filter out system dlls
# dll w/ names like *32.dll are likely to be system dlls
if current_u.upper() not in KNOWN_SYS_DLLS and not re.match(string=current_u, pattern=r'.*32\.DLL'):
results.append(current)
return results
def parse_imports_recursive(file_name, path_list=[]):
q = queue.Queue() # create a FIFO queue
# file_name can be a string or a list for the convience
if isinstance(file_name, str):
q.put(file_name)
elif isinstance(file_name, list):
for i in file_name:
q.put(i)
full_list = []
while q.qsize():
current = q.get_nowait()
print('> %s' % current)
deps = parse_imports(current)
# if this dll does not have any import, ignore it
if not deps:
continue
for dep in deps:
# the dependency already included in the list, skip
if dep in full_list:
continue
# find the requested dll in the provided paths
full_path = find_dll(dep)
if not full_path:
missing.append(dep)
continue
full_list.append(dep)
q.put(full_path)
path_list.append(full_path)
return full_list
def find_dll(name):
for path in DLL_PATH:
for root, _, files in os.walk(path):
for f in files:
if name.lower() == f.lower():
return os.path.join(root, f)
def deploy(name, dst, dry_run=False):
dlls_path = []
parse_imports_recursive(name, dlls_path)
for dll_entry in dlls_path:
if not dry_run:
shutil.copy(dll_entry, dst)
else:
print('[Dry-Run] Copy %s to %s' % (dll_entry, dst))
print('Deploy completed.')
return dlls_path
def main():
if len(sys.argv) < 3:
print('Usage: %s [files to examine ...] [target deploy directory]')
return 1
to_deploy = sys.argv[1:-1]
tgt_dir = sys.argv[-1]
if not os.path.isdir(tgt_dir):
print('%s is not a directory.' % tgt_dir)
return 1
print('Scanning dependencies...')
deploy(to_deploy, tgt_dir)
if missing:
print('Following DLLs are not found: %s' % ('\n'.join(missing)))
return 0
if __name__ == '__main__':
main()

View File

@ -1,13 +0,0 @@
#!/bin/bash -ex
. .ci/common/pre-upload.sh
REV_NAME="citra-windows-mingw-${GITDATE}-${GITREV}"
ARCHIVE_NAME="${REV_NAME}.tar.gz"
COMPRESSION_FLAGS="-czvf"
mkdir "$REV_NAME"
# get around the permission issues
cp -r package/* "$REV_NAME"
. .ci/common/post-upload.sh

20
.ci/linux.sh Executable file
View File

@ -0,0 +1,20 @@
#!/bin/sh -ex
mkdir build && cd build
cmake .. -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DENABLE_QT_TRANSLATION=ON \
-DCITRA_ENABLE_COMPATIBILITY_REPORTING=ON \
-DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON \
-DUSE_DISCORD_PRESENCE=ON
ninja
if [ "$TARGET" = "appimage" ]; then
ninja bundle
fi
ccache -s
ctest -VV -C Release

View File

@ -1,45 +1,43 @@
#!/bin/bash -ex
. .ci/common/pre-upload.sh
REV_NAME="citra-osx-${GITDATE}-${GITREV}"
ARCHIVE_NAME="${REV_NAME}.tar.gz"
COMPRESSION_FLAGS="-czvf"
ARTIFACTS_LIST=($ARTIFACTS)
BUNDLE_DIR=build/bundle
mkdir build
# Set up the base artifact to combine into.
BASE_ARTIFACT=${ARTIFACTS_LIST[0]}
BASE_ARTIFACT_ARCH="${BASE_ARTIFACT##*-}"
tar xf $BASE_ARTIFACT/$REV_NAME.tar.gz -C $BASE_ARTIFACT
mv $BASE_ARTIFACT/$REV_NAME $REV_NAME
mv $BASE_ARTIFACT $BUNDLE_DIR
# Executable binary paths that need to be combined.
BIN_PATHS=(citra citra-room citra-qt.app/Contents/MacOS/citra-qt)
# Dylib paths that need to be combined.
IFS=$'\n'
DYLIB_PATHS=($(cd $REV_NAME && find . -name '*.dylib'))
DYLIB_PATHS=($(cd $BUNDLE_DIR && find . -name '*.dylib'))
unset IFS
# Combine all of the executable binaries and dylibs.
for OTHER_ARTIFACT in "${ARTIFACTS_LIST[@]:1}"; do
OTHER_ARTIFACT_ARCH="${OTHER_ARTIFACT##*-}"
tar xf $OTHER_ARTIFACT/$REV_NAME.tar.gz -C $OTHER_ARTIFACT
for BIN_PATH in "${BIN_PATHS[@]}"; do
lipo -create -output $REV_NAME/$BIN_PATH $REV_NAME/$BIN_PATH $OTHER_ARTIFACT/$REV_NAME/$BIN_PATH
lipo -create -output $BUNDLE_DIR/$BIN_PATH $BUNDLE_DIR/$BIN_PATH $OTHER_ARTIFACT/$BIN_PATH
done
for DYLIB_PATH in "${DYLIB_PATHS[@]}"; do
# Only merge if the libraries do not have conflicting arches, otherwise it will fail.
DYLIB_INFO=`file $REV_NAME/$DYLIB_PATH`
OTHER_DYLIB_INFO=`file $OTHER_ARTIFACT/$REV_NAME/$DYLIB_PATH`
DYLIB_INFO=`file $BUNDLE_DIR/$DYLIB_PATH`
OTHER_DYLIB_INFO=`file $OTHER_ARTIFACT/$DYLIB_PATH`
if ! [[ "$DYLIB_INFO" =~ "$OTHER_ARTIFACT_ARCH" ]] && ! [[ "$OTHER_DYLIB_INFO" =~ "$BASE_ARTIFACT_ARCH" ]]; then
lipo -create -output $REV_NAME/$DYLIB_PATH $REV_NAME/$DYLIB_PATH $OTHER_ARTIFACT/$REV_NAME/$DYLIB_PATH
lipo -create -output $BUNDLE_DIR/$DYLIB_PATH $BUNDLE_DIR/$DYLIB_PATH $OTHER_ARTIFACT/$DYLIB_PATH
fi
done
done
. .ci/common/post-upload.sh
# Re-sign executables and bundles after combining.
APP_PATHS=(citra citra-room citra-qt.app)
for APP_PATH in "${APP_PATHS[@]}"; do
codesign --deep -fs - $BUNDLE_DIR/$APP_PATH
done

21
.ci/macos.sh Executable file
View File

@ -0,0 +1,21 @@
#!/bin/bash -ex
mkdir build && cd build
cmake .. -GNinja \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_OSX_ARCHITECTURES="$TARGET" \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DENABLE_QT_TRANSLATION=ON \
-DCITRA_ENABLE_COMPATIBILITY_REPORTING=ON \
-DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON \
-DUSE_DISCORD_PRESENCE=ON
ninja
ninja bundle
ccache -s
CURRENT_ARCH=`arch`
if [ "$TARGET" = "$CURRENT_ARCH" ]; then
ctest -VV -C Release
fi

View File

@ -1,35 +0,0 @@
#!/bin/bash -ex
set -o pipefail
export PATH="/usr/local/opt/ccache/libexec:$PATH"
# ccache configurations
export CCACHE_CPP2=yes
export CCACHE_SLOPPINESS=time_macros
export CC="ccache clang"
export CXX="ccache clang++"
export OBJC="clang"
export ASM="clang"
ccache -s
mkdir build && cd build
# TODO: LibreSSL ASM disabled due to platform detection issues in build.
cmake .. -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_OSX_ARCHITECTURES="$TARGET_ARCH" \
-DENABLE_QT_TRANSLATION=ON \
-DCITRA_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} \
-DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON \
-DUSE_DISCORD_PRESENCE=ON \
-DENABLE_FFMPEG_VIDEO_DUMPER=ON \
-DENABLE_ASM=OFF \
-GNinja
ninja
ccache -s
CURRENT_ARCH=`arch`
if [ "$TARGET_ARCH" = "$CURRENT_ARCH" ]; then
ctest -VV -C Release
fi

View File

@ -1,3 +0,0 @@
#!/bin/sh -ex
brew install ccache ninja || true

View File

@ -1,16 +0,0 @@
#!/bin/bash -ex
. .ci/common/pre-upload.sh
REV_NAME="citra-osx-${GITDATE}-${GITREV}"
ARCHIVE_NAME="${REV_NAME}.tar.gz"
COMPRESSION_FLAGS="-czvf"
mkdir "$REV_NAME"
cp build/bin/Release/citra "$REV_NAME"
cp -r build/bin/Release/libs "$REV_NAME"
cp -r build/bin/Release/citra-qt.app "$REV_NAME"
cp build/bin/Release/citra-room "$REV_NAME"
. .ci/common/post-upload.sh

48
.ci/pack.sh Executable file
View File

@ -0,0 +1,48 @@
#!/bin/bash -ex
GITDATE="`git show -s --date=short --format='%ad' | sed 's/-//g'`"
GITREV="`git show -s --format='%h'`"
REV_NAME="citra-${OS}-${TARGET}-${GITDATE}-${GITREV}"
# Find out what release we are building
if [[ "$GITHUB_REF_NAME" =~ ^canary- ]] || [[ "$GITHUB_REF_NAME" =~ ^nightly- ]]; then
RELEASE_NAME=$(echo $GITHUB_REF_NAME | cut -d- -f1)
# For compatibility with existing installs, use mingw/osx in the archive and target names.
if [ "$TARGET" = "msys2" ]; then
REV_NAME="citra-${OS}-mingw-${GITDATE}-${GITREV}"
RELEASE_NAME="${RELEASE_NAME}-mingw"
elif [ "$OS" = "macos" ]; then
REV_NAME="citra-osx-${TARGET}-${GITDATE}-${GITREV}"
fi
else
RELEASE_NAME=head
fi
mkdir -p artifacts
if [ -z "${UPLOAD_RAW}" ]; then
# Archive and upload the artifacts.
mkdir "$REV_NAME"
mv build/bundle/* "$REV_NAME"
if [ "$OS" = "windows" ]; then
ARCHIVE_NAME="${REV_NAME}.zip"
powershell Compress-Archive "$REV_NAME" "$ARCHIVE_NAME"
else
ARCHIVE_NAME="${REV_NAME}.tar.gz"
tar czvf "$ARCHIVE_NAME" "$REV_NAME"
fi
mv "$REV_NAME" $RELEASE_NAME
7z a "$REV_NAME.7z" $RELEASE_NAME
mv "$ARCHIVE_NAME" artifacts/
mv "$REV_NAME.7z" artifacts/
else
# Directly upload the raw artifacts, renamed with the revision.
for ARTIFACT in build/bundle/*; do
FILENAME=$(basename "$ARTIFACT")
EXTENSION="${FILENAME##*.}"
mv "$ARTIFACT" "artifacts/$REV_NAME.$EXTENSION"
done
fi

View File

@ -1,9 +1,13 @@
#!/bin/bash -ex
. .ci/common/pre-upload.sh
GITDATE="`git show -s --date=short --format='%ad' | sed 's/-//g'`"
GITREV="`git show -s --format='%h'`"
REV_NAME="citra-unified-source-${GITDATE}-${GITREV}"
COMPAT_LIST='dist/compatibility_list/compatibility_list.json'
mkdir artifacts
pip3 install git-archive-all
wget -q https://api.citra-emu.org/gamedb -O "${COMPAT_LIST}"
git describe --abbrev=0 --always HEAD > GIT-COMMIT

View File

@ -1,6 +1,4 @@
#!/bin/bash -e
set -x
#!/bin/bash -ex
echo -e "\e[1m\e[33mBuild tools information:\e[0m"
cmake --version

View File

@ -1,3 +0,0 @@
#!/bin/bash -e
docker run -e TRANSIFEX_API_TOKEN="${TRANSIFEX_API_TOKEN}" -v "$(pwd)":/citra citraemu/build-environments:linux-transifex /bin/sh -e /citra/.travis/transifex/docker.sh

View File

@ -1,21 +0,0 @@
#!/bin/sh -ex
mkdir build && cd build
cmake .. \
-DCMAKE_BUILD_TYPE=Release \
-G Ninja \
-DCMAKE_TOOLCHAIN_FILE="$(pwd)/../CMakeModules/MSVCCache.cmake" \
-DCITRA_USE_CCACHE=ON \
-DENABLE_QT_TRANSLATION=ON \
-DCITRA_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} \
-DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON \
-DUSE_DISCORD_PRESENCE=ON \
-DENABLE_MF=ON \
-DENABLE_FFMPEG_VIDEO_DUMPER=ON \
-DOPENSSL_DLL_DIR="C:\Program Files\OpenSSL\bin"
ninja
# show the caching efficiency
buildcache -s
ctest -VV -C Release || echo "::error ::Test error occurred on Windows MSVC build"

View File

@ -1,10 +0,0 @@
#!/bin/sh -ex
BUILDCACHE_VERSION="0.22.3"
choco install wget ninja
# Install buildcache
wget "https://github.com/mbitsnbites/buildcache/releases/download/v${BUILDCACHE_VERSION}/buildcache-win-mingw.zip"
7z x 'buildcache-win-mingw.zip'
mv ./buildcache/bin/buildcache.exe "/c/ProgramData/chocolatey/bin"
rm -rf ./buildcache/

View File

@ -1,41 +0,0 @@
$GITDATE = $(git show -s --date=short --format='%ad') -replace "-", ""
$GITREV = $(git show -s --format='%h')
# Find out what release we are building
if ( $env:GITHUB_REF_NAME -like "*canary-*" -or $env:GITHUB_REF_NAME -like "*nightly-*" ) {
$RELEASE_NAME = ${env:GITHUB_REF_NAME}.split("-")[0]
$RELEASE_NAME = "${RELEASE_NAME}-msvc"
}
else {
$RELEASE_NAME = "head"
}
$MSVC_BUILD_ZIP = "citra-windows-msvc-$GITDATE-$GITREV.zip" -replace " ", ""
$MSVC_SEVENZIP = "citra-windows-msvc-$GITDATE-$GITREV.7z" -replace " ", ""
$BUILD_DIR = ".\build\bin\Release"
# Create artifact directories
mkdir $RELEASE_NAME
mkdir "artifacts"
echo "Starting to pack ${RELEASE_NAME}"
Copy-Item $BUILD_DIR\* -Destination $RELEASE_NAME -Recurse
Remove-Item $RELEASE_NAME\tests.* -ErrorAction ignore
Remove-Item $RELEASE_NAME\*.pdb -ErrorAction ignore
# Copy documentation
Copy-Item license.txt -Destination $RELEASE_NAME
Copy-Item README.md -Destination $RELEASE_NAME
# Copy cross-platform scripting support
Copy-Item dist\scripting -Destination $RELEASE_NAME -Recurse
# Build the final release artifacts
7z a -tzip $MSVC_BUILD_ZIP $RELEASE_NAME\*
7z a $MSVC_SEVENZIP $RELEASE_NAME
Copy-Item $MSVC_BUILD_ZIP -Destination "artifacts"
Copy-Item $MSVC_SEVENZIP -Destination "artifacts"

17
.ci/windows.sh Normal file
View File

@ -0,0 +1,17 @@
#!/bin/sh -ex
mkdir build && cd build
cmake .. -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DENABLE_QT_TRANSLATION=ON \
-DCITRA_ENABLE_COMPATIBILITY_REPORTING=ON \
-DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON \
-DUSE_DISCORD_PRESENCE=ON
ninja
ninja bundle
ccache -s
ctest -VV -C Release || echo "::error ::Test error occurred on Windows build"

View File

@ -43,7 +43,7 @@ body:
id: log
attributes:
label: Log File
description: A log file will help our developers to better diagnose and fix the issue.
description: A log file will help our developers to better diagnose and fix the issue. Instructions can be found [here](https://community.citra-emu.org/t/how-to-upload-the-log-file/296).
validations:
required: true
- type: textarea

View File

@ -11,7 +11,7 @@ jobs:
clang-format:
runs-on: ubuntu-latest
container:
image: citraemu/build-environments:linux-clang-format
image: citraemu/build-environments:linux-fresh
options: -u 1001
steps:
- uses: actions/checkout@v3
@ -20,41 +20,7 @@ jobs:
- name: Build
env:
COMMIT_RANGE: ${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }}
run: ./.ci/linux-clang-format/docker.sh
build:
runs-on: ubuntu-latest
strategy:
matrix:
image: ["linux-appimage", "linux-fresh", "linux-frozen", "linux-mingw"]
container:
image: citraemu/build-environments:${{ matrix.image }}
options: -u 1001
steps:
- uses: actions/checkout@v3
with:
submodules: recursive
- name: Set up cache
uses: actions/cache@v3
with:
path: ~/.ccache
key: ${{ runner.os }}-${{ matrix.image }}-${{ github.sha }}
restore-keys: |
${{ runner.os }}-${{ matrix.image }}-
- name: Build
run: ./.ci/${{ matrix.image }}/docker.sh
env:
ENABLE_COMPATIBILITY_REPORTING: "ON"
- name: Pack
run: ./.ci/${{ matrix.image }}/upload.sh
if: ${{ matrix.image != 'linux-frozen' }}
env:
NAME: ${{ matrix.image }}
- name: Upload
uses: actions/upload-artifact@v3
if: ${{ matrix.image != 'linux-frozen' }}
with:
name: ${{ matrix.image }}
path: artifacts/
run: ./.ci/clang-format.sh
source:
if: ${{ !github.head_ref }}
runs-on: ubuntu-latest
@ -63,17 +29,57 @@ jobs:
with:
submodules: recursive
- name: Pack
run: ./.ci/source/build.sh
run: ./.ci/source.sh
- name: Upload
uses: actions/upload-artifact@v3
with:
name: source
path: artifacts/
linux:
runs-on: ubuntu-latest
strategy:
matrix:
target: ["appimage", "fresh"]
container:
image: citraemu/build-environments:linux-${{ matrix.target }}
options: -u 1001
env:
CCACHE_DIR: ${{ github.workspace }}/.ccache
OS: linux
TARGET: ${{ matrix.target }}
steps:
- uses: actions/checkout@v3
with:
submodules: recursive
- name: Set up cache
uses: actions/cache@v3
with:
path: ${{ env.CCACHE_DIR }}
key: ${{ runner.os }}-${{ matrix.target }}-${{ github.sha }}
restore-keys: |
${{ runner.os }}-${{ matrix.target }}-
- name: Build
run: ./.ci/linux.sh
- name: Pack
run: ./.ci/pack.sh
if: ${{ matrix.target == 'appimage' }}
- name: Upload
uses: actions/upload-artifact@v3
if: ${{ matrix.target == 'appimage' }}
with:
name: ${{ env.OS }}-${{ env.TARGET }}
path: artifacts/
macos:
runs-on: macos-latest
strategy:
matrix:
arch: ["x86_64", "arm64"]
target: ["x86_64", "arm64"]
env:
CCACHE_CPP2: yes
CCACHE_SLOPPINESS: time_macros
CCACHE_DIR: ${{ github.workspace }}/.ccache
OS: macos
TARGET: ${{ matrix.target }}
steps:
- uses: actions/checkout@v3
with:
@ -81,59 +87,66 @@ jobs:
- name: Set up cache
uses: actions/cache@v3
with:
path: ~/Library/Caches/ccache
key: ${{ runner.os }}-macos-${{ matrix.arch }}-${{ github.sha }}
path: ${{ env.CCACHE_DIR }}
key: ${{ runner.os }}-${{ matrix.target }}-${{ github.sha }}
restore-keys: |
${{ runner.os }}-macos-${{ matrix.arch }}-
- name: Install dependencies
run: ./.ci/macos/deps.sh
${{ runner.os }}-${{ matrix.target }}-
- name: Install tools
run: brew install ccache glslang ninja
- name: Build
run: ./.ci/macos/build.sh
env:
MACOSX_DEPLOYMENT_TARGET: "11"
ENABLE_COMPATIBILITY_REPORTING: "ON"
TARGET_ARCH: ${{ matrix.arch }}
- name: Pack
run: ./.ci/macos/upload.sh
- name: Upload
uses: actions/upload-artifact@v3
run: ./.ci/macos.sh
- name: Prepare outputs for caching
run: mv build/bundle $OS-$TARGET
- name: Cache outputs for universal build
uses: actions/cache/save@v3
with:
name: macos-${{ matrix.arch }}
path: artifacts/
path: ${{ env.OS }}-${{ env.TARGET }}
key: ${{ runner.os }}-${{ matrix.target }}-${{ github.sha }}-${{ github.run_id }}-${{ github.run_attempt }}
macos-universal:
runs-on: macos-latest
needs: macos
env:
OS: macos
TARGET: universal
steps:
- uses: actions/checkout@v3
with:
submodules: recursive
- name: Download x86 build
uses: actions/download-artifact@master
- name: Download x86_64 build from cache
uses: actions/cache/restore@v3
with:
name: macos-x86_64
path: macos-x86_64/
- name: Download ARM64 build
uses: actions/download-artifact@master
path: ${{ env.OS }}-x86_64
key: ${{ runner.os }}-x86_64-${{ github.sha }}-${{ github.run_id }}-${{ github.run_attempt }}
fail-on-cache-miss: true
- name: Download ARM64 build from cache
uses: actions/cache/restore@v3
with:
name: macos-arm64
path: macos-arm64/
path: ${{ env.OS }}-arm64
key: ${{ runner.os }}-arm64-${{ github.sha }}-${{ github.run_id }}-${{ github.run_attempt }}
fail-on-cache-miss: true
- name: Create universal app
run: ./.ci/macos/universal.sh
run: ./.ci/macos-universal.sh
env:
ARTIFACTS: macos-x86_64 macos-arm64
ARTIFACTS: ${{ env.OS }}-x86_64 ${{ env.OS }}-arm64
- name: Pack
run: ./.ci/pack.sh
# - name: Upload
# uses: actions/upload-artifact@v3
# with:
# name: macos
# name: ${{ env.OS }}-${{ env.TARGET }}
# path: artifacts/
- name: Delete intermediate artifacts
uses: geekyeggo/delete-artifact@v2
with:
name: |
macos-x86_64
macos-arm64
windows:
runs-on: windows-latest
strategy:
matrix:
target: ["msvc", "msys2"]
defaults:
run:
shell: ${{ (matrix.target == 'msys2' && 'msys2') || 'bash' }} {0}
env:
CCACHE_DIR: ${{ github.workspace }}/.ccache
OS: windows
TARGET: ${{ matrix.target }}
steps:
- uses: actions/checkout@v3
with:
@ -141,29 +154,50 @@ jobs:
- name: Set up cache
uses: actions/cache@v3
with:
path: ~/.buildcache
key: ${{ runner.os }}-win-${{ github.sha }}
path: ${{ env.CCACHE_DIR }}
key: ${{ runner.os }}-${{ matrix.target }}-${{ github.sha }}
restore-keys: |
${{ runner.os }}-win-
- name: Install dependencies
run: ./.ci/windows-msvc/deps.sh
shell: bash
${{ runner.os }}-${{ matrix.target }}-
- name: Set up MSVC
uses: ilammy/msvc-dev-cmd@v1
if: ${{ matrix.target == 'msvc' }}
- name: Install MSVC extra tools
run: choco install ccache ninja wget
if: ${{ matrix.target == 'msvc' }}
- name: Set up MSYS2
uses: msys2/setup-msys2@v2
if: ${{ matrix.target == 'msys2' }}
with:
msystem: clang64
update: true
install: git make p7zip
pacboy: >-
toolchain:p ccache:p cmake:p ninja:p
qt6-base:p qt6-multimedia:p qt6-multimedia-wmf:p qt6-tools:p qt6-translations:p
- name: Setup Vulkan SDK
uses: humbletim/setup-vulkan-sdk@v1.2.0
with:
vulkan-query-version: latest
vulkan-components: Glslang
vulkan-use-cache: true
- name: Test glslangValidator
run: glslangValidator --version
- name: Disable line ending translation
run: git config --global core.autocrlf input
- name: Build
run: ./.ci/windows-msvc/build.sh
shell: bash
env:
ENABLE_COMPATIBILITY_REPORTING: "ON"
run: ./.ci/windows.sh
- name: Pack
run: ./.ci/windows-msvc/upload.ps1
run: ./.ci/pack.sh
- name: Upload
uses: actions/upload-artifact@v3
with:
name: msvc
name: ${{ env.OS }}-${{ env.TARGET }}
path: artifacts/
android:
runs-on: ubuntu-latest
env:
OS: android
TARGET: universal
steps:
- uses: actions/checkout@v3
with:
@ -186,24 +220,28 @@ jobs:
echo $GIT_TAG_NAME
- name: Deps
run: |
sudo apt-get update
sudo apt-get install ccache apksigner -y
sudo add-apt-repository -y ppa:theofficialgman/gpu-tools
sudo apt-get update -y
sudo apt-get install ccache glslang-dev glslang-tools apksigner -y
- name: Build
run: ./.ci/android/build.sh
- name: Copy and sign artifacts
run: JAVA_HOME=$JAVA_HOME_17_X64 ./.ci/android.sh
env:
ANDROID_KEYSTORE_B64: ${{ secrets.ANDROID_KEYSTORE_B64 }}
ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }}
ANDROID_KEYSTORE_PASS: ${{ secrets.ANDROID_KEYSTORE_PASS }}
run: ./.ci/android/upload.sh
- name: Pack
run: ../../../.ci/pack.sh
working-directory: src/android/app
env:
UPLOAD_RAW: 1
- name: Upload
uses: actions/upload-artifact@v3
with:
name: android
path: artifacts/
name: ${{ env.OS }}-${{ env.TARGET }}
path: src/android/app/artifacts/
transifex:
runs-on: ubuntu-latest
container: citraemu/build-environments:linux-transifex
container: citraemu/build-environments:linux-fresh
if: ${{ github.repository == 'citra-emu/citra' && !github.head_ref }}
steps:
- uses: actions/checkout@v3
@ -211,12 +249,12 @@ jobs:
submodules: recursive
fetch-depth: 0
- name: Update Translation
run: ./.ci/transifex/docker.sh
run: ./.ci/transifex.sh
env:
TX_TOKEN: ${{ secrets.TRANSIFEX_API_TOKEN }}
release:
runs-on: ubuntu-latest
needs: [build, android, macos-universal, source, windows]
needs: [windows, linux, macos-universal, android, source]
if: ${{ startsWith(github.ref, 'refs/tags/') }}
steps:
- uses: actions/download-artifact@v3

4
.gitignore vendored
View File

@ -13,6 +13,8 @@ src/common/scm_rev.cpp
.vs/
.vscode/
.cache/
cmake-build-debug/
cmake-build-release/
CMakeLists.txt.user*
# *nix related
@ -41,4 +43,6 @@ Thumbs.db
repo/
# GitHub Actions generated files
.ccache/
node_modules/
VULKAN_SDK/

23
.gitmodules vendored
View File

@ -36,7 +36,7 @@
url = https://github.com/mozilla/cubeb
[submodule "discord-rpc"]
path = externals/discord-rpc
url = https://github.com/discord/discord-rpc.git
url = https://github.com/yuzu-emu/discord-rpc.git
[submodule "cpp-jwt"]
path = externals/cpp-jwt
url = https://github.com/arun11299/cpp-jwt.git
@ -64,6 +64,21 @@
[submodule "dds-ktx"]
path = externals/dds-ktx
url = https://github.com/septag/dds-ktx
[submodule "externals/openal-soft"]
path = externals/openal-soft
url = https://github.com/kcat/openal-soft
[submodule "openal-soft"]
path = externals/openal-soft
url = https://github.com/kcat/openal-soft
[submodule "glslang"]
path = externals/glslang
url = https://github.com/KhronosGroup/glslang
[submodule "vma"]
path = externals/vma
url = https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator
[submodule "vulkan-headers"]
path = externals/vulkan-headers
url = https://github.com/KhronosGroup/Vulkan-Headers
[submodule "sirit"]
path = externals/sirit
url = https://github.com/yuzu-emu/sirit
[submodule "library-headers"]
path = externals/library-headers/library-headers
url = https://github.com/citra-emu/ext-library-headers.git

View File

@ -5,6 +5,10 @@ cmake_minimum_required(VERSION 3.15)
cmake_policy(SET CMP0092 NEW)
# Enforce new LTO setting
cmake_policy(SET CMP0069 NEW)
# Honor visibility properties for all targets
# Set the default so subdirectory cmake_minimum_required calls won't unset the policy.
cmake_policy(SET CMP0063 NEW)
set(CMAKE_POLICY_DEFAULT_CMP0063 NEW)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/externals/cmake-modules")
@ -14,67 +18,70 @@ include(CMakeDependentOption)
project(citra LANGUAGES C CXX ASM)
if (APPLE)
enable_language(OBJC)
# Silence warnings on empty objects, for example when platform-specific code is #ifdef'd out.
set(CMAKE_C_ARCHIVE_CREATE "<CMAKE_AR> Scr <TARGET> <LINK_FLAGS> <OBJECTS>")
set(CMAKE_CXX_ARCHIVE_CREATE "<CMAKE_AR> Scr <TARGET> <LINK_FLAGS> <OBJECTS>")
set(CMAKE_C_ARCHIVE_FINISH "<CMAKE_RANLIB> -no_warning_for_no_symbols -c <TARGET>")
set(CMAKE_CXX_ARCHIVE_FINISH "<CMAKE_RANLIB> -no_warning_for_no_symbols -c <TARGET>")
if (IOS)
# Minimum iOS 14
set(CMAKE_OSX_DEPLOYMENT_TARGET "14.0")
# Enable searching CMAKE_PREFIX_PATH for bundled dependencies.
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE BOTH)
else()
# Minimum macOS 11
set(CMAKE_OSX_DEPLOYMENT_TARGET "11.0")
endif()
endif()
option(ENABLE_LTO "Enable link time optimization" OFF)
if (CMAKE_BUILD_TYPE STREQUAL Debug)
set(IS_DEBUG_BUILD ON)
else()
set(IS_DEBUG_BUILD OFF)
endif()
option(ENABLE_SDL2 "Enable the SDL2 frontend" ON)
option(ENABLE_SDL2 "Enable using SDL2" ON)
CMAKE_DEPENDENT_OPTION(ENABLE_SDL2_FRONTEND "Enable the SDL2 frontend" ON "ENABLE_SDL2;NOT ANDROID AND NOT IOS" OFF)
option(USE_SYSTEM_SDL2 "Use the system SDL2 lib (instead of the bundled one)" OFF)
# Set bundled qt as dependent options.
option(ENABLE_QT "Enable the Qt frontend" ON)
option(ENABLE_QT_TRANSLATION "Enable translations for the Qt frontend" OFF)
CMAKE_DEPENDENT_OPTION(CITRA_USE_BUNDLED_QT "Download bundled Qt binaries" ON "ENABLE_QT;MSVC OR APPLE" OFF)
CMAKE_DEPENDENT_OPTION(ENABLE_QT_UPDATER "Enable built-in updater for the Qt frontend" ON "NOT IOS" OFF)
CMAKE_DEPENDENT_OPTION(ENABLE_TESTS "Enable generating tests executable" ON "NOT IOS" OFF)
CMAKE_DEPENDENT_OPTION(ENABLE_DEDICATED_ROOM "Enable generating dedicated room executable" ON "NOT ANDROID AND NOT IOS" OFF)
option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON)
if (MSVC)
set(OPENSSL_DLL_DIR "" CACHE PATH "Location of the Openssl dlls")
endif()
option(ENABLE_CUBEB "Enables the cubeb audio backend" ON)
CMAKE_DEPENDENT_OPTION(ENABLE_CUBEB "Enables the cubeb audio backend" ON "NOT IOS" OFF)
option(ENABLE_OPENAL "Enables the OpenAL audio backend" ON)
CMAKE_DEPENDENT_OPTION(ENABLE_LIBUSB "Enable libusb for GameCube Adapter support" ON "NOT IOS" OFF)
option(ENABLE_FFMPEG_AUDIO_DECODER "Enable FFmpeg audio (AAC) decoder" OFF)
option(ENABLE_FFMPEG_VIDEO_DUMPER "Enable FFmpeg video dumper" OFF)
if (ENABLE_FFMPEG_AUDIO_DECODER OR ENABLE_FFMPEG_VIDEO_DUMPER)
set(ENABLE_FFMPEG ON)
endif()
CMAKE_DEPENDENT_OPTION(CITRA_USE_BUNDLED_FFMPEG "Download bundled FFmpeg binaries" ON "ENABLE_FFMPEG;MSVC OR APPLE" OFF)
option(USE_DISCORD_PRESENCE "Enables Discord Rich Presence" OFF)
option(CITRA_USE_PRECOMPILED_HEADERS "Use precompiled headers" ON)
CMAKE_DEPENDENT_OPTION(ENABLE_MF "Use Media Foundation decoder (preferred over FFmpeg)" ON "WIN32" OFF)
CMAKE_DEPENDENT_OPTION(ENABLE_AUDIOTOOLBOX "Use AudioToolbox decoder (preferred over FFmpeg)" ON "APPLE" OFF)
CMAKE_DEPENDENT_OPTION(COMPILE_WITH_DWARF "Add DWARF debugging information" ON "MINGW" OFF)
option(USE_SYSTEM_BOOST "Use the system Boost libs (instead of the bundled ones)" OFF)
CMAKE_DEPENDENT_OPTION(ENABLE_FDK "Use FDK AAC decoder" OFF "NOT ENABLE_FFMPEG_AUDIO_DECODER;NOT ENABLE_MF" OFF)
CMAKE_DEPENDENT_OPTION(CITRA_BUNDLE_LIBRARIES "Bundle dependent libraries with the output executables" ON "APPLE" OFF)
# Compile options
CMAKE_DEPENDENT_OPTION(COMPILE_WITH_DWARF "Add DWARF debugging information" ${IS_DEBUG_BUILD} "MINGW" OFF)
option(ENABLE_LTO "Enable link time optimization" OFF)
option(CITRA_USE_PRECOMPILED_HEADERS "Use precompiled headers" ON)
option(CITRA_WARNINGS_AS_ERRORS "Enable warnings as errors" ON)
if (CITRA_USE_PRECOMPILED_HEADERS)
if (MSVC AND CCACHE)
# buildcache does not properly cache PCH files, leading to compilation errors.
# See https://github.com/mbitsnbites/buildcache/discussions/230
message(WARNING "Buildcache does not properly support Precompiled Headers. Disabling PCH")
set(CITRA_USE_PRECOMPILED_HEADERS OFF)
endif()
if(APPLE)
message(WARNING "Precompiled Headers currently do not work on Apple. Disabling PCH")
set(CITRA_USE_PRECOMPILED_HEADERS OFF)
endif()
endif()
# System library options
CMAKE_DEPENDENT_OPTION(USE_SYSTEM_QT "Use the system Qt lib (instead of the bundled one)" OFF "ENABLE_QT;MSVC OR APPLE" ON)
CMAKE_DEPENDENT_OPTION(USE_SYSTEM_MOLTENVK "Use the system MoltenVK lib (instead of the bundled one)" OFF "APPLE" OFF)
option(USE_SYSTEM_SDL2 "Use the system SDL2 lib (instead of the bundled one)" OFF)
option(USE_SYSTEM_BOOST "Use the system Boost libs (instead of the bundled ones)" OFF)
option(USE_SYSTEM_OPENSSL "Use the system OpenSSL libs (instead of the bundled LibreSSL)" OFF)
option(USE_SYSTEM_LIBUSB "Use the system libusb (instead of the bundled libusb)" OFF)
if (CITRA_USE_PRECOMPILED_HEADERS)
message(STATUS "Using Precompiled Headers.")
set(CMAKE_PCH_INSTANTIATE_TEMPLATES ON)
@ -124,7 +131,10 @@ function(check_submodules_present)
endif()
endforeach()
endfunction()
check_submodules_present()
if (EXISTS "${PROJECT_SOURCE_DIR}/.git/objects")
# only check submodules when source is obtained via Git
check_submodules_present()
endif()
configure_file(${PROJECT_SOURCE_DIR}/dist/compatibility_list/compatibility_list.qrc
${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.qrc
@ -187,9 +197,15 @@ message(STATUS "Target architecture: ${ARCHITECTURE}")
# boost asio's concept usage doesn't play nicely with some compilers yet.
add_definitions(-DBOOST_ASIO_DISABLE_CONCEPTS)
# boost can have issues compiling with C++17 and up on newer versions of Clang.
add_definitions(-DBOOST_NO_CXX98_FUNCTION_BASE)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Apply consistent visibility settings.
set(CMAKE_CXX_VISIBILITY_PRESET default)
set(CMAKE_VISIBILITY_INLINES_HIDDEN NO)
# set up output paths for executable binaries
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin/$<CONFIG>)
@ -202,9 +218,8 @@ set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
if (ENABLE_QT)
if (CITRA_USE_BUNDLED_QT)
download_qt_external(6.5.0 QT_PREFIX)
list(APPEND CMAKE_PREFIX_PATH ${QT_PREFIX})
if (NOT USE_SYSTEM_QT)
download_qt(6.5.0)
endif()
find_package(Qt6 REQUIRED COMPONENTS Widgets Multimedia Concurrent)
@ -216,63 +231,6 @@ if (ENABLE_QT)
if (ENABLE_QT_TRANSLATION)
find_package(Qt6 REQUIRED COMPONENTS LinguistTools)
endif()
if (NOT CITRA_USE_BUNDLED_QT)
# Make sure the Qt bin directory is in the prefix path for later use, such as in post-build scripts.
get_target_property(qmake_executable Qt6::qmake IMPORTED_LOCATION)
get_filename_component(qt_bin_dir "${qmake_executable}" DIRECTORY)
list(APPEND CMAKE_PREFIX_PATH ${qt_bin_dir})
endif()
endif()
# Ensure libusb is properly configured (based on dolphin libusb include)
if (ENABLE_LIBUSB)
if(NOT APPLE)
include(FindPkgConfig)
find_package(LibUSB)
endif()
if (NOT LIBUSB_FOUND)
add_subdirectory(externals/libusb)
set(LIBUSB_INCLUDE_DIR "")
set(LIBUSB_LIBRARIES usb)
endif()
endif()
if (ENABLE_FFMPEG)
if (CITRA_USE_BUNDLED_FFMPEG)
if ((MSVC_VERSION GREATER_EQUAL 1920 AND MSVC_VERSION LESS 1940) AND "x86_64" IN_LIST ARCHITECTURE)
set(FFmpeg_VER "ffmpeg-4.1-win64")
elseif (APPLE)
set(FFmpeg_VER "ffmpeg-6.0")
else()
message(FATAL_ERROR "No bundled FFmpeg binaries for your toolchain. Disable CITRA_USE_BUNDLED_FFMPEG and provide your own.")
endif()
if (DEFINED FFmpeg_VER)
download_bundled_external("ffmpeg/" ${FFmpeg_VER} FFmpeg_PREFIX)
set(FFMPEG_DIR "${FFmpeg_PREFIX}")
endif()
endif()
if (ENABLE_FFMPEG_VIDEO_DUMPER)
find_package(FFmpeg REQUIRED COMPONENTS avcodec avformat avutil swscale swresample)
else()
find_package(FFmpeg REQUIRED COMPONENTS avcodec)
endif()
if ("${FFmpeg_avcodec_VERSION}" VERSION_LESS "57.48.101")
message(FATAL_ERROR "Found version for libavcodec is too low. The required version is at least 57.48.101 (included in FFmpeg 3.1 and later).")
endif()
endif()
if (ENABLE_FFMPEG_VIDEO_DUMPER)
add_definitions(-DENABLE_FFMPEG_VIDEO_DUMPER)
endif()
if (ENABLE_FDK)
find_library(FDK_AAC fdk-aac DOC "The path to fdk_aac library")
if(FDK_AAC STREQUAL "FDK_AAC-NOTFOUND")
message(FATAL_ERROR "fdk_aac library not found.")
endif()
endif()
# Use system tsl::robin_map if available (otherwise we fallback to version bundled with dynarmic)
@ -282,10 +240,20 @@ find_package(tsl-robin-map QUIET)
# ======================================
if (APPLE)
# Umbrella framework for everything GUI-related
find_library(COCOA_LIBRARY Cocoa)
find_library(AVFOUNDATION_LIBRARY AVFoundation)
set(PLATFORM_LIBRARIES ${COCOA_LIBRARY} ${AVFOUNDATION_LIBRARY} ${IOKIT_LIBRARY} ${COREVIDEO_LIBRARY})
if (NOT USE_SYSTEM_MOLTENVK)
download_moltenvk()
endif()
find_library(MOLTENVK_LIBRARY MoltenVK REQUIRED)
message(STATUS "Using MoltenVK at ${MOLTENVK_LIBRARY}.")
if (NOT IOS)
# Umbrella framework for everything GUI-related
find_library(COCOA_LIBRARY Cocoa REQUIRED)
endif()
find_library(AVFOUNDATION_LIBRARY AVFoundation REQUIRED)
find_library(IOSURFACE_LIBRARY IOSurface REQUIRED)
set(PLATFORM_LIBRARIES ${COCOA_LIBRARY} ${AVFOUNDATION_LIBRARY} ${IOSURFACE_LIBRARY} ${MOLTENVK_LIBRARY})
elseif (WIN32)
set(PLATFORM_LIBRARIES winmm ws2_32)
if (MINGW)
@ -336,7 +304,7 @@ if (CLANG_FORMAT)
add_custom_target(clang-format
COMMAND powershell.exe -Command "Get-ChildItem '${SRCS}/*' -Include *.cpp,*.h,*.mm -Recurse | Foreach {&'${CLANG_FORMAT}' -i $_.fullname}"
COMMENT ${CCOMMENT})
endif()
endif()
else()
add_custom_target(clang-format
COMMAND find ${SRCS} -iname *.h -o -iname *.cpp -o -iname *.mm | xargs ${CLANG_FORMAT} -i
@ -394,11 +362,6 @@ endif()
enable_testing()
add_subdirectory(externals)
# See externals/CMakeLists.txt
foreach(def ${CRYPTOPP_COMPILE_DEFINITIONS})
add_definitions(-D${def})
endforeach()
# Boost
if (USE_SYSTEM_BOOST)
find_package(Boost 1.70.0 COMPONENTS serialization iostreams REQUIRED)
@ -417,6 +380,11 @@ if (ENABLE_SDL2 AND USE_SYSTEM_SDL2)
add_library(SDL2::SDL2 ALIAS SDL2)
endif()
if (ENABLE_LIBUSB AND USE_SYSTEM_LIBUSB)
include(FindPkgConfig)
find_package(LibUSB)
endif()
add_subdirectory(src)
add_subdirectory(dist/installer)
@ -428,6 +396,20 @@ else()
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT citra)
endif()
# Create target for outputting distributable bundles.
if (NOT ANDROID AND NOT IOS)
include(BundleTarget)
if (ENABLE_SDL2_FRONTEND)
bundle_target(citra)
endif()
if (ENABLE_QT)
bundle_target(citra-qt)
endif()
if (ENABLE_DEDICATED_ROOM)
bundle_target(citra-room)
endif()
endif()
# Installation instructions
# =========================
@ -436,7 +418,7 @@ endif()
# http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html
# http://standards.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-latest.html
if(ENABLE_QT AND UNIX AND NOT APPLE)
install(FILES "${PROJECT_SOURCE_DIR}/dist/citra.desktop"
install(FILES "${PROJECT_SOURCE_DIR}/dist/citra-qt.desktop"
DESTINATION "${CMAKE_INSTALL_PREFIX}/share/applications")
install(FILES "${PROJECT_SOURCE_DIR}/dist/citra.svg"
DESTINATION "${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/scalable/apps")

View File

@ -12,7 +12,7 @@ endif()
list(APPEND CMAKE_MODULE_PATH "${BASE_DIR}/CMakeModules")
include(DownloadExternals)
download_qt_external(tools_ifw QT_PREFIX)
download_qt(tools_ifw QT_PREFIX)
file(GLOB_RECURSE INSTALLER_BASE "${QT_PREFIX}/**/installerbase*")
file(GLOB_RECURSE BINARY_CREATOR "${QT_PREFIX}/**/binarycreator*")

View File

@ -1,66 +0,0 @@
# Bundles libraries with an output executable.
# Parameters:
# - TYPE: "qt" or "standalone". The type of app to bundle.
# - "qt" uses windeployqt/macdeployqt to bundle Qt and other libraries.
# - "standalone" copies dependent libraries to a "libs" folder alongside the executable file.
# - EXECUTABLE_PATH: Path to the executable binary.
# TODO: This does not really work fully for Windows yet, some libraries are missing from the output.
# TODO: Leaving a basic framework of Windows support here to be iterated on in the future.
if (WIN32)
message(FATAL_ERROR "Advanced library bundling is not yet supported for Windows.")
endif()
if ("${TYPE}" STREQUAL "qt")
get_filename_component(executable_dir ${EXECUTABLE_PATH} DIRECTORY)
# Bundle dependencies using appropriate Qt tool.
if (WIN32)
find_program(WINDEPLOYQT_EXECUTABLE windeployqt)
execute_process(COMMAND ${WINDEPLOYQT_EXECUTABLE} ${EXECUTABLE_PATH}
--no-compiler-runtime --no-system-d3d-compiler --no-opengl-sw --no-translations
--plugindir "${executable_dir}/plugins")
elseif (APPLE)
get_filename_component(contents_dir ${executable_dir} DIRECTORY)
get_filename_component(bundle_dir ${contents_dir} DIRECTORY)
find_program(MACDEPLOYQT_EXECUTABLE macdeployqt)
execute_process(COMMAND ${MACDEPLOYQT_EXECUTABLE} ${bundle_dir} -executable=${EXECUTABLE_PATH} -always-overwrite)
# Bundling libraries can rewrite path information and break code signatures of system libraries.
# Perform an ad-hoc re-signing on the whole app bundle to fix this.
execute_process(COMMAND codesign --deep -fs - ${bundle_dir})
else()
message(FATAL_ERROR "Unsupported OS for Qt-based library bundling.")
endif()
else()
# Resolve dependent library files.
file(GET_RUNTIME_DEPENDENCIES
EXECUTABLES ${EXECUTABLE_PATH}
RESOLVED_DEPENDENCIES_VAR resolved_deps
UNRESOLVED_DEPENDENCIES_VAR unresolved_deps
POST_EXCLUDE_REGEXES ".*system32/.*\\.dll")
# Determine libraries directory.
get_filename_component(executable_dir ${EXECUTABLE_PATH} DIRECTORY)
if (WIN32)
# Same directory since we don't have rpath.
set(lib_dir ${executable_dir})
else()
set(lib_dir ${executable_dir}/libs)
endif()
# Copy library files to bundled output.
file(MAKE_DIRECTORY ${lib_dir})
foreach (lib_file ${resolved_deps})
# Use native copy to turn symlinks into normal files.
execute_process(COMMAND cp -L ${lib_file} ${lib_dir})
endforeach()
# Add libs directory to executable rpath where applicable.
if (APPLE)
execute_process(COMMAND install_name_tool -add_rpath "@loader_path/libs" ${EXECUTABLE_PATH})
elseif (UNIX)
execute_process(COMMAND patchelf --set-rpath '$ORIGIN/../libs' ${EXECUTABLE_PATH})
endif()
endif()

View File

@ -0,0 +1,271 @@
if (BUNDLE_TARGET_EXECUTE)
# --- Bundling method logic ---
function(bundle_qt executable_path)
if (WIN32)
get_filename_component(executable_parent_dir "${executable_path}" DIRECTORY)
find_program(windeployqt_executable windeployqt6)
# Create a qt.conf file pointing to the app directory.
# This ensures Qt can find its plugins.
file(WRITE "${executable_parent_dir}/qt.conf" "[Paths]\nprefix = .")
message(STATUS "Executing windeployqt for executable ${executable_path}")
execute_process(COMMAND "${windeployqt_executable}" "${executable_path}"
--no-compiler-runtime --no-system-d3d-compiler --no-opengl-sw --no-translations
--plugindir "${executable_parent_dir}/plugins")
# Remove the FFmpeg multimedia plugin as we don't include FFmpeg.
# We want to use the Windows media plugin instead, which is also included.
file(REMOVE "${executable_parent_dir}/plugins/multimedia/ffmpegmediaplugin.dll")
elseif (APPLE)
get_filename_component(executable_name "${executable_path}" NAME_WE)
find_program(MACDEPLOYQT_EXECUTABLE macdeployqt6)
message(STATUS "Executing macdeployqt for executable ${executable_path}")
execute_process(
COMMAND "${MACDEPLOYQT_EXECUTABLE}"
"${executable_path}"
"-executable=${executable_path}/Contents/MacOS/${executable_name}"
-always-overwrite)
# Bundling libraries can rewrite path information and break code signatures of system libraries.
# Perform an ad-hoc re-signing on the whole app bundle to fix this.
execute_process(COMMAND codesign --deep -fs - "${executable_path}")
else()
message(FATAL_ERROR "Unsupported OS for Qt bundling.")
endif()
endfunction()
function(bundle_appimage bundle_dir executable_path source_path binary_path linuxdeploy_executable enable_qt)
get_filename_component(executable_name "${executable_path}" NAME_WE)
set(appdir_path "${binary_path}/AppDir-${executable_name}")
if (enable_qt)
# Find qmake to make sure the plugin uses the right version of Qt.
find_program(QMAKE_EXECUTABLE qmake6)
set(extra_linuxdeploy_env "QMAKE=${QMAKE_EXECUTABLE}")
set(extra_linuxdeploy_args --plugin qt)
endif()
message(STATUS "Creating AppDir for executable ${executable_path}")
execute_process(COMMAND ${CMAKE_COMMAND} -E env
${extra_linuxdeploy_env}
"${linuxdeploy_executable}"
${extra_linuxdeploy_args}
--plugin checkrt
--executable "${executable_path}"
--icon-file "${source_path}/dist/citra.svg"
--desktop-file "${source_path}/dist/${executable_name}.desktop"
--appdir "${appdir_path}")
if (enable_qt)
set(qt_hook_file "${appdir_path}/apprun-hooks/linuxdeploy-plugin-qt-hook.sh")
file(READ "${qt_hook_file}" qt_hook_contents)
# Add Cinnamon to list of DEs for GTK3 theming.
string(REPLACE
"*XFCE*"
"*X-Cinnamon*|*XFCE*"
qt_hook_contents "${qt_hook_contents}")
# Wayland backend crashes due to changed schemas in Gnome 40.
string(REPLACE
"export QT_QPA_PLATFORMTHEME=gtk3"
"export QT_QPA_PLATFORMTHEME=gtk3; export GDK_BACKEND=x11"
qt_hook_contents "${qt_hook_contents}")
file(WRITE "${qt_hook_file}" "${qt_hook_contents}")
endif()
message(STATUS "Creating AppImage for executable ${executable_path}")
execute_process(COMMAND ${CMAKE_COMMAND} -E env
"OUTPUT=${bundle_dir}/${executable_name}.AppImage"
"${linuxdeploy_executable}"
--output appimage
--appdir "${appdir_path}")
endfunction()
function(bundle_standalone executable_path original_executable_path bundle_library_paths)
get_filename_component(executable_parent_dir "${executable_path}" DIRECTORY)
# Resolve dependent library files if they were not passed in.
message(STATUS "Determining runtime dependencies of ${executable_path} using library paths ${bundle_library_paths}")
file(GET_RUNTIME_DEPENDENCIES
EXECUTABLES ${original_executable_path}
RESOLVED_DEPENDENCIES_VAR resolved_deps
UNRESOLVED_DEPENDENCIES_VAR unresolved_deps
DIRECTORIES ${bundle_library_paths}
POST_EXCLUDE_REGEXES ".*system32.*")
if (WIN32)
# Same directory since we don't have rpath.
set(lib_dir "${executable_parent_dir}")
else()
set(lib_dir "${executable_parent_dir}/libs")
endif()
# Copy files to bundled output.
if (resolved_deps)
file(MAKE_DIRECTORY ${lib_dir})
foreach (lib_file IN LISTS resolved_deps)
message(STATUS "Bundling library ${lib_file}")
# Use native copy to turn symlinks into normal files.
execute_process(COMMAND cp -L "${lib_file}" "${lib_dir}")
endforeach()
endif()
# Add libs directory to executable rpath where applicable.
if (APPLE)
execute_process(COMMAND install_name_tool -add_rpath "@loader_path/libs" "${executable_path}")
elseif (UNIX)
execute_process(COMMAND patchelf --set-rpath '$ORIGIN/../libs' "${executable_path}")
endif()
endfunction()
# --- Root bundling logic ---
set(bundle_dir ${BINARY_PATH}/bundle)
# On Linux, always bundle an AppImage.
if (DEFINED LINUXDEPLOY)
if (IN_PLACE)
message(FATAL_ERROR "Cannot bundle for Linux in-place.")
endif()
bundle_appimage("${bundle_dir}" "${EXECUTABLE_PATH}" "${SOURCE_PATH}" "${BINARY_PATH}" "${LINUXDEPLOY}" ${BUNDLE_QT})
else()
if (IN_PLACE)
message(STATUS "Bundling dependencies in-place")
set(bundled_executable_path "${EXECUTABLE_PATH}")
else()
message(STATUS "Copying base executable ${EXECUTABLE_PATH} to output directory ${bundle_dir}")
file(COPY ${EXECUTABLE_PATH} DESTINATION ${bundle_dir})
get_filename_component(bundled_executable_name "${EXECUTABLE_PATH}" NAME)
set(bundled_executable_path "${bundle_dir}/${bundled_executable_name}")
endif()
if (BUNDLE_QT)
bundle_qt("${bundled_executable_path}")
endif()
if (WIN32 OR NOT BUNDLE_QT)
bundle_standalone("${bundled_executable_path}" "${EXECUTABLE_PATH}" "${BUNDLE_LIBRARY_PATHS}")
endif()
endif()
else()
# --- Bundling target creation logic ---
# Downloads and extracts a linuxdeploy component.
function(download_linuxdeploy_component base_dir name executable_name)
set(executable_file "${base_dir}/${executable_name}")
if (NOT EXISTS "${executable_file}")
message(STATUS "Downloading ${executable_name}")
file(DOWNLOAD
"https://github.com/linuxdeploy/${name}/releases/download/continuous/${executable_name}"
"${executable_file}" SHOW_PROGRESS)
file(CHMOD "${executable_file}" PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE)
get_filename_component(executable_ext "${executable_file}" LAST_EXT)
if (executable_ext STREQUAL ".AppImage")
message(STATUS "Extracting ${executable_name}")
execute_process(
COMMAND "${executable_file}" --appimage-extract
WORKING_DIRECTORY "${base_dir}")
else()
message(STATUS "Copying ${executable_name}")
file(COPY "${executable_file}" DESTINATION "${base_dir}/squashfs-root/usr/bin/")
endif()
endif()
endfunction()
# Adds a target to the bundle target, packing in required libraries.
# If in_place is true, the bundling will be done in-place as part of the specified target.
function(bundle_target_internal target_name in_place)
# Create base bundle target if it does not exist.
if (NOT in_place AND NOT TARGET bundle)
message(STATUS "Creating base bundle target")
add_custom_target(bundle)
add_custom_command(
TARGET bundle
COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/bundle/")
add_custom_command(
TARGET bundle
COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_SOURCE_DIR}/license.txt" "${CMAKE_BINARY_DIR}/bundle/")
add_custom_command(
TARGET bundle
COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_SOURCE_DIR}/README.md" "${CMAKE_BINARY_DIR}/bundle/")
add_custom_command(
TARGET bundle
COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_SOURCE_DIR}/dist/scripting" "${CMAKE_BINARY_DIR}/bundle/scripting")
endif()
set(BUNDLE_EXECUTABLE_PATH "$<TARGET_FILE:${target_name}>")
if (target_name MATCHES ".*qt")
set(BUNDLE_QT ON)
if (APPLE)
# For Qt targets on Apple, expect an app bundle.
set(BUNDLE_EXECUTABLE_PATH "$<TARGET_BUNDLE_DIR:${target_name}>")
endif()
else()
set(BUNDLE_QT OFF)
endif()
# Build a list of library search paths from prefix paths.
foreach(prefix_path IN LISTS CMAKE_PREFIX_PATH CMAKE_SYSTEM_PREFIX_PATH)
if (WIN32)
list(APPEND BUNDLE_LIBRARY_PATHS "${prefix_path}/bin")
endif()
list(APPEND BUNDLE_LIBRARY_PATHS "${prefix_path}/lib")
endforeach()
foreach(library_path IN LISTS CMAKE_SYSTEM_LIBRARY_PATH)
list(APPEND BUNDLE_LIBRARY_PATHS "${library_path}")
endforeach()
# On Linux, prepare linuxdeploy and any required plugins.
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
set(LINUXDEPLOY_BASE "${CMAKE_BINARY_DIR}/externals/linuxdeploy")
# Download plugins first so they don't overwrite linuxdeploy's AppRun file.
download_linuxdeploy_component("${LINUXDEPLOY_BASE}" "linuxdeploy-plugin-qt" "linuxdeploy-plugin-qt-x86_64.AppImage")
download_linuxdeploy_component("${LINUXDEPLOY_BASE}" "linuxdeploy-plugin-checkrt" "linuxdeploy-plugin-checkrt-x86_64.sh")
download_linuxdeploy_component("${LINUXDEPLOY_BASE}" "linuxdeploy" "linuxdeploy-x86_64.AppImage")
set(EXTRA_BUNDLE_ARGS "-DLINUXDEPLOY=${LINUXDEPLOY_BASE}/squashfs-root/AppRun")
endif()
if (in_place)
message(STATUS "Adding in-place bundling to ${target_name}")
set(DEST_TARGET ${target_name})
else()
message(STATUS "Adding ${target_name} to bundle target")
set(DEST_TARGET bundle)
add_dependencies(bundle ${target_name})
endif()
add_custom_command(TARGET ${DEST_TARGET} POST_BUILD
COMMAND ${CMAKE_COMMAND}
"-DCMAKE_PREFIX_PATH=\"${CMAKE_PREFIX_PATH}\""
"-DBUNDLE_TARGET_EXECUTE=1"
"-DTARGET=${target_name}"
"-DSOURCE_PATH=${CMAKE_SOURCE_DIR}"
"-DBINARY_PATH=${CMAKE_BINARY_DIR}"
"-DEXECUTABLE_PATH=${BUNDLE_EXECUTABLE_PATH}"
"-DBUNDLE_LIBRARY_PATHS=\"${BUNDLE_LIBRARY_PATHS}\""
"-DBUNDLE_QT=${BUNDLE_QT}"
"-DIN_PLACE=${in_place}"
${EXTRA_BUNDLE_ARGS}
-P "${CMAKE_SOURCE_DIR}/CMakeModules/BundleTarget.cmake"
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}")
endfunction()
# Adds a target to the bundle target, packing in required libraries.
function(bundle_target target_name)
bundle_target_internal("${target_name}" OFF)
endfunction()
# Bundles the target in-place, packing in required libraries.
function(bundle_target_in_place target_name)
bundle_target_internal("${target_name}" ON)
endfunction()
endif()

View File

@ -1,11 +0,0 @@
function(copy_citra_FFmpeg_deps target_dir)
include(WindowsCopyFiles)
set(DLL_DEST "${CMAKE_BINARY_DIR}/bin/$<CONFIG>/")
windows_copy_files(${target_dir} ${FFMPEG_DIR}/bin ${DLL_DEST}
avcodec*.dll
avformat*.dll
avutil*.dll
swresample*.dll
swscale*.dll
)
endfunction(copy_citra_FFmpeg_deps)

View File

@ -1,6 +0,0 @@
function(copy_citra_openssl_deps target_dir)
include(WindowsCopyFiles)
set(DLL_DEST "${CMAKE_BINARY_DIR}/bin/$<CONFIG>/")
windows_copy_files(${target_dir} ${OPENSSL_DLL_DIR} ${DLL_DEST} libcrypto-1_1-x64.dll)
windows_copy_files(${target_dir} ${OPENSSL_DLL_DIR} ${DLL_DEST} libssl-1_1-x64.dll)
endfunction(copy_citra_openssl_deps)

View File

@ -1,46 +0,0 @@
function(copy_citra_Qt6_deps target_dir)
include(WindowsCopyFiles)
set(DLL_DEST "${CMAKE_BINARY_DIR}/bin/$<CONFIG>/")
set(Qt6_DLL_DIR "${Qt6_DIR}/../../../bin")
set(Qt6_PLATFORMS_DIR "${Qt6_DIR}/../../../plugins/platforms/")
set(Qt6_MULTIMEDIA_DIR "${Qt6_DIR}/../../../plugins/multimedia/")
set(Qt6_STYLES_DIR "${Qt6_DIR}/../../../plugins/styles/")
set(Qt6_IMAGEFORMATS_DIR "${Qt6_DIR}/../../../plugins/imageformats/")
set(PLATFORMS ${DLL_DEST}plugins/platforms/)
set(MULTIMEDIA ${DLL_DEST}plugins/multimedia/)
set(STYLES ${DLL_DEST}plugins/styles/)
set(IMAGEFORMATS ${DLL_DEST}plugins/imageformats/)
windows_copy_files(${target_dir} ${Qt6_DLL_DIR} ${DLL_DEST}
icudt*.dll
icuin*.dll
icuuc*.dll
Qt6Core$<$<CONFIG:Debug>:d>.*
Qt6Gui$<$<CONFIG:Debug>:d>.*
Qt6Widgets$<$<CONFIG:Debug>:d>.*
Qt6Concurrent$<$<CONFIG:Debug>:d>.*
Qt6Multimedia$<$<CONFIG:Debug>:d>.*
Qt6Network$<$<CONFIG:Debug>:d>.*
)
windows_copy_files(citra-qt ${Qt6_PLATFORMS_DIR} ${PLATFORMS} qwindows$<$<CONFIG:Debug>:d>.*)
windows_copy_files(citra-qt ${Qt6_MULTIMEDIA_DIR} ${MULTIMEDIA}
windowsmediaplugin$<$<CONFIG:Debug>:d>.*
)
windows_copy_files(citra-qt ${Qt6_STYLES_DIR} ${STYLES} qwindowsvistastyle$<$<CONFIG:Debug>:d>.*)
windows_copy_files(${target_dir} ${Qt6_IMAGEFORMATS_DIR} ${IMAGEFORMATS}
qgif$<$<CONFIG:Debug>:d>.dll
qicns$<$<CONFIG:Debug>:d>.dll
qico$<$<CONFIG:Debug>:d>.dll
qjpeg$<$<CONFIG:Debug>:d>.dll
qsvg$<$<CONFIG:Debug>:d>.dll
qtga$<$<CONFIG:Debug>:d>.dll
qtiff$<$<CONFIG:Debug>:d>.dll
qwbmp$<$<CONFIG:Debug>:d>.dll
qwebp$<$<CONFIG:Debug>:d>.dll
)
# Create an empty qt.conf file. Qt will detect that this file exists, and use the folder that its in as the root folder.
# This way it'll look for plugins in the root/plugins/ folder
add_custom_command(TARGET citra-qt POST_BUILD
COMMAND ${CMAKE_COMMAND} -E touch ${DLL_DEST}qt.conf
)
endfunction(copy_citra_Qt6_deps)

View File

@ -1,96 +1,117 @@
# This function downloads a binary library package from our external repo.
# Params:
# remote_path: path to the file to download, relative to the remote repository root
# prefix_var: name of a variable which will be set with the path to the extracted contents
function(download_bundled_external remote_path lib_name prefix_var)
get_external_prefix(${lib_name} prefix)
if (NOT EXISTS "${prefix}")
message(STATUS "Downloading binaries for ${lib_name}...")
if (WIN32)
set(repo_base "ext-windows-bin/raw/master")
elseif (APPLE)
set(repo_base "ext-macos-bin/raw/main")
else()
message(FATAL_ERROR "Bundled libraries are unsupported for this OS.")
endif()
file(DOWNLOAD
https://github.com/citra-emu/${repo_base}/${remote_path}${lib_name}.7z
"${CMAKE_BINARY_DIR}/externals/${lib_name}.7z" SHOW_PROGRESS)
execute_process(COMMAND ${CMAKE_COMMAND} -E tar xf "${CMAKE_BINARY_DIR}/externals/${lib_name}.7z"
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/externals")
endif()
# For packages that include the /usr/local prefix, include it in the prefix path.
if (EXISTS "${prefix}/usr/local")
set(prefix "${prefix}/usr/local")
endif()
message(STATUS "Using bundled binaries at ${prefix}")
set(${prefix_var} "${prefix}" PARENT_SCOPE)
endfunction()
# This function downloads Qt using aqt.
# Params:
# target: Qt dependency to install. Specify a version number to download Qt, or "tools_(name)" for a specific build tool.
# prefix_var: Name of a variable which will be set with the path to the extracted contents.
function(download_qt_external target prefix_var)
function(download_qt target)
# Determine installation parameters for OS, architecture, and compiler
if (WIN32)
set(host "windows")
set(type "desktop")
if (MINGW)
set(arch_path "mingw81")
elseif ((MSVC_VERSION GREATER_EQUAL 1920 AND MSVC_VERSION LESS 1940) AND "x86_64" IN_LIST ARCHITECTURE)
set(arch "win64_mingw")
set(arch_path "mingw_64")
elseif (MSVC)
if ("arm64" IN_LIST ARCHITECTURE)
set(arch_path "msvc2019_arm64")
elseif ("x86_64" IN_LIST ARCHITECTURE)
set(arch_path "msvc2019_64")
else()
message(FATAL_ERROR "Unsupported bundled Qt architecture. Disable CITRA_USE_BUNDLED_QT and provide your own.")
message(FATAL_ERROR "Unsupported bundled Qt architecture. Enable USE_SYSTEM_QT and provide your own.")
endif()
set(arch "win64_${arch_path}")
else()
message(FATAL_ERROR "Unsupported bundled Qt toolchain. Disable CITRA_USE_BUNDLED_QT and provide your own.")
message(FATAL_ERROR "Unsupported bundled Qt toolchain. Enable USE_SYSTEM_QT and provide your own.")
endif()
set(arch "win64_${arch_path}")
elseif (APPLE)
set(host "mac")
set(arch "clang_64")
set(arch_path "macos")
if (IOS)
set(type "ios")
set(arch "ios")
set(arch_path "ios")
set(host_arch_path "macos")
else()
set(type "desktop")
set(arch "clang_64")
set(arch_path "macos")
endif()
else()
set(host "linux")
set(type "desktop")
set(arch "gcc_64")
set(arch_path "linux")
endif()
get_external_prefix(qt base_path)
file(MAKE_DIRECTORY "${base_path}")
if (target MATCHES "tools_.*")
set(prefix "${base_path}")
set(install_args install-tool --outputdir ${base_path} ${host} desktop ${target})
else()
set(prefix "${base_path}/${target}/${arch_path}")
set(install_args install-qt --outputdir ${base_path} ${host} desktop ${target} ${arch} -m qtmultimedia)
if (host_arch_path)
set(host_flag "--autodesktop")
set(host_prefix "${base_path}/${target}/${host_arch_path}")
endif()
set(install_args install-qt --outputdir ${base_path} ${host} ${type} ${target} ${arch} ${host_flag} -m qtmultimedia)
endif()
if (NOT EXISTS "${prefix}")
message(STATUS "Downloading binaries for Qt...")
if (WIN32)
set(aqt_path "${CMAKE_BINARY_DIR}/externals/aqt.exe")
set(aqt_path "${base_path}/aqt.exe")
file(DOWNLOAD
https://github.com/miurahr/aqtinstall/releases/download/v3.1.4/aqt.exe
${aqt_path} SHOW_PROGRESS)
execute_process(COMMAND ${aqt_path} ${install_args})
execute_process(COMMAND ${aqt_path} ${install_args}
WORKING_DIRECTORY ${base_path})
else()
# aqt does not offer binary releases for other platforms, so download and run from pip.
set(aqt_install_path "${CMAKE_BINARY_DIR}/externals/aqt")
execute_process(COMMAND python3 -m pip install --target=${aqt_install_path} aqtinstall)
execute_process(COMMAND ${CMAKE_COMMAND} -E env PYTHONPATH=${aqt_install_path} python3 -m aqt ${install_args})
set(aqt_install_path "${base_path}/aqt")
file(MAKE_DIRECTORY "${aqt_install_path}")
execute_process(COMMAND python3 -m pip install --target=${aqt_install_path} aqtinstall
WORKING_DIRECTORY ${base_path})
execute_process(COMMAND ${CMAKE_COMMAND} -E env PYTHONPATH=${aqt_install_path} python3 -m aqt ${install_args}
WORKING_DIRECTORY ${base_path})
endif()
endif()
message(STATUS "Using downloaded Qt binaries at ${prefix}")
set(${prefix_var} "${prefix}" PARENT_SCOPE)
# Add the Qt prefix path so CMake can locate it.
list(APPEND CMAKE_PREFIX_PATH "${prefix}")
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} PARENT_SCOPE)
if (DEFINED host_prefix)
message(STATUS "Using downloaded host Qt binaries at ${host_prefix}")
set(QT_HOST_PATH "${host_prefix}" CACHE STRING "")
endif()
endfunction()
function(download_moltenvk)
if (IOS)
set(MOLTENVK_PLATFORM "iOS")
else()
set(MOLTENVK_PLATFORM "macOS")
endif()
set(MOLTENVK_DIR "${CMAKE_BINARY_DIR}/externals/MoltenVK")
set(MOLTENVK_TAR "${CMAKE_BINARY_DIR}/externals/MoltenVK.tar")
if (NOT EXISTS ${MOLTENVK_DIR})
if (NOT EXISTS ${MOLTENVK_TAR})
file(DOWNLOAD https://github.com/KhronosGroup/MoltenVK/releases/latest/download/MoltenVK-all.tar
${MOLTENVK_TAR} SHOW_PROGRESS)
endif()
execute_process(COMMAND ${CMAKE_COMMAND} -E tar xf "${MOLTENVK_TAR}"
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/externals")
endif()
# Add the MoltenVK library path to the prefix so find_library can locate it.
list(APPEND CMAKE_PREFIX_PATH "${MOLTENVK_DIR}/MoltenVK/dylib/${MOLTENVK_PLATFORM}")
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} PARENT_SCOPE)
endfunction()
function(get_external_prefix lib_name prefix_var)

View File

@ -0,0 +1,67 @@
# Gets a UTC timstamp and sets the provided variable to it
function(get_timestamp _var)
string(TIMESTAMP timestamp UTC)
set(${_var} "${timestamp}" PARENT_SCOPE)
endfunction()
get_timestamp(BUILD_DATE)
list(APPEND CMAKE_MODULE_PATH "${SRC_DIR}/externals/cmake-modules")
if (EXISTS "${SRC_DIR}/.git/objects")
# Find the package here with the known path so that the GetGit commands can find it as well
find_package(Git QUIET PATHS "${GIT_EXECUTABLE}")
# only use Git to check revision info when source is obtained via Git
include(GetGitRevisionDescription)
get_git_head_revision(GIT_REF_SPEC GIT_REV)
git_describe(GIT_DESC --always --long --dirty)
git_branch_name(GIT_BRANCH)
elseif (EXISTS "${SRC_DIR}/GIT-COMMIT" AND EXISTS "${SRC_DIR}/GIT-TAG")
# unified source archive
file(READ "${SRC_DIR}/GIT-COMMIT" GIT_REV_RAW LIMIT 64)
string(STRIP "${GIT_REV_RAW}" GIT_REV)
string(SUBSTRING "${GIT_REV_RAW}" 0 9 GIT_DESC)
set(GIT_BRANCH "HEAD")
else()
# self-packed archive?
set(GIT_REV "UNKNOWN")
set(GIT_DESC "UNKNOWN")
set(GIT_BRANCH "UNKNOWN")
endif()
string(SUBSTRING "${GIT_REV}" 0 7 GIT_SHORT_REV)
# Generate cpp with Git revision from template
# Also if this is a CI build, add the build name (ie: Nightly, Canary) to the scm_rev file as well
set(REPO_NAME "")
set(BUILD_VERSION "0")
set(BUILD_FULLNAME "${GIT_SHORT_REV}")
if (DEFINED ENV{CI})
if (DEFINED ENV{GITHUB_ACTIONS})
set(BUILD_REPOSITORY $ENV{GITHUB_REPOSITORY})
set(BUILD_TAG $ENV{GITHUB_REF_NAME})
endif()
# regex capture the string nightly or canary into CMAKE_MATCH_1
string(REGEX MATCH "citra-emu/citra-?(.*)" OUTVAR ${BUILD_REPOSITORY})
if ("${CMAKE_MATCH_COUNT}" GREATER 0)
# capitalize the first letter of each word in the repo name.
string(REPLACE "-" ";" REPO_NAME_LIST ${CMAKE_MATCH_1})
foreach(WORD ${REPO_NAME_LIST})
string(SUBSTRING ${WORD} 0 1 FIRST_LETTER)
string(SUBSTRING ${WORD} 1 -1 REMAINDER)
string(TOUPPER ${FIRST_LETTER} FIRST_LETTER)
set(REPO_NAME "${REPO_NAME}${FIRST_LETTER}${REMAINDER}")
endforeach()
string(REGEX MATCH "${CMAKE_MATCH_1}-([0-9]+)" OUTVAR ${BUILD_TAG})
if (${CMAKE_MATCH_COUNT} GREATER 0)
set(BUILD_VERSION ${CMAKE_MATCH_1})
endif()
if (BUILD_VERSION)
# This leaves a trailing space on the last word, but we actually want that
# because of how it's styled in the title bar.
set(BUILD_FULLNAME "${REPO_NAME} ${BUILD_VERSION} ")
else()
set(BUILD_FULLNAME "")
endif()
endif()
endif()

View File

@ -1,55 +1,5 @@
# Gets a UTC timstamp and sets the provided variable to it
function(get_timestamp _var)
string(TIMESTAMP timestamp UTC)
set(${_var} "${timestamp}" PARENT_SCOPE)
endfunction()
list(APPEND CMAKE_MODULE_PATH "${SRC_DIR}/externals/cmake-modules")
# Find the package here with the known path so that the GetGit commands can find it as well
find_package(Git QUIET PATHS "${GIT_EXECUTABLE}")
# generate git/build information
include(GetGitRevisionDescription)
get_git_head_revision(GIT_REF_SPEC GIT_REV)
git_describe(GIT_DESC --always --long --dirty)
git_branch_name(GIT_BRANCH)
get_timestamp(BUILD_DATE)
# Generate cpp with Git revision from template
# Also if this is a CI build, add the build name (ie: Nightly, Canary) to the scm_rev file as well
set(REPO_NAME "")
set(BUILD_VERSION "0")
if (DEFINED ENV{CI})
if (DEFINED ENV{GITHUB_ACTIONS})
set(BUILD_REPOSITORY $ENV{GITHUB_REPOSITORY})
set(BUILD_TAG $ENV{GITHUB_REF_NAME})
endif()
# regex capture the string nightly or canary into CMAKE_MATCH_1
string(REGEX MATCH "citra-emu/citra-?(.*)" OUTVAR ${BUILD_REPOSITORY})
if ("${CMAKE_MATCH_COUNT}" GREATER 0)
# capitalize the first letter of each word in the repo name.
string(REPLACE "-" ";" REPO_NAME_LIST ${CMAKE_MATCH_1})
foreach(WORD ${REPO_NAME_LIST})
string(SUBSTRING ${WORD} 0 1 FIRST_LETTER)
string(SUBSTRING ${WORD} 1 -1 REMAINDER)
string(TOUPPER ${FIRST_LETTER} FIRST_LETTER)
set(REPO_NAME "${REPO_NAME}${FIRST_LETTER}${REMAINDER}")
endforeach()
string(REGEX MATCH "${CMAKE_MATCH_1}-([0-9]+)" OUTVAR ${BUILD_TAG})
if (${CMAKE_MATCH_COUNT} GREATER 0)
set(BUILD_VERSION ${CMAKE_MATCH_1})
endif()
if (BUILD_VERSION)
# This leaves a trailing space on the last word, but we actually want that
# because of how it's styled in the title bar.
set(BUILD_FULLNAME "${REPO_NAME} ${BUILD_VERSION} ")
else()
set(BUILD_FULLNAME "")
endif()
endif()
endif()
list(APPEND CMAKE_MODULE_PATH "${SRC_DIR}/CMakeModules")
include(GenerateBuildInfo)
# The variable SRC_DIR must be passed into the script (since it uses the current build directory for all values of CMAKE_*_DIR)
set(VIDEO_CORE "${SRC_DIR}/src/video_core")

View File

@ -1,12 +0,0 @@
# buildcache wrapper
OPTION(CITRA_USE_CCACHE "Use buildcache for compilation" OFF)
IF(CITRA_USE_CCACHE)
FIND_PROGRAM(CCACHE buildcache)
IF (CCACHE)
MESSAGE(STATUS "Using buildcache found in PATH")
SET_PROPERTY(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ${CCACHE})
SET_PROPERTY(GLOBAL PROPERTY RULE_LAUNCH_LINK ${CCACHE})
ELSE(CCACHE)
MESSAGE(WARNING "CITRA_USE_CCACHE enabled, but no buildcache executable found")
ENDIF(CCACHE)
ENDIF(CITRA_USE_CCACHE)

View File

@ -1,52 +0,0 @@
SET(MINGW_PREFIX /usr/x86_64-w64-mingw32/)
SET(CMAKE_SYSTEM_NAME Windows)
SET(CMAKE_SYSTEM_PROCESSOR x86_64)
SET(CMAKE_FIND_ROOT_PATH ${MINGW_PREFIX})
SET(SDL2_PATH ${MINGW_PREFIX})
SET(MINGW_TOOL_PREFIX ${CMAKE_SYSTEM_PROCESSOR}-w64-mingw32-)
# Specify the cross compiler
SET(CMAKE_C_COMPILER ${MINGW_TOOL_PREFIX}gcc)
SET(CMAKE_CXX_COMPILER ${MINGW_TOOL_PREFIX}g++)
SET(CMAKE_RC_COMPILER ${MINGW_TOOL_PREFIX}windres)
# Mingw tools
SET(STRIP ${MINGW_TOOL_PREFIX}strip)
SET(WINDRES ${MINGW_TOOL_PREFIX}windres)
SET(ENV{PKG_CONFIG} ${MINGW_TOOL_PREFIX}pkg-config)
# ccache wrapper
OPTION(CITRA_USE_CCACHE "Use ccache for compilation" OFF)
IF(CITRA_USE_CCACHE)
FIND_PROGRAM(CCACHE ccache)
IF (CCACHE)
MESSAGE(STATUS "Using ccache found in PATH")
SET_PROPERTY(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ${CCACHE})
SET_PROPERTY(GLOBAL PROPERTY RULE_LAUNCH_LINK ${CCACHE})
ELSE(CCACHE)
MESSAGE(WARNING "CITRA_USE_CCACHE enabled, but no ccache found")
ENDIF(CCACHE)
ENDIF(CITRA_USE_CCACHE)
# Search for programs in the build host directories
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# Echo modified cmake vars to screen for debugging purposes
IF(NOT DEFINED ENV{MINGW_DEBUG_INFO})
MESSAGE("")
MESSAGE("Custom cmake vars: (blank = system default)")
MESSAGE("-----------------------------------------")
MESSAGE("* CMAKE_C_COMPILER : ${CMAKE_C_COMPILER}")
MESSAGE("* CMAKE_CXX_COMPILER : ${CMAKE_CXX_COMPILER}")
MESSAGE("* CMAKE_RC_COMPILER : ${CMAKE_RC_COMPILER}")
MESSAGE("* WINDRES : ${WINDRES}")
MESSAGE("* ENV{PKG_CONFIG} : $ENV{PKG_CONFIG}")
MESSAGE("* STRIP : ${STRIP}")
MESSAGE("* CITRA_USE_CCACHE : ${CITRA_USE_CCACHE}")
MESSAGE("")
# So that the debug info only appears once
SET(ENV{MINGW_DEBUG_INFO} SHOWN)
ENDIF()

View File

@ -2,45 +2,49 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleGetInfoString</key>
<string></string>
<key>CFBundleIconFile</key>
<string>citra.icns</string>
<key>CFBundleIdentifier</key>
<string>com.citra-emu.citra</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleLongVersionString</key>
<string></string>
<!-- Templated data -->
<key>CFBundleName</key>
<string>Citra</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string></string>
<key>CFBundleSignature</key>
<string>????</string>
<string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
<key>CFBundleVersion</key>
<string></string>
<key>CSResourcesFileMapped</key>
<true/>
<key>LSRequiresCarbon</key>
<true/>
<string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
<key>CFBundleShortVersionString</key>
<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
<key>CFBundleLongVersionString</key>
<string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string>
<key>CFBundleExecutable</key>
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
<key>CFBundleIconFile</key>
<string>${MACOSX_BUNDLE_ICON_FILE}</string>
<key>CFBundleGetInfoString</key>
<string>${MACOSX_BUNDLE_INFO_STRING}</string>
<key>NSHumanReadableCopyright</key>
<string></string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>NSHighResolutionCapable</key>
<string>True</string>
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
<!-- Fixed -->
<key>LSApplicationCategoryType</key>
<string>public.app-category.games</string>
<key>NSCameraUsageDescription</key>
<string>This app requires camera access to emulate the 3DS&apos;s cameras.</string>
<key>NSMicrophoneUsageDescription</key>
<string>This app requires microphone access to emulate the 3DS&apos;s microphone.</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.games</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CSResourcesFileMapped</key>
<true/>
<key>LSSupportsOpeningDocumentsInPlace</key>
<true/>
<key>NSHighResolutionCapable</key>
<string>True</string>
<key>UIFileSharingEnabled</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
</dict>
</plist>

42
dist/apple/LaunchScreen.storyboard vendored Normal file
View File

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="21701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" initialViewController="Y6W-OH-hqX">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21679"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="s0d-6b-0kx">
<objects>
<viewController id="Y6W-OH-hqX" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="5EZ-qb-Rvc">
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="launch_logo.png" translatesAutoresizingMaskIntoConstraints="NO" id="yrZ-hu-Uge">
<rect key="frame" x="-59.666666666666657" y="306" width="512.33333333333337" height="240"/>
<constraints>
<constraint firstAttribute="height" constant="240" id="VhL-hA-Bwr"/>
</constraints>
</imageView>
</subviews>
<viewLayoutGuide key="safeArea" id="vDu-zF-Fre"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="yrZ-hu-Uge" firstAttribute="centerX" secondItem="5EZ-qb-Rvc" secondAttribute="centerX" id="1y3-Mx-a65"/>
<constraint firstItem="yrZ-hu-Uge" firstAttribute="centerY" secondItem="5EZ-qb-Rvc" secondAttribute="centerY" id="vNO-xV-EPD"/>
</constraints>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="Ief-a0-LHa" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="219" y="18"/>
</scene>
</scenes>
<resources>
<image name="launch_logo.png" width="512" height="512"/>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
</resources>
</document>

BIN
dist/apple/launch_logo.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

15
dist/citra-qt.desktop vendored Normal file
View File

@ -0,0 +1,15 @@
[Desktop Entry]
Version=1.0
Type=Application
Name=Citra
GenericName=3DS Emulator
GenericName[fr]=Émulateur 3DS
Comment=Nintendo 3DS video game console emulator
Comment[fr]=Émulateur de console de jeu Nintendo 3DS
Icon=citra
TryExec=citra-qt
Exec=citra-qt %f
Categories=Game;Emulator;Qt;
MimeType=application/x-ctr-3dsx;application/x-ctr-cci;application/x-ctr-cia;application/x-ctr-cxi;
Keywords=3DS;Nintendo;
PrefersNonDefaultGPU=true

10
dist/citra-room.desktop vendored Normal file
View File

@ -0,0 +1,10 @@
[Desktop Entry]
Version=1.0
Type=Application
Name=Citra Room
Comment=Multiplayer room host for Citra
Icon=citra
TryExec=citra-room
Exec=citra-room %f
Categories=Game;Emulator;
Keywords=3DS;Nintendo

6
dist/citra.desktop vendored
View File

@ -7,9 +7,9 @@ GenericName[fr]=Émulateur 3DS
Comment=Nintendo 3DS video game console emulator
Comment[fr]=Émulateur de console de jeu Nintendo 3DS
Icon=citra
TryExec=citra-qt
Exec=citra-qt %f
Categories=Game;Emulator;Qt;
TryExec=citra
Exec=citra %f
Categories=Game;Emulator;
MimeType=application/x-ctr-3dsx;application/x-ctr-cci;application/x-ctr-cia;application/x-ctr-cxi;
Keywords=3DS;Nintendo;
PrefersNonDefaultGPU=true

View File

@ -1,3 +1,17 @@
QPushButton#GraphicsAPIStatusBarButton {
color: #656565;
border: 1px solid transparent;
background-color: transparent;
padding: 0px 3px 0px 3px;
text-align: center;
min-width: 60px;
min-height: 20px;
}
QPushButton#GraphicsAPIStatusBarButton:hover {
border: 1px solid #76797C;
}
QPushButton#3DOptionStatusBarButton {
color: #A5A5A5;
font-weight: bold;

View File

@ -1,3 +1,31 @@
QPushButton#TogglableStatusBarButton {
color: #959595;
border: 1px solid transparent;
background-color: transparent;
padding: 0px 3px 0px 3px;
text-align: center;
}
QPushButton#TogglableStatusBarButton:checked {
color: palette(text);
}
QPushButton#TogglableStatusBarButton:hover {
border: 1px solid #76797C;
}
QPushButton#GraphicsAPIStatusBarButton {
color: #656565;
border: 1px solid transparent;
background-color: transparent;
padding: 0px 3px 0px 3px;
text-align: center;
}
QPushButton#GraphicsAPIStatusBarButton:hover {
border: 1px solid #76797C;
}
QToolTip {
border: 1px solid #76797C;
background-color: #5A7566;

View File

@ -3,6 +3,8 @@
# Suppress warnings from external libraries
if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
add_compile_options(/W0)
else()
add_compile_options(-w)
endif()
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/CMakeModules)
@ -10,9 +12,9 @@ include(DownloadExternals)
include(ExternalProject)
# Boost
set(BOOST_ROOT "${CMAKE_SOURCE_DIR}/externals/boost")
set(Boost_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/externals/boost")
set(Boost_NO_SYSTEM_PATHS ON)
set(BOOST_ROOT "${CMAKE_SOURCE_DIR}/externals/boost" CACHE STRING "")
set(Boost_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/externals/boost" CACHE STRING "")
set(Boost_NO_SYSTEM_PATHS ON CACHE BOOL "")
add_library(boost INTERFACE)
target_include_directories(boost SYSTEM INTERFACE ${Boost_INCLUDE_DIR})
@ -33,23 +35,17 @@ target_link_libraries(boost_iostreams PUBLIC boost)
# Add additional boost libs here; remember to ALIAS them in the root CMakeLists!
# Catch2
set(CATCH_INSTALL_DOCS OFF)
set(CATCH_INSTALL_EXTRAS OFF)
set(CATCH_INSTALL_DOCS OFF CACHE BOOL "")
set(CATCH_INSTALL_EXTRAS OFF CACHE BOOL "")
add_subdirectory(catch2)
# Crypto++
set(CRYPTOPP_BUILD_DOCUMENTATION OFF)
set(CRYPTOPP_BUILD_TESTING OFF)
set(CRYPTOPP_INSTALL OFF)
set(CRYPTOPP_SOURCES "${CMAKE_SOURCE_DIR}/externals/cryptopp")
set(CRYPTOPP_BUILD_DOCUMENTATION OFF CACHE BOOL "")
set(CRYPTOPP_BUILD_TESTING OFF CACHE BOOL "")
set(CRYPTOPP_INSTALL OFF CACHE BOOL "")
set(CRYPTOPP_SOURCES "${CMAKE_SOURCE_DIR}/externals/cryptopp" CACHE STRING "")
add_subdirectory(cryptopp-cmake)
# HACK: Mismatch between compilation of CryptoPP and headers used in Citra can cause runtime issues.
# Pull out the compile definitions from CryptoPP and apply them to Citra as well to fix this.
# See: https://github.com/weidai11/cryptopp/issues/1191
get_source_file_property(CRYPTOPP_COMPILE_DEFINITIONS ${CRYPTOPP_SOURCES}/cryptlib.cpp TARGET_DIRECTORY cryptopp COMPILE_DEFINITIONS)
set(CRYPTOPP_COMPILE_DEFINITIONS ${CRYPTOPP_COMPILE_DEFINITIONS} PARENT_SCOPE)
# HACK: The logic to set up the base include directory for CryptoPP does not work with Android SDK CMake 3.22.1.
# Until there is a fixed version available, this code will detect and add in the proper include if it does not exist.
if(ANDROID)
@ -80,8 +76,8 @@ endif()
# Dynarmic
if ("x86_64" IN_LIST ARCHITECTURE OR "arm64" IN_LIST ARCHITECTURE)
set(DYNARMIC_TESTS OFF)
set(DYNARMIC_FRONTENDS "A32")
set(DYNARMIC_TESTS OFF CACHE BOOL "")
set(DYNARMIC_FRONTENDS "A32" CACHE STRING "")
add_subdirectory(dynarmic EXCLUDE_FROM_ALL)
endif()
@ -93,28 +89,43 @@ endif()
# Glad
add_subdirectory(glad)
# glslang
set(SKIP_GLSLANG_INSTALL ON CACHE BOOL "")
set(ENABLE_GLSLANG_BINARIES OFF CACHE BOOL "")
set(ENABLE_SPVREMAPPER OFF CACHE BOOL "")
set(ENABLE_CTEST OFF CACHE BOOL "")
set(ENABLE_HLSL OFF CACHE BOOL "")
add_subdirectory(glslang)
# inih
add_subdirectory(inih)
# MicroProfile
add_library(microprofile INTERFACE)
target_include_directories(microprofile INTERFACE ./microprofile)
target_include_directories(microprofile SYSTEM INTERFACE ./microprofile)
# Nihstro
add_library(nihstro-headers INTERFACE)
target_include_directories(nihstro-headers INTERFACE ./nihstro/include)
target_include_directories(nihstro-headers SYSTEM INTERFACE ./nihstro/include)
if (MSVC)
target_compile_options(nihstro-headers INTERFACE /W0)
# TODO: For some reason MSVC still applies this warning even with /W0 for externals.
target_compile_options(nihstro-headers INTERFACE /wd4715)
endif()
# Open Source Archives
add_subdirectory(open_source_archives)
# SoundTouch
# Dynamic library headers
add_subdirectory(library-headers EXCLUDE_FROM_ALL)
# SoundTouch
set(INTEGER_SAMPLES ON CACHE BOOL "")
set(SOUNDSTRETCH OFF CACHE BOOL "")
set(SOUNDTOUCH_DLL OFF CACHE BOOL "")
add_subdirectory(soundtouch)
add_subdirectory(soundtouch EXCLUDE_FROM_ALL)
# sirit
add_subdirectory(sirit EXCLUDE_FROM_ALL)
# Teakra
add_subdirectory(teakra EXCLUDE_FROM_ALL)
@ -124,6 +135,13 @@ if (ENABLE_SDL2 AND NOT USE_SYSTEM_SDL2)
add_subdirectory(sdl2)
endif()
# libusb
if (ENABLE_LIBUSB AND NOT USE_SYSTEM_LIBUSB)
add_subdirectory(libusb)
set(LIBUSB_INCLUDE_DIR "" PARENT_SCOPE)
set(LIBUSB_LIBRARIES usb PARENT_SCOPE)
endif()
# Zstandard
set(ZSTD_LEGACY_SUPPORT OFF)
set(ZSTD_BUILD_PROGRAMS OFF)
@ -138,6 +156,8 @@ target_include_directories(enet INTERFACE ./enet/include)
# Cubeb
if (ENABLE_CUBEB)
set(BUILD_TESTS OFF CACHE BOOL "")
set(BUILD_TOOLS OFF CACHE BOOL "")
set(BUNDLE_SPEEX ON CACHE BOOL "")
add_subdirectory(cubeb EXCLUDE_FROM_ALL)
endif()
@ -152,10 +172,14 @@ add_library(json-headers INTERFACE)
target_include_directories(json-headers INTERFACE ./json)
if (ENABLE_WEB_SERVICE)
find_package(OpenSSL 1.1)
if (OPENSSL_FOUND)
set(OPENSSL_LIBRARIES OpenSSL::SSL OpenSSL::Crypto)
else()
if (USE_SYSTEM_OPENSSL)
find_package(OpenSSL 1.1)
if (OPENSSL_FOUND)
set(OPENSSL_LIBRARIES OpenSSL::SSL OpenSSL::Crypto)
endif()
endif()
if (NOT OPENSSL_FOUND)
# LibreSSL
set(LIBRESSL_SKIP_INSTALL ON CACHE BOOL "")
set(OPENSSLDIR "/etc/ssl/")
@ -205,3 +229,11 @@ if (ENABLE_OPENAL)
set(LIBTYPE "STATIC" CACHE STRING "")
add_subdirectory(openal-soft EXCLUDE_FROM_ALL)
endif()
# VMA
add_library(vma INTERFACE)
target_include_directories(vma SYSTEM INTERFACE ./vma/include)
# vulkan-headers
add_library(vulkan-headers INTERFACE)
target_include_directories(vulkan-headers SYSTEM INTERFACE ./vulkan-headers/include)

View File

@ -1,192 +0,0 @@
# FindFFmpeg
# ----------
#
# Find the native FFmpeg includes and libraries
#
# This module defines the following variables:
#
# FFmpeg_INCLUDE_<component>: where to find <component>.h
# FFmpeg_LIBRARY_<component>: where to find the <component> library
# FFmpeg_INCLUDES: aggregate all the include paths
# FFmpeg_LIBRARIES: aggregate all the paths to the libraries
# FFmpeg_FOUND: True if all components have been found
#
# This module defines the following targets, which are prefered over variables:
#
# FFmpeg::<component>: Target to use <component> directly, with include path,
# library and dependencies set up. If you are using a static build, you are
# responsible for adding any external dependencies (such as zlib, bzlib...).
#
# <component> can be one of:
# avcodec
# avdevice
# avfilter
# avformat
# postproc
# swresample
# swscale
#
set(_FFmpeg_ALL_COMPONENTS
avcodec
avdevice
avfilter
avformat
avutil
postproc
swresample
swscale
)
set(_FFmpeg_DEPS_avcodec avutil)
set(_FFmpeg_DEPS_avdevice avcodec avformat avutil)
set(_FFmpeg_DEPS_avfilter avutil)
set(_FFmpeg_DEPS_avformat avcodec avutil)
set(_FFmpeg_DEPS_postproc avutil)
set(_FFmpeg_DEPS_swresample avutil)
set(_FFmpeg_DEPS_swscale avutil)
function(find_ffmpeg LIBNAME)
if(DEFINED ENV{FFMPEG_DIR})
set(FFMPEG_DIR $ENV{FFMPEG_DIR})
endif()
if(FFMPEG_DIR)
list(APPEND INCLUDE_PATHS
${FFMPEG_DIR}
${FFMPEG_DIR}/ffmpeg
${FFMPEG_DIR}/lib${LIBNAME}
${FFMPEG_DIR}/include/lib${LIBNAME}
${FFMPEG_DIR}/include/ffmpeg
${FFMPEG_DIR}/include
NO_DEFAULT_PATH
NO_CMAKE_FIND_ROOT_PATH
)
list(APPEND LIB_PATHS
${FFMPEG_DIR}
${FFMPEG_DIR}/lib
${FFMPEG_DIR}/lib${LIBNAME}
NO_DEFAULT_PATH
NO_CMAKE_FIND_ROOT_PATH
)
else()
list(APPEND INCLUDE_PATHS
/usr/local/include/ffmpeg
/usr/local/include/lib${LIBNAME}
/usr/include/ffmpeg
/usr/include/lib${LIBNAME}
/usr/include/ffmpeg/lib${LIBNAME}
)
list(APPEND LIB_PATHS
/usr/local/lib
/usr/lib
)
endif()
find_path(FFmpeg_INCLUDE_${LIBNAME} lib${LIBNAME}/${LIBNAME}.h
HINTS ${INCLUDE_PATHS}
)
find_library(FFmpeg_LIBRARY_${LIBNAME} ${LIBNAME}
HINTS ${LIB_PATHS}
)
if(NOT FFMPEG_DIR AND (NOT FFmpeg_LIBRARY_${LIBNAME} OR NOT FFmpeg_INCLUDE_${LIBNAME}))
# Didn't find it in the usual paths, try pkg-config
find_package(PkgConfig QUIET)
pkg_check_modules(FFmpeg_PKGCONFIG_${LIBNAME} QUIET lib${LIBNAME})
find_path(FFmpeg_INCLUDE_${LIBNAME} lib${LIBNAME}/${LIBNAME}.h
${FFmpeg_PKGCONFIG_${LIBNAME}_INCLUDE_DIRS}
)
find_library(FFmpeg_LIBRARY_${LIBNAME} ${LIBNAME}
${FFmpeg_PKGCONFIG_${LIBNAME}_LIBRARY_DIRS}
)
endif()
if(FFmpeg_INCLUDE_${LIBNAME} AND FFmpeg_LIBRARY_${LIBNAME})
set(FFmpeg_INCLUDE_${LIBNAME} "${FFmpeg_INCLUDE_${LIBNAME}}" PARENT_SCOPE)
set(FFmpeg_LIBRARY_${LIBNAME} "${FFmpeg_LIBRARY_${LIBNAME}}" PARENT_SCOPE)
# Extract FFmpeg version from version.h
foreach(v MAJOR MINOR MICRO)
set(FFmpeg_${LIBNAME}_VERSION_${v} 0)
endforeach()
string(TOUPPER ${LIBNAME} LIBNAME_UPPER)
file(STRINGS "${FFmpeg_INCLUDE_${LIBNAME}}/lib${LIBNAME}/version.h" _FFmpeg_VERSION_H_CONTENTS REGEX "#define LIB${LIBNAME_UPPER}_VERSION_(MAJOR|MINOR|MICRO) ")
if (EXISTS "${FFmpeg_INCLUDE_${LIBNAME}}/lib${LIBNAME}/version_major.h")
file(STRINGS "${FFmpeg_INCLUDE_${LIBNAME}}/lib${LIBNAME}/version_major.h" _FFmpeg_MAJOR_VERSION_H_CONTENTS REGEX "#define LIB${LIBNAME_UPPER}_VERSION_MAJOR ")
string(APPEND _FFmpeg_VERSION_H_CONTENTS "\n" ${_FFmpeg_MAJOR_VERSION_H_CONTENTS})
endif()
set(_FFmpeg_VERSION_REGEX "([0-9]+)")
foreach(v MAJOR MINOR MICRO)
if("${_FFmpeg_VERSION_H_CONTENTS}" MATCHES "#define LIB${LIBNAME_UPPER}_VERSION_${v}[\\t ]+${_FFmpeg_VERSION_REGEX}")
set(FFmpeg_${LIBNAME}_VERSION_${v} "${CMAKE_MATCH_1}")
endif()
endforeach()
set(FFmpeg_${LIBNAME}_VERSION "${FFmpeg_${LIBNAME}_VERSION_MAJOR}.${FFmpeg_${LIBNAME}_VERSION_MINOR}.${FFmpeg_${LIBNAME}_VERSION_MICRO}")
set(FFmpeg_${c}_VERSION "${FFmpeg_${LIBNAME}_VERSION}" PARENT_SCOPE)
unset(_FFmpeg_VERSION_REGEX)
unset(_FFmpeg_VERSION_H_CONTENTS)
set(FFmpeg_${c}_FOUND TRUE PARENT_SCOPE)
if(NOT FFmpeg_FIND_QUIETLY)
message("-- Found ${LIBNAME}: ${FFmpeg_INCLUDE_${LIBNAME}} ${FFmpeg_LIBRARY_${LIBNAME}} (version: ${FFmpeg_${LIBNAME}_VERSION})")
endif()
endif()
endfunction()
foreach(c ${_FFmpeg_ALL_COMPONENTS})
find_ffmpeg(${c})
endforeach()
foreach(c ${_FFmpeg_ALL_COMPONENTS})
if(FFmpeg_${c}_FOUND)
list(APPEND FFmpeg_INCLUDES ${FFmpeg_INCLUDE_${c}})
list(APPEND FFmpeg_LIBRARIES ${FFmpeg_LIBRARY_${c}})
add_library(FFmpeg::${c} IMPORTED UNKNOWN)
set_target_properties(FFmpeg::${c} PROPERTIES
IMPORTED_LOCATION ${FFmpeg_LIBRARY_${c}}
INTERFACE_INCLUDE_DIRECTORIES ${FFmpeg_INCLUDE_${c}}
)
if(APPLE)
set_target_properties(FFmpeg::${c} PROPERTIES
MACOSX_RPATH 1
)
endif()
if(_FFmpeg_DEPS_${c})
set(deps)
foreach(dep ${_FFmpeg_DEPS_${c}})
list(APPEND deps FFmpeg::${dep})
endforeach()
set_target_properties(FFmpeg::${c} PROPERTIES
INTERFACE_LINK_LIBRARIES "${deps}"
)
unset(deps)
endif()
endif()
endforeach()
if(FFmpeg_INCLUDES)
list(REMOVE_DUPLICATES FFmpeg_INCLUDES)
endif()
foreach(c ${FFmpeg_FIND_COMPONENTS})
list(APPEND _FFmpeg_REQUIRED_VARS FFmpeg_INCLUDE_${c} FFmpeg_LIBRARY_${c})
endforeach()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(FFmpeg
REQUIRED_VARS ${_FFmpeg_REQUIRED_VARS}
HANDLE_COMPONENTS
)
foreach(c ${_FFmpeg_ALL_COMPONENTS})
unset(_FFmpeg_DEPS_${c})
endforeach()
unset(_FFmpeg_ALL_COMPONENTS)
unset(_FFmpeg_REQUIRED_VARS)

View File

@ -1,28 +0,0 @@
# Copyright 2016 Citra Emulator Project
# Licensed under GPLv2 or any later version
# Refer to the license.txt file included.
# This file provides the function windows_copy_files.
# This is only valid on Windows.
# Include guard
if(__windows_copy_files)
return()
endif()
set(__windows_copy_files YES)
# Any number of files to copy from SOURCE_DIR to DEST_DIR can be specified after DEST_DIR.
# This copying happens post-build.
function(windows_copy_files TARGET SOURCE_DIR DEST_DIR)
# windows commandline expects the / to be \ so switch them
string(REPLACE "/" "\\\\" SOURCE_DIR ${SOURCE_DIR})
string(REPLACE "/" "\\\\" DEST_DIR ${DEST_DIR})
# /NJH /NJS /NDL /NFL /NC /NS /NP - Silence any output
# cmake adds an extra check for command success which doesn't work too well with robocopy
# so trick it into thinking the command was successful with the || cmd /c "exit /b 0"
add_custom_command(TARGET ${TARGET} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E make_directory ${DEST_DIR}
COMMAND robocopy ${SOURCE_DIR} ${DEST_DIR} ${ARGN} /NJH /NJS /NDL /NFL /NC /NS /NP || cmd /c "exit /b 0"
)
endfunction()

1
externals/glslang vendored Submodule

Submodule externals/glslang added at 1e4955adbc

View File

@ -233,6 +233,12 @@ using socket_t = int;
#undef X509_EXTENSIONS
#undef PKCS7_SIGNER_INFO
// libressl will warn without this, which becomes an error.
#undef OCSP_REQUEST
#undef OCSP_RESPONSE
#undef PKCS7_ISSUER_AND_SERIAL
#undef __WINCRYPT_H__
#ifdef _MSC_VER
#pragma comment(lib, "crypt32.lib")
#pragma comment(lib, "cryptui.lib")

View File

@ -0,0 +1,48 @@
add_library(library-headers INTERFACE)
# libfdk-aac headers
find_path(FDK_AAC_INCLUDES NAMES fdk-aac/aacdecoder_lib.h)
if (FDK_AAC_INCLUDES STREQUAL "FDK_AAC_INCLUDES-NOTFOUND")
message(STATUS "fdk_aac headers not found, using bundled headers.")
target_include_directories(library-headers INTERFACE ./library-headers/fdk-aac/include)
else()
message(STATUS "Using headers from system fdk_aac")
target_include_directories(library-headers SYSTEM INTERFACE ${FDK_AAC_INCLUDES})
endif()
# FFmpeg headers
find_path(AVUTIL_INCLUDES NAMES libavutil/avutil.h)
find_path(AVCODEC_INCLUDES NAMES libavcodec/avcodec.h)
find_path(AVFORMAT_INCLUDES NAMES libavformat/avformat.h)
find_path(AVFILTER_INCLUDES NAMES libavfilter/avfilter.h)
find_path(SWRESAMPLE_INCLUDES NAMES libswresample/swresample.h)
# Make sure all the headers are found and from the same place, so we don't
# have missing or mismatched components.
if (AVUTIL_INCLUDES STREQUAL "AVUTIL_INCLUDES-NOTFOUND"
OR NOT AVCODEC_INCLUDES STREQUAL AVUTIL_INCLUDES
OR NOT AVFORMAT_INCLUDES STREQUAL AVUTIL_INCLUDES
OR NOT AVFILTER_INCLUDES STREQUAL AVUTIL_INCLUDES
OR NOT SWRESAMPLE_INCLUDES STREQUAL AVUTIL_INCLUDES)
message(STATUS "Complete FFmpeg headers not found, using bundled headers.")
target_include_directories(library-headers INTERFACE ./library-headers/ffmpeg/include)
else()
# Extract libavutil version from header.
file(STRINGS "${AVUTIL_INCLUDES}/libavutil/version.h" AVUTIL_VERSION_DATA
REGEX "#define LIBAVUTIL_VERSION_(MAJOR|MINOR|MICRO) ")
set(AVUTIL_VERSION_REGEX "([0-9]+)")
foreach(v MAJOR MINOR MICRO)
if("${AVUTIL_VERSION_DATA}" MATCHES "#define LIBAVUTIL_VERSION_${v}[\\t ]+${AVUTIL_VERSION_REGEX}")
set(AVUTIL_VERSION_${v} "${CMAKE_MATCH_1}")
endif()
endforeach()
set(AVUTIL_VERSION "${AVUTIL_VERSION_MAJOR}.${AVUTIL_VERSION_MINOR}.${AVUTIL_VERSION_MICRO}")
message(STATUS "Detected FFmpeg libavutil version is ${AVUTIL_VERSION}")
if ("${AVUTIL_VERSION}" VERSION_LESS "56.30.100")
message(WARNING "System FFmpeg version is too low (< 4.2), using bundled headers.")
target_include_directories(library-headers INTERFACE ./library-headers/ffmpeg/include)
else()
message(STATUS "Using headers from system FFmpeg")
target_include_directories(library-headers SYSTEM INTERFACE ${AVUTIL_INCLUDES})
endif()
endif()

View File

@ -16,7 +16,7 @@ set(SDL_THREADS ON CACHE BOOL "")
set(SDL_TIMERS ON CACHE BOOL "")
set(SDL_FILE ON CACHE BOOL "")
set(SDL_LOADSO ON CACHE BOOL "")
set(SDL_CPUINFO OFF CACHE BOOL "")
set(SDL_CPUINFO ON CACHE BOOL "")
set(SDL_FILESYSTEM OFF CACHE BOOL "")
set(SDL_DLOPEN ON CACHE BOOL "")
set(SDL_SENSOR OFF CACHE BOOL "")

1
externals/sirit vendored Submodule

Submodule externals/sirit added at 4ab79a8c02

1
externals/vma vendored Submodule

Submodule externals/vma added at 0e89587db3

1
externals/vulkan-headers vendored Submodule

View File

@ -40,7 +40,6 @@ if (MSVC)
/Zo
/permissive-
/EHsc
/std:c++latest
/utf-8
/volatile:iso
/Zc:externConstexpr
@ -85,7 +84,7 @@ if (MSVC)
# Since MSVC's debugging information is not very deterministic, so we have to disable it
# when using ccache or other caching tools
if (CITRA_USE_CCACHE OR CITRA_USE_PRECOMPILED_HEADERS)
# Precompiled headers are deleted if not using /Z7. See https://github.com/nanoant/CMakePCHCompiler/issues/21
# Precompiled headers are deleted if not using /Z7. See https://github.com/nanoant/CMakePCHCompiler/issues/21
add_compile_options(/Z7)
else()
add_compile_options(/Zi)
@ -102,17 +101,12 @@ else()
-Wno-attributes
)
if (APPLE AND CMAKE_CXX_COMPILER_ID STREQUAL Clang)
add_compile_options("-stdlib=libc++")
if (CITRA_WARNINGS_AS_ERRORS)
add_compile_options(-Werror)
endif()
# Set file offset size to 64 bits.
#
# On modern Unixes, this is typically already the case. The lone exception is
# glibc, which may default to 32 bits. glibc allows this to be configured
# by setting _FILE_OFFSET_BITS.
if(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR MINGW)
add_definitions(-D_FILE_OFFSET_BITS=64)
if (APPLE AND CMAKE_CXX_COMPILER_ID STREQUAL Clang)
add_compile_options("-stdlib=libc++")
endif()
if (MINGW)
@ -120,14 +114,16 @@ else()
if (COMPILE_WITH_DWARF)
add_compile_options("-gdwarf")
endif()
if (MINGW_STATIC_BUILD)
add_definitions(-DQT_STATICPLUGIN)
add_compile_options("-static")
endif()
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR MINGW)
# Set file offset size to 64 bits.
#
# On modern Unixes, this is typically already the case. The lone exception is
# glibc, which may default to 32 bits. glibc allows this to be configured
# by setting _FILE_OFFSET_BITS.
add_definitions(-D_FILE_OFFSET_BITS=64)
# GNU ar: Create thin archive files.
# Requires binutils-2.19 or later.
set(CMAKE_C_ARCHIVE_CREATE "<CMAKE_AR> qcTP <TARGET> <LINK_FLAGS> <OBJECTS>")
@ -143,9 +139,12 @@ add_subdirectory(video_core)
add_subdirectory(audio_core)
add_subdirectory(network)
add_subdirectory(input_common)
add_subdirectory(tests)
if (ENABLE_SDL2)
if (ENABLE_TESTS)
add_subdirectory(tests)
endif()
if (ENABLE_SDL2 AND ENABLE_SDL2_FRONTEND)
add_subdirectory(citra)
endif()
@ -153,11 +152,13 @@ if (ENABLE_QT)
add_subdirectory(citra_qt)
endif()
if (ENABLE_DEDICATED_ROOM)
add_subdirectory(dedicated_room)
endif()
if (ANDROID)
add_subdirectory(android/app/src/main/jni)
target_include_directories(citra-android PRIVATE android/app/src/main)
else()
add_subdirectory(dedicated_room)
endif()
if (ENABLE_WEB_SERVICE)

View File

@ -1,169 +0,0 @@
apply plugin: 'com.android.application'
/**
* Use the number of seconds/10 since Jan 1 2016 as the versionCode.
* This lets us upload a new build at most every 10 seconds for the
* next 680 years.
*/
def autoVersion = (int) (((new Date().getTime() / 1000) - 1451606400) / 10)
def buildType
def abiFilter = "arm64-v8a" //, "x86"
android {
compileSdkVersion 32
ndkVersion "25.1.8937393"
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
lintOptions {
// This is important as it will run lint but not abort on error
// Lint has some overly obnoxious "errors" that should really be warnings
abortOnError false
//Uncomment disable lines for test builds...
//disable 'MissingTranslation'bin
//disable 'ExtraTranslation'
}
defaultConfig {
// TODO If this is ever modified, change application_id in strings.xml
applicationId "org.citra.citra_emu"
minSdkVersion 28
targetSdkVersion 31
versionCode autoVersion
versionName getVersion()
ndk.abiFilters abiFilter
}
signingConfigs {
//release {
// storeFile file('')
// storePassword System.getenv('ANDROID_KEYPASS')
// keyAlias = 'key0'
// keyPassword System.getenv('ANDROID_KEYPASS')
//}
}
applicationVariants.all { variant ->
buildType = variant.buildType.name // sets the current build type
}
// Define build types, which are orthogonal to product flavors.
buildTypes {
// Signed by release key, allowing for upload to Play Store.
release {
signingConfig signingConfigs.debug
}
// builds a release build that doesn't need signing
// Attaches 'debug' suffix to version and package name, allowing installation alongside the release build.
relWithDebInfo {
initWith release
applicationIdSuffix ".debug"
versionNameSuffix '-debug'
signingConfig signingConfigs.debug
minifyEnabled false
testCoverageEnabled false
debuggable true
jniDebuggable true
}
// Signed by debug key disallowing distribution on Play Store.
// Attaches 'debug' suffix to version and package name, allowing installation alongside the release build.
debug {
// TODO If this is ever modified, change application_id in debug/strings.xml
applicationIdSuffix ".debug"
versionNameSuffix '-debug'
debuggable true
jniDebuggable true
}
}
flavorDimensions "version"
productFlavors {
canary {
dimension "version"
applicationIdSuffix ".canary"
}
nightly {
dimension "version"
}
}
externalNativeBuild {
cmake {
version "3.22.1"
path "../../../CMakeLists.txt"
}
}
defaultConfig {
externalNativeBuild {
cmake {
arguments "-DENABLE_QT=0", // Don't use QT
"-DENABLE_SDL2=0", // Don't use SDL
"-DENABLE_WEB_SERVICE=0", // Don't use telemetry
"-DANDROID_ARM_NEON=true", // cryptopp requires Neon to work
"-DBUNDLE_SPEEX=ON"
abiFilters abiFilter
}
}
}
}
dependencies {
implementation "androidx.activity:activity:1.5.1"
implementation "androidx.fragment:fragment:1.5.5"
implementation 'androidx.appcompat:appcompat:1.5.1'
implementation 'androidx.exifinterface:exifinterface:1.3.4'
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'androidx.recyclerview:recyclerview:1.2.1'
implementation "androidx.documentfile:documentfile:1.0.1"
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.lifecycle:lifecycle-viewmodel:2.5.1'
implementation 'androidx.fragment:fragment:1.5.3'
implementation "androidx.slidingpanelayout:slidingpanelayout:1.2.0"
implementation 'com.google.android.material:material:1.6.1'
implementation 'androidx.core:core-splashscreen:1.0.0'
// For loading huge screenshots from the disk.
implementation 'com.squareup.picasso:picasso:2.71828'
// Allows FRP-style asynchronous operations in Android.
implementation 'io.reactivex:rxandroid:1.2.1'
implementation 'org.ini4j:ini4j:0.5.4'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.1.0'
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
// Please don't upgrade the billing library as the newer version is not GPL-compatible
implementation 'com.android.billingclient:billing:2.0.3'
// To use the androidx.test.core APIs
androidTestImplementation "androidx.test:core:1.5.0"
androidTestImplementation "androidx.test.ext:junit:1.1.5"
}
def getVersion() {
def versionName = '0.0'
try {
versionName = 'git describe --always --long'.execute([], project.rootDir).text
.trim()
.replaceAll(/(-0)?-[^-]+$/, "")
} catch (Exception) {
logger.error('Cannot find git, defaulting to dummy version number')
}
if (System.getenv("GITHUB_ACTIONS") != null) {
def gitTag = System.getenv("GIT_TAG_NAME")
versionName = gitTag ?: versionName
}
return versionName
}

View File

@ -0,0 +1,203 @@
// Copyright 2023 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
import android.databinding.tool.ext.capitalizeUS
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
}
/**
* Use the number of seconds/10 since Jan 1 2016 as the versionCode.
* This lets us upload a new build at most every 10 seconds for the
* next 680 years.
*/
val autoVersion = (((System.currentTimeMillis() / 1000) - 1451606400) / 10).toInt()
val abiFilter = listOf("arm64-v8a"/*, "x86", "x86_64"*/)
@Suppress("UnstableApiUsage")
android {
namespace = "org.citra.citra_emu"
compileSdkVersion = "android-33"
ndkVersion = "25.2.9519653"
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = "17"
}
buildFeatures {
viewBinding = true
}
lint {
// This is important as it will run lint but not abort on error
// Lint has some overly obnoxious "errors" that should really be warnings
abortOnError = false
}
defaultConfig {
// TODO If this is ever modified, change application_id in strings.xml
applicationId = "org.citra.citra_emu"
minSdk = 28
targetSdk = 33
versionCode = autoVersion
versionName = getGitVersion()
ndk {
//noinspection ChromeOsAbiSupport
abiFilters += abiFilter
}
externalNativeBuild {
cmake {
arguments(
"-DENABLE_QT=0", // Don't use QT
"-DENABLE_SDL2=0", // Don't use SDL
"-DANDROID_ARM_NEON=true" // cryptopp requires Neon to work
)
}
}
}
val keystoreFile = System.getenv("ANDROID_KEYSTORE_FILE")
if (keystoreFile != null) {
signingConfigs {
create("release") {
storeFile = file(keystoreFile)
storePassword = System.getenv("ANDROID_KEYSTORE_PASS")
keyAlias = System.getenv("ANDROID_KEY_ALIAS")
keyPassword = System.getenv("ANDROID_KEYSTORE_PASS")
}
}
}
// Define build types, which are orthogonal to product flavors.
buildTypes {
// Signed by release key, allowing for upload to Play Store.
release {
signingConfig = if (keystoreFile != null) {
signingConfigs.getByName("release")
} else {
signingConfigs.getByName("debug")
}
}
// builds a release build that doesn't need signing
// Attaches 'debug' suffix to version and package name, allowing installation alongside the release build.
register("relWithDebInfo") {
initWith(getByName("release"))
applicationIdSuffix = ".debug"
versionNameSuffix = "-debug"
signingConfig = signingConfigs.getByName("debug")
isMinifyEnabled = false
isDebuggable = true
isJniDebuggable = true
}
// Signed by debug key disallowing distribution on Play Store.
// Attaches 'debug' suffix to version and package name, allowing installation alongside the release build.
debug {
// TODO If this is ever modified, change application_id in debug/strings.xml
applicationIdSuffix = ".debug"
versionNameSuffix = "-debug"
isDebuggable = true
isJniDebuggable = true
}
}
flavorDimensions.add("version")
productFlavors {
create("canary") {
dimension = "version"
applicationIdSuffix = ".canary"
}
create("nightly") {
dimension = "version"
}
}
externalNativeBuild {
cmake {
version = "3.22.1"
path = file("../../../CMakeLists.txt")
}
}
}
dependencies {
implementation("androidx.activity:activity-ktx:1.7.2")
implementation("androidx.fragment:fragment-ktx:1.6.0")
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("androidx.documentfile:documentfile:1.0.1")
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1")
implementation("androidx.slidingpanelayout:slidingpanelayout:1.2.0")
implementation("com.google.android.material:material:1.9.0")
implementation("androidx.core:core-splashscreen:1.0.1")
implementation("androidx.work:work-runtime:2.8.1")
// For loading huge screenshots from the disk.
implementation("com.squareup.picasso:picasso:2.71828")
// Allows FRP-style asynchronous operations in Android.
implementation("io.reactivex:rxandroid:1.2.1")
implementation("org.ini4j:ini4j:0.5.4")
implementation("androidx.localbroadcastmanager:localbroadcastmanager:1.1.0")
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
// Please don't upgrade the billing library as the newer version is not GPL-compatible
implementation("com.android.billingclient:billing:2.0.3")
}
fun getGitVersion(): String {
var versionName = "0.0"
try {
versionName = ProcessBuilder("git", "describe", "--always", "--long")
.directory(project.rootDir)
.redirectOutput(ProcessBuilder.Redirect.PIPE)
.redirectError(ProcessBuilder.Redirect.PIPE)
.start().inputStream.bufferedReader().use { it.readText() }
.trim()
.replace(Regex("(-0)?-[^-]+$"), "")
} catch (e: Exception) {
logger.error("Cannot find git, defaulting to dummy version number")
}
if (System.getenv("GITHUB_ACTIONS") != null) {
val gitTag = System.getenv("GIT_TAG_NAME")
versionName = gitTag ?: versionName
}
return versionName
}
android.applicationVariants.configureEach {
val variant = this
val capitalizedName = variant.name.capitalizeUS()
val copyTask = tasks.register("copyBundle${capitalizedName}") {
doLast {
project.copy {
from(variant.outputs.first().outputFile.parentFile)
include("*.apk")
into(layout.buildDirectory.dir("bundle"))
}
project.copy {
from(layout.buildDirectory.dir("outputs/bundle/${variant.name}"))
include("*.aab")
into(layout.buildDirectory.dir("bundle"))
}
}
}
tasks.named("bundle${capitalizedName}").configure { finalizedBy(copyTask) }
}

View File

@ -1,26 +0,0 @@
package org.citra.citra_emu;
import android.content.Context;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = ApplicationProvider.getApplicationContext();
assertEquals("org.citra.citra_emu", appContext.getPackageName());
}
}

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.citra.citra_emu">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-feature
android:name="android.hardware.touchscreen"
android:required="false"/>

View File

@ -23,16 +23,33 @@ public class CitraApplication extends Application {
private void createNotificationChannel() {
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
return;
}
NotificationManager notificationManager = getSystemService(NotificationManager.class);
{
// General notification
CharSequence name = getString(R.string.app_notification_channel_name);
String description = getString(R.string.app_notification_channel_description);
NotificationChannel channel = new NotificationChannel(getString(R.string.app_notification_channel_id), name, NotificationManager.IMPORTANCE_LOW);
NotificationChannel channel = new NotificationChannel(
getString(R.string.app_notification_channel_id), name,
NotificationManager.IMPORTANCE_LOW);
channel.setDescription(description);
channel.setSound(null, null);
channel.setVibrationPattern(null);
// Register the channel with the system; you can't change the importance
// or other notification behaviors after this
NotificationManager notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
{
// CIA Install notifications
NotificationChannel channel = new NotificationChannel(
getString(R.string.cia_install_notification_channel_id),
getString(R.string.cia_install_notification_channel_name),
NotificationManager.IMPORTANCE_DEFAULT);
channel.setDescription(getString(R.string.cia_install_notification_channel_description));
channel.setSound(null, null);
channel.setVibrationPattern(null);
notificationManager.createNotificationChannel(channel);
}
}

View File

@ -585,12 +585,10 @@ public final class NativeLibrary {
/// Notifies that the activity is now in foreground and camera devices can now be reloaded
public static native void ReloadCameraDevices();
public static native boolean LoadAmiibo(byte[] bytes);
public static native boolean LoadAmiibo(String path);
public static native void RemoveAmiibo();
public static native void InstallCIAS(String[] path);
public static final int SAVESTATE_SLOT_COUNT = 10;
public static final class SavestateInfo {

View File

@ -570,15 +570,7 @@ public final class EmulationActivity extends AppCompatActivity {
}
private void onAmiiboSelected(String selectedFile) {
boolean success = false;
try {
Uri uri = Uri.parse(selectedFile);
DocumentFile file = DocumentFile.fromSingleUri(this, uri);
byte[] bytes = FileUtil.getBytesFromFile(this, file);
success = NativeLibrary.LoadAmiibo(bytes);
} catch (IOException e) {
e.printStackTrace();
}
boolean success = NativeLibrary.LoadAmiibo(selectedFile);
if (!success) {
new MaterialAlertDialogBuilder(this)

View File

@ -196,8 +196,12 @@ public final class SettingsFragmentPresenter {
sl.add(new SingleChoiceSetting(SettingsFile.KEY_REGION_VALUE, Settings.SECTION_SYSTEM, R.string.emulated_region, 0, R.array.regionNames, R.array.regionValues, -1, region));
sl.add(new SingleChoiceSetting(SettingsFile.KEY_LANGUAGE, Settings.SECTION_SYSTEM, R.string.emulated_language, 0, R.array.languageNames, R.array.languageValues, 1, language));
sl.add(new HeaderSetting(null, null, R.string.clock, 0));
sl.add(new SingleChoiceSetting(SettingsFile.KEY_INIT_CLOCK, Settings.SECTION_SYSTEM, R.string.init_clock, R.string.init_clock_description, R.array.systemClockNames, R.array.systemClockValues, 0, systemClock));
sl.add(new DateTimeSetting(SettingsFile.KEY_INIT_TIME, Settings.SECTION_SYSTEM, R.string.init_time, R.string.init_time_description, "2000-01-01 00:00:01", dateTime));
sl.add(new HeaderSetting(null, null, R.string.plugin_loader, 0));
sl.add(new CheckBoxSetting(SettingsFile.KEY_PLUGIN_LOADER, Settings.SECTION_SYSTEM, R.string.plugin_loader, R.string.plugin_loader_description, false, pluginLoader));
sl.add(new CheckBoxSetting(SettingsFile.KEY_ALLOW_PLUGIN_LOADER, Settings.SECTION_SYSTEM, R.string.allow_plugin_loader, R.string.allow_plugin_loader_description, true, allowPluginLoader));
}

View File

@ -20,10 +20,15 @@ import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.work.Data;
import androidx.work.ExistingWorkPolicy;
import androidx.work.OneTimeWorkRequest;
import androidx.work.OutOfQuotaPolicy;
import androidx.work.WorkManager;
import androidx.work.WorkRequest;
import com.google.android.material.appbar.AppBarLayout;
import org.citra.citra_emu.NativeLibrary;
import org.citra.citra_emu.R;
import org.citra.citra_emu.activities.EmulationActivity;
import org.citra.citra_emu.contracts.OpenFileResultContract;
@ -32,6 +37,7 @@ import org.citra.citra_emu.model.GameProvider;
import org.citra.citra_emu.ui.platform.PlatformGamesFragment;
import org.citra.citra_emu.utils.AddDirectoryHelper;
import org.citra.citra_emu.utils.BillingManager;
import org.citra.citra_emu.utils.CiaInstallWorker;
import org.citra.citra_emu.utils.CitraDirectoryHelper;
import org.citra.citra_emu.utils.DirectoryInitialization;
import org.citra.citra_emu.utils.FileBrowserHelper;
@ -50,7 +56,9 @@ public final class MainActivity extends AppCompatActivity implements MainView {
private int mFrameLayoutId;
private PlatformGamesFragment mPlatformGamesFragment;
private MainPresenter mPresenter = new MainPresenter(this);
private final MainPresenter mPresenter = new MainPresenter(this);
// private final CiaInstallWorker mCiaInstallWorker = new CiaInstallWorker();
// Singleton to manage user billing state
private static BillingManager mBillingManager;
@ -91,7 +99,7 @@ public final class MainActivity extends AppCompatActivity implements MainView {
mPresenter.onDirectorySelected(result.toString());
});
private final ActivityResultLauncher<Boolean> mOpenFileLauncher =
private final ActivityResultLauncher<Boolean> mInstallCiaFileLauncher =
registerForActivityResult(new OpenFileResultContract(), result -> {
if (result == null)
return;
@ -104,8 +112,16 @@ public final class MainActivity extends AppCompatActivity implements MainView {
.show();
return;
}
NativeLibrary.InstallCIAS(selectedFiles);
mPresenter.refreshGameList();
WorkManager workManager = WorkManager.getInstance(getApplicationContext());
workManager.enqueueUniqueWork("installCiaWork", ExistingWorkPolicy.APPEND_OR_REPLACE,
new OneTimeWorkRequest.Builder(CiaInstallWorker.class)
.setInputData(
new Data.Builder().putStringArray("CIA_FILES", selectedFiles)
.build()
)
.setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
.build()
);
});
@Override
@ -233,7 +249,7 @@ public final class MainActivity extends AppCompatActivity implements MainView {
mOpenGameListLauncher.launch(null);
break;
case MainPresenter.REQUEST_INSTALL_CIA:
mOpenFileLauncher.launch(true);
mInstallCiaFileLauncher.launch(true);
break;
}
} else {

View File

@ -0,0 +1,160 @@
package org.citra.citra_emu.utils;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.core.app.NotificationCompat;
import androidx.work.ForegroundInfo;
import androidx.work.Worker;
import androidx.work.WorkerParameters;
import org.citra.citra_emu.R;
public class CiaInstallWorker extends Worker {
private final Context mContext = getApplicationContext();
private final NotificationManager mNotificationManager =
mContext.getSystemService(NotificationManager.class);
static final String GROUP_KEY_CIA_INSTALL_STATUS = "org.citra.citra_emu.CIA_INSTALL_STATUS";
private final NotificationCompat.Builder mInstallProgressBuilder = new NotificationCompat.Builder(
mContext, mContext.getString(R.string.cia_install_notification_channel_id))
.setContentTitle(mContext.getString(R.string.install_cia_title))
.setContentIntent(PendingIntent.getBroadcast(mContext, 0,
new Intent("CitraDoNothing"), PendingIntent.FLAG_IMMUTABLE))
.setSmallIcon(R.drawable.ic_stat_notification_logo);
private final NotificationCompat.Builder mInstallStatusBuilder = new NotificationCompat.Builder(
mContext, mContext.getString(R.string.cia_install_notification_channel_id))
.setContentTitle(mContext.getString(R.string.install_cia_title))
.setSmallIcon(R.drawable.ic_stat_notification_logo)
.setGroup(GROUP_KEY_CIA_INSTALL_STATUS);
private final Notification mSummaryNotification =
new NotificationCompat.Builder(mContext, mContext.getString(R.string.cia_install_notification_channel_id))
.setContentTitle(mContext.getString(R.string.install_cia_title))
.setSmallIcon(R.drawable.ic_stat_notification_logo)
.setGroup(GROUP_KEY_CIA_INSTALL_STATUS)
.setGroupSummary(true)
.build();
private static long mLastNotifiedTime = 0;
private static final int SUMMARY_NOTIFICATION_ID = 0xC1A0000;
private static final int PROGRESS_NOTIFICATION_ID = SUMMARY_NOTIFICATION_ID + 1;
private static int mStatusNotificationId = SUMMARY_NOTIFICATION_ID + 2;
public CiaInstallWorker(
@NonNull Context context,
@NonNull WorkerParameters params) {
super(context, params);
}
enum InstallStatus {
Success,
ErrorFailedToOpenFile,
ErrorFileNotFound,
ErrorAborted,
ErrorInvalid,
ErrorEncrypted,
}
private void notifyInstallStatus(String filename, InstallStatus status) {
switch(status){
case Success:
mInstallStatusBuilder.setContentTitle(
mContext.getString(R.string.cia_install_notification_success_title));
mInstallStatusBuilder.setContentText(
mContext.getString(R.string.cia_install_success, filename));
break;
case ErrorAborted:
mInstallStatusBuilder.setContentTitle(
mContext.getString(R.string.cia_install_notification_error_title));
mInstallStatusBuilder.setStyle(new NotificationCompat.BigTextStyle()
.bigText(mContext.getString(
R.string.cia_install_error_aborted, filename)));
break;
case ErrorInvalid:
mInstallStatusBuilder.setContentTitle(
mContext.getString(R.string.cia_install_notification_error_title));
mInstallStatusBuilder.setContentText(
mContext.getString(R.string.cia_install_error_invalid, filename));
break;
case ErrorEncrypted:
mInstallStatusBuilder.setContentTitle(
mContext.getString(R.string.cia_install_notification_error_title));
mInstallStatusBuilder.setStyle(new NotificationCompat.BigTextStyle()
.bigText(mContext.getString(
R.string.cia_install_error_encrypted, filename)));
break;
case ErrorFailedToOpenFile:
// TODO:
case ErrorFileNotFound:
// shouldn't happen
default:
mInstallStatusBuilder.setContentTitle(
mContext.getString(R.string.cia_install_notification_error_title));
mInstallStatusBuilder.setStyle(new NotificationCompat.BigTextStyle()
.bigText(mContext.getString(R.string.cia_install_error_unknown, filename)));
break;
}
// Even if newer versions of Android don't show the group summary text that you design,
// you always need to manually set a summary to enable grouped notifications.
mNotificationManager.notify(SUMMARY_NOTIFICATION_ID, mSummaryNotification);
mNotificationManager.notify(mStatusNotificationId++, mInstallStatusBuilder.build());
}
@NonNull
@Override
public Result doWork() {
String[] selectedFiles = getInputData().getStringArray("CIA_FILES");
assert selectedFiles != null;
final CharSequence toastText = mContext.getResources().getQuantityString(R.plurals.cia_install_toast,
selectedFiles.length, selectedFiles.length);
getApplicationContext().getMainExecutor().execute(() -> Toast.makeText(mContext, toastText,
Toast.LENGTH_LONG).show());
// Issue the initial notification with zero progress
mInstallProgressBuilder.setOngoing(true);
setProgressCallback(100, 0);
int i = 0;
for (String file : selectedFiles) {
String filename = FileUtil.getFilename(mContext, file);
mInstallProgressBuilder.setContentText(mContext.getString(
R.string.cia_install_notification_installing, filename, ++i, selectedFiles.length));
InstallStatus res = InstallCIA(file);
notifyInstallStatus(filename, res);
}
mNotificationManager.cancel(PROGRESS_NOTIFICATION_ID);
return Result.success();
}
public void setProgressCallback(int max, int progress) {
long currentTime = System.currentTimeMillis();
// Android applies a rate limit when updating a notification.
// If you post updates to a single notification too frequently,
// such as many in less than one second, the system might drop updates.
// TODO: consider moving to C++ side
if (currentTime - mLastNotifiedTime < 500 /* ms */){
return;
}
mLastNotifiedTime = currentTime;
mInstallProgressBuilder.setProgress(max, progress, false);
mNotificationManager.notify(PROGRESS_NOTIFICATION_ID, mInstallProgressBuilder.build());
}
@NonNull
@Override
public ForegroundInfo getForegroundInfo() {
return new ForegroundInfo(PROGRESS_NOTIFICATION_ID, mInstallProgressBuilder.build());
}
private native InstallStatus InstallCIA(String path);
}

View File

@ -2,7 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
package org.citra.citra_emu.disk_shader_cache;
package org.citra.citra_emu.utils;
import android.app.Activity;
import android.app.Dialog;

View File

@ -7,8 +7,8 @@
#include <sstream>
#include <unordered_map>
#include <inih/cpp/INIReader.h>
#include "common/file_util.h"
#include "common/logging/backend.h"
#include "common/logging/log.h"
#include "common/param_package.h"
#include "common/settings.h"
@ -260,6 +260,12 @@ void Config::ReadValues() {
// Miscellaneous
ReadSetting("Miscellaneous", Settings::values.log_filter);
// Apply the log_filter setting as the logger has already been initialized
// and doesn't pick up the filter on its own.
Common::Log::Filter filter;
filter.ParseFilterString(Settings::values.log_filter.GetValue());
Common::Log::SetGlobalFilter(filter);
// Debugging
Settings::values.record_frame_times =
sdl2_config->GetBoolean("Debugging", "record_frame_times", false);
@ -274,7 +280,7 @@ void Config::ReadValues() {
// Web Service
NetSettings::values.enable_telemetry =
sdl2_config->GetBoolean("WebService", "enable_telemetry", true);
sdl2_config->GetBoolean("WebService", "enable_telemetry", false);
NetSettings::values.web_api_url =
sdl2_config->GetString("WebService", "web_api_url", "https://api.citra-emu.org");
NetSettings::values.citra_username = sdl2_config->GetString("WebService", "citra_username", "");

View File

@ -334,7 +334,7 @@ gdbstub_port=24689
[WebService]
# Whether or not to enable telemetry
# 0: No, 1 (default): Yes
# 0 (default): No, 1: Yes
enable_telemetry =
# URL for Web API
web_api_url = https://api.citra-emu.org

View File

@ -67,7 +67,7 @@ JNIEXPORT jlong JNICALL Java_org_citra_citra_1emu_model_GameInfo_initialize(JNIE
Loader::SMDH* smdh = nullptr;
if (Loader::IsValidSMDH(smdh_data)) {
smdh = new Loader::SMDH;
memcpy(smdh, smdh_data.data(), sizeof(Loader::SMDH));
std::memcpy(smdh, smdh_data.data(), sizeof(Loader::SMDH));
}
return reinterpret_cast<jlong>(smdh);
}

View File

@ -8,6 +8,7 @@
#include "common/logging/filter.h"
#include "common/logging/log.h"
#include "common/settings.h"
#include "core/hle/service/am/am.h"
#include "jni/applets/mii_selector.h"
#include "jni/applets/swkbd.h"
#include "jni/camera/still_image_camera.h"
@ -21,8 +22,6 @@ static JavaVM* s_java_vm;
static jclass s_core_error_class;
static jclass s_savestate_info_class;
static jclass s_disk_cache_progress_class;
static jclass s_load_callback_stage_class;
static jclass s_native_library_class;
static jmethodID s_on_core_error;
@ -34,7 +33,6 @@ static jmethodID s_landscape_screen_layout;
static jmethodID s_exit_emulation_activity;
static jmethodID s_request_camera_permission;
static jmethodID s_request_mic_permission;
static jmethodID s_disk_cache_load_progress;
static jclass s_cheat_class;
static jfieldID s_cheat_pointer;
@ -44,8 +42,14 @@ static jfieldID s_cheat_engine_pointer;
static jfieldID s_game_info_pointer;
static jclass s_disk_cache_progress_class;
static jmethodID s_disk_cache_load_progress;
static std::unordered_map<VideoCore::LoadCallbackStage, jobject> s_java_load_callback_stages;
static jclass s_cia_install_helper_class;
static jmethodID s_cia_install_helper_set_progress;
static std::unordered_map<Service::AM::InstallStatus, jobject> s_java_cia_install_status;
namespace IDCache {
JNIEnv* GetEnvForThread() {
@ -75,14 +79,6 @@ jclass GetSavestateInfoClass() {
return s_savestate_info_class;
}
jclass GetDiskCacheProgressClass() {
return s_disk_cache_progress_class;
}
jclass GetDiskCacheLoadCallbackStageClass() {
return s_load_callback_stage_class;
}
jclass GetNativeLibraryClass() {
return s_native_library_class;
}
@ -123,10 +119,6 @@ jmethodID GetRequestMicPermission() {
return s_request_mic_permission;
}
jmethodID GetDiskCacheLoadProgress() {
return s_disk_cache_load_progress;
}
jclass GetCheatClass() {
return s_cheat_class;
}
@ -147,6 +139,14 @@ jfieldID GetGameInfoPointer() {
return s_game_info_pointer;
}
jclass GetDiskCacheProgressClass() {
return s_disk_cache_progress_class;
}
jmethodID GetDiskCacheLoadProgress() {
return s_disk_cache_load_progress;
}
jobject GetJavaLoadCallbackStage(VideoCore::LoadCallbackStage stage) {
const auto it = s_java_load_callback_stages.find(stage);
ASSERT_MSG(it != s_java_load_callback_stages.end(), "Invalid LoadCallbackStage: {}", stage);
@ -154,6 +154,19 @@ jobject GetJavaLoadCallbackStage(VideoCore::LoadCallbackStage stage) {
return it->second;
}
jclass GetCiaInstallHelperClass() {
return s_cia_install_helper_class;
}
jmethodID GetCiaInstallHelperSetProgress() {
return s_cia_install_helper_set_progress;
}
jobject GetJavaCiaInstallStatus(Service::AM::InstallStatus status) {
const auto it = s_java_cia_install_status.find(status);
ASSERT_MSG(it != s_java_cia_install_status.end(), "Invalid InstallStatus: {}", status);
return it->second;
}
} // namespace IDCache
#ifdef __cplusplus
@ -167,21 +180,11 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION) != JNI_OK)
return JNI_ERR;
// Initialize Logger
Log::Filter log_filter;
log_filter.ParseFilterString(Settings::values.log_filter.GetValue());
Log::SetGlobalFilter(log_filter);
Log::AddBackend(std::make_unique<Log::LogcatBackend>());
// Initialize misc classes
s_savestate_info_class = reinterpret_cast<jclass>(
env->NewGlobalRef(env->FindClass("org/citra/citra_emu/NativeLibrary$SavestateInfo")));
s_core_error_class = reinterpret_cast<jclass>(
env->NewGlobalRef(env->FindClass("org/citra/citra_emu/NativeLibrary$CoreError")));
s_disk_cache_progress_class = reinterpret_cast<jclass>(env->NewGlobalRef(
env->FindClass("org/citra/citra_emu/disk_shader_cache/DiskShaderCacheProgress")));
s_load_callback_stage_class = reinterpret_cast<jclass>(env->NewGlobalRef(env->FindClass(
"org/citra/citra_emu/disk_shader_cache/DiskShaderCacheProgress$LoadCallbackStage")));
// Initialize NativeLibrary
const jclass native_library_class = env->FindClass("org/citra/citra_emu/NativeLibrary");
@ -205,9 +208,6 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
env->GetStaticMethodID(s_native_library_class, "RequestCameraPermission", "()Z");
s_request_mic_permission =
env->GetStaticMethodID(s_native_library_class, "RequestMicPermission", "()Z");
s_disk_cache_load_progress = env->GetStaticMethodID(
s_disk_cache_progress_class, "loadProgress",
"(Lorg/citra/citra_emu/disk_shader_cache/DiskShaderCacheProgress$LoadCallbackStage;II)V");
env->DeleteLocalRef(native_library_class);
// Initialize Cheat
@ -228,16 +228,23 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
s_game_info_pointer = env->GetFieldID(game_info_class, "mPointer", "J");
env->DeleteLocalRef(game_info_class);
// Initialize Disk Shader Cache Progress Dialog
s_disk_cache_progress_class = reinterpret_cast<jclass>(
env->NewGlobalRef(env->FindClass("org/citra/citra_emu/utils/DiskShaderCacheProgress")));
jclass load_callback_stage_class =
env->FindClass("org/citra/citra_emu/utils/DiskShaderCacheProgress$LoadCallbackStage");
s_disk_cache_load_progress = env->GetStaticMethodID(
s_disk_cache_progress_class, "loadProgress",
"(Lorg/citra/citra_emu/utils/DiskShaderCacheProgress$LoadCallbackStage;II)V");
// Initialize LoadCallbackStage map
const auto to_java_load_callback_stage = [env](const std::string& stage) {
jclass load_callback_stage_class = IDCache::GetDiskCacheLoadCallbackStageClass();
const auto to_java_load_callback_stage = [env,
load_callback_stage_class](const std::string& stage) {
return env->NewGlobalRef(env->GetStaticObjectField(
load_callback_stage_class,
env->GetStaticFieldID(load_callback_stage_class, stage.c_str(),
"Lorg/citra/citra_emu/disk_shader_cache/"
"Lorg/citra/citra_emu/utils/"
"DiskShaderCacheProgress$LoadCallbackStage;")));
};
s_java_load_callback_stages.emplace(VideoCore::LoadCallbackStage::Prepare,
to_java_load_callback_stage("Prepare"));
s_java_load_callback_stages.emplace(VideoCore::LoadCallbackStage::Decompile,
@ -246,6 +253,36 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
to_java_load_callback_stage("Build"));
s_java_load_callback_stages.emplace(VideoCore::LoadCallbackStage::Complete,
to_java_load_callback_stage("Complete"));
env->DeleteLocalRef(load_callback_stage_class);
// CIA Install
s_cia_install_helper_class = reinterpret_cast<jclass>(
env->NewGlobalRef(env->FindClass("org/citra/citra_emu/utils/CiaInstallWorker")));
s_cia_install_helper_set_progress =
env->GetMethodID(s_cia_install_helper_class, "setProgressCallback", "(II)V");
// Initialize CIA InstallStatus map
jclass cia_install_status_class =
env->FindClass("org/citra/citra_emu/utils/CiaInstallWorker$InstallStatus");
const auto to_java_cia_install_status = [env,
cia_install_status_class](const std::string& stage) {
return env->NewGlobalRef(env->GetStaticObjectField(
cia_install_status_class, env->GetStaticFieldID(cia_install_status_class, stage.c_str(),
"Lorg/citra/citra_emu/utils/"
"CiaInstallWorker$InstallStatus;")));
};
s_java_cia_install_status.emplace(Service::AM::InstallStatus::Success,
to_java_cia_install_status("Success"));
s_java_cia_install_status.emplace(Service::AM::InstallStatus::ErrorFailedToOpenFile,
to_java_cia_install_status("ErrorFailedToOpenFile"));
s_java_cia_install_status.emplace(Service::AM::InstallStatus::ErrorFileNotFound,
to_java_cia_install_status("ErrorFileNotFound"));
s_java_cia_install_status.emplace(Service::AM::InstallStatus::ErrorAborted,
to_java_cia_install_status("ErrorAborted"));
s_java_cia_install_status.emplace(Service::AM::InstallStatus::ErrorInvalid,
to_java_cia_install_status("ErrorInvalid"));
s_java_cia_install_status.emplace(Service::AM::InstallStatus::ErrorEncrypted,
to_java_cia_install_status("ErrorEncrypted"));
env->DeleteLocalRef(cia_install_status_class);
MiiSelector::InitJNI(env);
SoftwareKeyboard::InitJNI(env);
@ -264,14 +301,18 @@ void JNI_OnUnload(JavaVM* vm, void* reserved) {
env->DeleteGlobalRef(s_savestate_info_class);
env->DeleteGlobalRef(s_core_error_class);
env->DeleteGlobalRef(s_disk_cache_progress_class);
env->DeleteGlobalRef(s_load_callback_stage_class);
env->DeleteGlobalRef(s_native_library_class);
env->DeleteGlobalRef(s_cheat_class);
env->DeleteGlobalRef(s_cia_install_helper_class);
for (auto& [key, object] : s_java_load_callback_stages) {
env->DeleteGlobalRef(object);
}
for (auto& [key, object] : s_java_cia_install_status) {
env->DeleteGlobalRef(object);
}
MiiSelector::CleanupJNI(env);
SoftwareKeyboard::CleanupJNI(env);
Camera::StillImage::CleanupJNI(env);

View File

@ -9,14 +9,16 @@
#include <jni.h>
#include "video_core/rasterizer_interface.h"
namespace Service::AM {
enum class InstallStatus : u32;
} // namespace Service::AM
namespace IDCache {
JNIEnv* GetEnvForThread();
jclass GetCoreErrorClass();
jclass GetSavestateInfoClass();
jclass GetDiskCacheProgressClass();
jclass GetDiskCacheLoadCallbackStageClass();
jclass GetNativeLibraryClass();
jmethodID GetOnCoreError();
@ -28,7 +30,6 @@ jmethodID GetLandscapeScreenLayout();
jmethodID GetExitEmulationActivity();
jmethodID GetRequestCameraPermission();
jmethodID GetRequestMicPermission();
jmethodID GetDiskCacheLoadProgress();
jclass GetCheatClass();
jfieldID GetCheatPointer();
@ -38,8 +39,14 @@ jfieldID GetCheatEnginePointer();
jfieldID GetGameInfoPointer();
jclass GetDiskCacheProgressClass();
jmethodID GetDiskCacheLoadProgress();
jobject GetJavaLoadCallbackStage(VideoCore::LoadCallbackStage stage);
jclass GetCiaInstallHelperClass();
jmethodID GetCiaInstallHelperSetProgress();
jobject GetJavaCiaInstallStatus(Service::AM::InstallStatus status);
} // namespace IDCache
template <typename T = jobject>

View File

@ -56,35 +56,6 @@ std::condition_variable running_cv;
} // Anonymous namespace
static bool DisplayAlertMessage(const char* caption, const char* text, bool yes_no) {
JNIEnv* env = IDCache::GetEnvForThread();
// Execute the Java method.
jboolean result = env->CallStaticBooleanMethod(
IDCache::GetNativeLibraryClass(), IDCache::GetDisplayAlertMsg(), ToJString(env, caption),
ToJString(env, text), yes_no ? JNI_TRUE : JNI_FALSE);
return result != JNI_FALSE;
}
static std::string DisplayAlertPrompt(const char* caption, const char* text, int buttonConfig) {
JNIEnv* env = IDCache::GetEnvForThread();
jstring value = reinterpret_cast<jstring>(env->CallStaticObjectMethod(
IDCache::GetNativeLibraryClass(), IDCache::GetDisplayAlertPrompt(), ToJString(env, caption),
ToJString(env, text), buttonConfig));
return GetJString(env, value);
}
static int AlertPromptButton() {
JNIEnv* env = IDCache::GetEnvForThread();
// Execute the Java method.
return static_cast<int>(env->CallStaticIntMethod(IDCache::GetNativeLibraryClass(),
IDCache::GetAlertPromptButton()));
}
static jobject ToJavaCoreError(Core::System::ResultStatus result) {
static const std::map<Core::System::ResultStatus, const char*> CoreErrorNameMap{
{Core::System::ResultStatus::ErrorSystemFiles, "ErrorSystemFiles"},
@ -170,7 +141,7 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) {
app_loader->ReadProgramId(program_id);
GameSettings::LoadOverrides(program_id);
}
Settings::Apply();
system.ApplySettings();
Settings::LogSettings();
Camera::RegisterFactory("image", std::make_unique<Camera::StillImage::Factory>());
@ -467,10 +438,8 @@ void Java_org_citra_citra_1emu_NativeLibrary_CreateConfigFile(JNIEnv* env,
void Java_org_citra_citra_1emu_NativeLibrary_CreateLogFile(JNIEnv* env,
[[maybe_unused]] jclass clazz) {
Log::RemoveBackend(Log::FileBackend::Name());
FileUtil::CreateFullPath(FileUtil::GetUserPath(FileUtil::UserPath::LogDir));
Log::AddBackend(std::make_unique<Log::FileBackend>(
FileUtil::GetUserPath(FileUtil::UserPath::LogDir) + LOG_FILE));
Common::Log::Initialize();
Common::Log::Start();
LOG_INFO(Frontend, "Logging backend initialised");
}
@ -503,7 +472,7 @@ void Java_org_citra_citra_1emu_NativeLibrary_ReloadSettings(JNIEnv* env,
GameSettings::LoadOverrides(program_id);
}
Settings::Apply();
system.ApplySettings();
}
jstring Java_org_citra_citra_1emu_NativeLibrary_GetUserSetting(JNIEnv* env,
@ -598,20 +567,16 @@ void Java_org_citra_citra_1emu_NativeLibrary_ReloadCameraDevices(JNIEnv* env, jc
}
jboolean Java_org_citra_citra_1emu_NativeLibrary_LoadAmiibo(JNIEnv* env, jclass clazz,
jbyteArray bytes) {
jstring j_file) {
std::string filepath = GetJString(env, j_file);
Core::System& system{Core::System::GetInstance()};
Service::SM::ServiceManager& sm = system.ServiceManager();
auto nfc = sm.GetService<Service::NFC::Module::Interface>("nfc:u");
if (nfc == nullptr || env->GetArrayLength(bytes) != sizeof(Service::NFC::AmiiboData)) {
if (nfc == nullptr) {
return static_cast<jboolean>(false);
}
Service::NFC::AmiiboData amiibo_data{};
env->GetByteArrayRegion(bytes, 0, sizeof(Service::NFC::AmiiboData),
reinterpret_cast<jbyte*>(&amiibo_data));
nfc->LoadAmiibo(amiibo_data);
return static_cast<jboolean>(true);
return static_cast<jboolean>(nfc->LoadAmiibo(filepath));
}
void Java_org_citra_citra_1emu_NativeLibrary_RemoveAmiibo(JNIEnv* env, jclass clazz) {
@ -625,29 +590,16 @@ void Java_org_citra_citra_1emu_NativeLibrary_RemoveAmiibo(JNIEnv* env, jclass cl
nfc->RemoveAmiibo();
}
void Java_org_citra_citra_1emu_NativeLibrary_InstallCIAS(JNIEnv* env, [[maybe_unused]] jclass clazz,
jobjectArray path) {
const jsize count{env->GetArrayLength(path)};
std::vector<std::string> paths;
paths.reserve(count);
for (jsize idx{0}; idx < count; ++idx) {
paths.emplace_back(
GetJString(env, static_cast<jstring>(env->GetObjectArrayElement(path, idx))));
}
std::atomic<jsize> idx{count};
std::vector<std::thread> threads;
std::generate_n(std::back_inserter(threads),
std::min<jsize>(std::thread::hardware_concurrency(), count), [&] {
return std::thread{[&idx, &paths, env] {
jsize work_idx;
while ((work_idx = --idx) >= 0) {
LOG_INFO(Frontend, "Installing CIA {}", work_idx);
Service::AM::InstallCIA(paths[work_idx]);
}
}};
});
for (auto& thread : threads)
thread.join();
JNIEXPORT jobject JNICALL Java_org_citra_citra_1emu_utils_CiaInstallWorker_InstallCIA(
JNIEnv* env, jobject jobj, jstring jpath) {
std::string path = GetJString(env, jpath);
Service::AM::InstallStatus res =
Service::AM::InstallCIA(path, [env, jobj](size_t total_bytes_read, size_t file_size) {
env->CallVoidMethod(jobj, IDCache::GetCiaInstallHelperSetProgress(),
static_cast<jint>(file_size), static_cast<jint>(total_bytes_read));
});
return IDCache::GetJavaCiaInstallStatus(res);
}
jobjectArray Java_org_citra_citra_1emu_NativeLibrary_GetSavestateInfo(

View File

@ -142,14 +142,10 @@ JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_ReloadCameraDevic
jclass clazz);
JNIEXPORT jboolean Java_org_citra_citra_1emu_NativeLibrary_LoadAmiibo(JNIEnv* env, jclass clazz,
jbyteArray bytes);
jstring j_file);
JNIEXPORT void Java_org_citra_citra_1emu_NativeLibrary_RemoveAmiibo(JNIEnv* env, jclass clazz);
JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_InstallCIAS(JNIEnv* env,
jclass clazz,
jobjectArray path);
JNIEXPORT jobjectArray JNICALL
Java_org_citra_citra_1emu_NativeLibrary_GetSavestateInfo(JNIEnv* env, jclass clazz);
@ -162,6 +158,10 @@ JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_LoadState(JNIEnv*
JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_LogDeviceInfo(JNIEnv* env,
jclass clazz);
JNIEXPORT jobject JNICALL Java_org_citra_citra_1emu_NativeLibrary_InstallCIA(JNIEnv* env,
jclass clazz,
jstring file);
#ifdef __cplusplus
}
#endif

View File

@ -7,7 +7,7 @@
<string name="app_notification_channel_name" translatable="false">Citra</string>
<string name="app_notification_channel_id" translatable="false">Citra</string>
<string name="app_notification_channel_description">Citra 3DS emulator notifications</string>
<string name="app_notification_running">Citra is running</string>
<string name="app_notification_running">Citra is Running</string>
<string name="app_game_install_description">Next, you will need to select a Game Folder. Citra will display all of the 3DS ROMs inside of the selected folder in the app.\n\nCIA ROMs, updates and DLC will need to be installed separately by clicking on the folder icon and selecting Install CIA.</string>
<!-- Input related strings -->
@ -42,56 +42,57 @@
<string name="design_updated">Theme will update when exiting Settings</string>
<!-- Core settings strings -->
<string name="cpu_jit">Enable CPU JIT</string>
<string name="cpu_jit">CPU JIT</string>
<string name="cpu_jit_description">Uses the Just-in-Time (JIT) compiler for CPU emulation. When enabled, game performance will be significantly improved.</string>
<string name="init_clock">System clock type</string>
<string name="init_clock">Clock</string>
<string name="init_clock_description">Set the emulated 3DS clock to either reflect that of your device or start at a simulated date and time.</string>
<!-- System settings strings -->
<string name="init_time">System clock starting time override</string>
<string name="init_time_description">If the \"System clock type\" setting is set to \"Simulated clock\", this changes the fixed date and time to start at.</string>
<string name="emulated_region">Emulated region</string>
<string name="emulated_language">Emulated language</string>
<string name="plugin_loader">Enable 3GX Plugin Loader</string>
<string name="plugin_loader_description">Loads 3GX plugins from the emulated SD if they are available.</string>
<string name="allow_plugin_loader">Allow apps to change plugin loader state</string>
<string name="allow_plugin_loader_description">Allow homebrew apps to enable the plugin loader even when it is disabled.</string>
<string name="clock">Clock</string>
<string name="init_time">Offset Time</string>
<string name="init_time_description">If the clock is set to \"Simulated clock\", this changes the fixed date and time to start at.</string>
<string name="emulated_region">Region</string>
<string name="emulated_language">Language</string>
<string name="plugin_loader">3GX Plugin Loader</string>
<string name="plugin_loader_description">Loads 3GX plugins from the emulated SD card if they are available.</string>
<string name="allow_plugin_loader">Allow Games to Change Plugin Loader State</string>
<string name="allow_plugin_loader_description">Allows homebrew apps to enable the plugin loader even when it is disabled.</string>
<!-- Camera settings strings -->
<string name="inner_camera">Inner Camera</string>
<string name="outer_left_camera">Outer Left Camera</string>
<string name="outer_right_camera">Outer Right Camera</string>
<string name="image_source">Image Source</string>
<string name="image_source">Camera Image Source</string>
<string name="image_source_description">Sets the image source of the virtual camera. You can use an image file, or a device camera when supported.</string>
<string name="camera_device">Camera Device</string>
<string name="camera_device">Camera</string>
<string name="camera_device_description">If the \"Image Source\" setting is set to \"Device Camera\", this sets the physical camera to use.</string>
<string name="camera_facing_front">Front</string>
<string name="camera_facing_back">Back</string>
<string name="camera_facing_external">External</string>
<string name="image_flip">Image Flip</string>
<string name="image_flip">Flip</string>
<!-- Graphics settings strings -->
<string name="renderer">Renderer</string>
<string name="graphics_api">Graphics API</string>
<string name="renderer_debug">Enable debug renderer</string>
<string name="renderer_debug_description">Log additional graphics related debug information. When enabled, game performance will be significantly reduced</string>
<string name="renderer_debug">Debug Renderer</string>
<string name="renderer_debug_description">Log additional graphics related debug information. When enabled, game performance will be significantly reduced.</string>
<string name="vsync">Enable V-Sync</string>
<string name="vsync_description">Synchronizes the game frame rate to the refresh rate of your device.</string>
<string name="linear_filtering">Enable linear filtering</string>
<string name="linear_filtering">Linear Filtering</string>
<string name="linear_filtering_description">Enables linear filtering, which causes game visuals to appear smoother.</string>
<string name="texture_filter_name">Texture Filter</string>
<string name="texture_filter_description">Enhances the visuals of games by applying a filter to textures. The supported filters are Anime4K Ultrafast, Bicubic, ScaleForce, and xBRZ freescale.</string>
<string name="hw_shaders">Enable hardware shader</string>
<string name="hw_shaders">Enable Hardware Shader</string>
<string name="hw_shaders_description">Uses hardware to emulate 3DS shaders. When enabled, game performance will be significantly improved.</string>
<string name="shaders_accurate_mul">Enable accurate shader multiplication</string>
<string name="shaders_accurate_mul">Accurate Multiplication</string>
<string name="shaders_accurate_mul_description">Uses more accurate multiplication in hardware shaders, which may fix some graphical bugs. When enabled, performance will be reduced.</string>
<string name="asynchronous_gpu">Enable asynchronous GPU emulation</string>
<string name="asynchronous_gpu_description">Uses a separate thread to emulate the GPU asynchronously. When enabled, performance will be improved.</string>
<string name="frame_limit_enable">Enable limit speed</string>
<string name="frame_limit_enable">Limit Speed</string>
<string name="frame_limit_enable_description">When enabled, emulation speed will be limited to a specified percentage of normal speed.</string>
<string name="frame_limit_slider">Limit speed percent</string>
<string name="frame_limit_slider">Limit Speed Percent</string>
<string name="frame_limit_slider_description">Specifies the percentage to limit emulation speed. With the default of 100% emulation will be limited to normal speed. Values higher or lower will increase or decrease the speed limit.</string>
<string name="internal_resolution">Internal resolution</string>
<string name="internal_resolution">Internal Resolution</string>
<string name="internal_resolution_description">Specifies the resolution used to render at. A high resolution will improve visual quality a lot but is also quite heavy on performance and might cause glitches in certain games.</string>
<string name="performance_warning">Turning off this setting will significantly reduce emulation performance! For the best experience, it is recommended that you leave this setting enabled.</string>
<string name="debug_warning">Warning: Modifying these settings will slow emulation</string>
@ -100,24 +101,25 @@
<string name="factor3d">Depth</string>
<string name="factor3d_description">Specifies the value of the 3D slider. This should be set to higher than 0% when Stereoscopic 3D is enabled.</string>
<string name="cardboard_vr">Cardboard VR</string>
<string name="cardboard_screen_size">Cardboard Screen size</string>
<string name="cardboard_screen_size">Cardboard Screen Size</string>
<string name="cardboard_screen_size_description">Scales the screen to a percentage of its original size.</string>
<string name="cardboard_x_shift">Horizontal shift</string>
<string name="cardboard_x_shift">Horizontal Shift</string>
<string name="cardboard_x_shift_description">Specifies the percentage of empty space to shift the screens horizontally. Positive values move the two eyes closer to the middle, while negative values move them away.</string>
<string name="cardboard_y_shift">Vertical shift</string>
<string name="cardboard_y_shift">Vertical Shift</string>
<string name="cardboard_y_shift_description">Specifies the percentage of empty space to shift the screens vertically. Positive values move the two eyes towards the bottom, while negative values move them towards the top.</string>
<string name="use_shader_jit">Use shader JIT</string>
<string name="use_disk_shader_cache">Use disk shader cache</string>
<string name="use_shader_jit">Shader JIT</string>
<string name="use_disk_shader_cache">Disk Shader Cache</string>
<string name="use_disk_shader_cache_description">Reduce stuttering by storing and loading generated shaders to disk. It cannot be used without Enabling Hardware Shader.</string>
<string name="utility">Utility</string>
<string name="dump_textures">Dump textures</string>
<string name="dump_textures_description">Dumps textures to dump/textures/[GAME ID]</string>
<string name="custom_textures">Use custom textures</string>
<string name="custom_textures_description">Uses custom textures found in load/textures/[GAME ID]</string>
<string name="preload_textures">Preload custom textures</string>
<string name="dump_textures">Dump Textures</string>
<string name="dump_textures_description">Textures are dumped to dump/textures/[Title ID]/.</string>
<string name="custom_textures">Custom Textures</string>
<string name="custom_textures_description">Textures are loaded from load/textures/[Title ID]/.</string>
<string name="preload_textures">Preload Custom Textures</string>
<string name="preload_textures_description">Loads all custom textures into memory. This feature can use a lot of memory.</string>
<string name="async_custom_loading">Async custom texture loading</string>
<string name="async_custom_loading_description">Loads custom textures in the background with worker threads to reduce loading stutter.</string>
<string name="async_custom_loading">Async Custom Texture Loading</string>
<string name="async_custom_loading_description">Load custom textures asynchronously with background threads to reduce loading stutter.</string>
<!-- Premium strings -->
<string name="premium_text">Premium</string>
<string name="premium_settings_upsell">Upgrade to Premium and support Citra!</string>
@ -126,7 +128,7 @@
<string name="premium_settings_welcome_description">Thank you for your support!</string>
<!-- Audio settings strings -->
<string name="audio_stretch">Enable audio stretching</string>
<string name="audio_stretch">Audio Stretching</string>
<string name="audio_stretch_description">Stretches audio to reduce stuttering. When enabled, increases audio latency and slightly reduces performance.</string>
<string name="audio_input_type">Audio Input Device</string>
@ -136,7 +138,7 @@
<string name="ini_saved">Saved settings</string>
<string name="gameid_saved">Saved settings for %1$s</string>
<string name="error_saving">Error saving %1$s.ini: %2$s</string>
<string name="loading">Loading...</string>
<string name="loading">Loading</string>
<!-- Game Grid Screen-->
<string name="grid_menu_core_settings">Settings</string>
@ -162,7 +164,7 @@
<string name="preferences_debug">Debug</string>
<!-- ROM loading errors -->
<string name="loader_error_encrypted">Your ROM is encrypted</string>
<string name="loader_error_encrypted">Your ROM is Encrypted</string>
<string name="loader_error_invalid_format">Invalid ROM format</string>
<!-- Emulation Menu -->
@ -178,7 +180,7 @@
<string name="emulation_toggle_controls">Toggle Controls</string>
<string name="emulation_control_scale">Adjust Scale</string>
<string name="emulation_control_joystick_rel_center">Relative Stick Center</string>
<string name="emulation_control_dpad_slide_enable">Enable D-Pad Sliding</string>
<string name="emulation_control_dpad_slide_enable">D-Pad Sliding</string>
<string name="emulation_open_settings">Open Settings</string>
<string name="emulation_open_cheats">Open Cheats</string>
<string name="emulation_switch_screen_layout">Landscape Screen Layout</string>
@ -194,12 +196,12 @@
<string name="menu_emulation_amiibo">Amiibo</string>
<string name="menu_emulation_amiibo_load">Load</string>
<string name="menu_emulation_amiibo_remove">Remove</string>
<string name="select_amiibo">Select Amiibo file</string>
<string name="amiibo_load_error">Error loading Amiibo</string>
<string name="select_amiibo">Select Amiibo File</string>
<string name="amiibo_load_error">Error Loading Amiibo</string>
<string name="amiibo_load_error_message">While loading the specified Amiibo file, an error occurred. Please check that the file is correct.</string>
<string name="write_permission_needed">You need to allow write access to external storage for the emulator to work</string>
<string name="load_settings">Loading Settings...</string>
<string name="load_settings">Loading Settings</string>
<string name="external_storage_not_mounted">The external storage needs to be available in order to use Citra</string>
@ -247,8 +249,8 @@
<string name="fatal_error_message">A fatal error occurred. Check the log for details.\nContinuing emulation may result in crashes and bugs.</string>
<!-- Disk shader cache -->
<string name="preparing_shaders">Preparing shaders</string>
<string name="building_shaders">Building shaders</string>
<string name="preparing_shaders">Preparing Shaders</string>
<string name="building_shaders">Building Shaders</string>
<!-- Cheats -->
<string name="cheats">Cheats</string>
@ -262,4 +264,22 @@
<string name="cheats_error_no_name">Name can\'t be empty</string>
<string name="cheats_error_no_code_lines">Code can\'t be empty</string>
<string name="cheats_error_on_line">Error on line %1$d</string>
<!-- CIA Install -->
<plurals name="cia_install_toast">
<item quantity="one">Installing %d file. See notification for more details.</item>
<item quantity="other">Installing %d files. See notification for more details.</item>
</plurals>
<string name="cia_install_notification_channel_name" translatable="false">Citra CIA Install</string>
<string name="cia_install_notification_channel_id" translatable="false">citra-cia</string>
<string name="cia_install_notification_channel_description">Citra notifications during CIA Install</string>
<string name="cia_install_notification_title">Installing CIA</string>
<string name="cia_install_notification_installing">Installing %s (%d/%d)</string>
<string name="cia_install_notification_success_title">Successfully installed CIA</string>
<string name="cia_install_notification_error_title">Failed to install CIA</string>
<string name="cia_install_success">\"%s\" has been installed successfully</string>
<string name="cia_install_error_aborted">The installation of \"%s\" was aborted.\n Please see the log for more details</string>
<string name="cia_install_error_invalid">\"%s\" is not a valid CIA</string>
<string name="cia_install_error_encrypted">\"%s\" must be decrypted before being used with Citra.\n A real 3DS is required</string>
<string name="cia_install_error_unknown">An unknown error occurred while installing \"%s\".\n Please see the log for more details</string>
</resources>

View File

@ -1,17 +0,0 @@
package org.citra.citra_emu;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() {
assertEquals(4, 2 + 2);
}
}

View File

@ -1,28 +0,0 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
mavenCentral()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.4.2'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
mavenCentral()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}

View File

@ -0,0 +1,14 @@
// Copyright 2023 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id("com.android.application") version "8.0.2" apply false
id("com.android.library") version "8.0.2" apply false
id("org.jetbrains.kotlin.android") version "1.8.21" apply false
}
tasks.register("clean").configure {
delete(rootProject.buildDir)
}

View File

@ -14,3 +14,6 @@ org.gradle.jvmargs=-Xmx1536m
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
android.native.buildOutput=verbose
android.defaults.buildfeatures.buildconfig=true
android.nonTransitiveRClass=false
android.nonFinalResIds=false

View File

@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip

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