Compare commits

..

140 Commits

Author SHA1 Message Date
c02b0a0113 logging: backend: Migrate to the new Common::FS library 2022-10-31 20:57:49 +02:00
97cbcc6e49 common: fs: Initial port of yuzu fs library 2022-10-31 20:52:07 +02:00
9d6aa2db81 file_util: Migrate remaining file handling functions over to std::filesystem
Converts creation and deletion functions over to std::filesystem,
simplifying our file-handling code.

Notably with this, CopyDir will now function on Windows.
2022-10-31 19:49:16 +02:00
0675bd946c file_util: Migrate Exists() and IsDirectory() over to std::filesystem
Greatly simplifies our file-handling code for these functions.
2022-10-30 21:04:16 +02:00
281f2926bb common/fileutil: Convert namespace to Common::FS
Migrates a remaining common file over to the Common namespace, making it
consistent with the rest of common files.

This also allows for high-traffic FS related code to alias the
filesystem function namespace as

namespace FS = Common::FS;

for more concise typing.
2022-10-30 21:03:49 +02:00
349ac6ac05 vk_texture_runtime: Implement RGBA4 converter
* Fixes graphics in NES Remix. Need to also do a reinterpreter some time, but this will suffice for now
2022-10-30 19:10:18 +02:00
16571a96a2 texture_downloader_es: Remove invalid operations 2022-10-30 18:51:27 +02:00
a0e9836386 gl_texture_runtime: Use OGLStreamBuffer for uploads/downloads
* Much better than the current implementation
2022-10-30 18:41:47 +02:00
fb10d05f97 vk_stream_buffer: Cleanup flush barrier 2022-10-30 09:34:08 +02:00
182bebf272 video_core: Reorder microprofile defines 2022-10-29 20:49:39 +03:00
7626804a90 citra_qt: Add shader cache options 2022-10-29 15:04:05 +03:00
20496e8ca4 renderer_vulkan: Rewrite stream buffer, again...
* The previous implemention was fine, but it wasted space. Buckets now are just ticks attached to a particular buffer region, which means we can flush/map arbitrary regions

* A bug in the texture runtime is also fixed which commited to the same buffer twice
2022-10-29 15:03:55 +03:00
b4184a3c2b renderer_vulkan: Pack PicaFSConfig
* Using bitfields the struct size was reduced from 420 to 190 bytes. which should speed up hashing and copying to the worker thread
2022-10-29 15:02:13 +03:00
2251d96d4d renderer_vulkan: Cleanup vertex array setup
* Also the function would commit more data then it requested leading to out of bound crashes
2022-10-29 15:02:12 +03:00
c028a8c7c5 renderer_vulkan: Remove AttribType
* Use VertexAttributeFormat to avoid unnecessary enum casts
2022-10-29 15:01:49 +03:00
359f97be22 video_core: Move HardwareVertex to RasterizerAccelerated 2022-10-29 15:01:49 +03:00
748f8a0658 video_core: Move api agnostic uniform updates to RasterizerAccelerated 2022-10-29 15:01:48 +03:00
a7611bb2d3 renderer_vulkan: Fix swapchain resizing 2022-10-29 15:01:13 +03:00
6f35a3bf37 renderer_vulkan: Add single-thread record ability to the scheduler
* Async is pretty nice but games that do a lot of flushes might have worse performance due to thread synchronization overhead

* I haven't noticed any cases of this yet but it doesn't hurt making this a UI option
2022-10-29 14:59:21 +03:00
58573dd7b3 citra_qt: Refuse to enable debug option if the layers are not available 2022-10-29 14:59:21 +03:00
11728d6772 renderer_vulkan: Scheduler and presentation rewrite
* This commit ports yuzu's async scheduler replacing our older and crummier version
  Commands are recorded by the scheduler and processed by a separate worker thread.

* Queue submission is also moved to the worker thread which should alliviate slowdowns related to vkQueueSubmit stalls

* Fragment shader compilation and queue submission are also moved to that thread to reduce stutters
2022-10-28 23:05:37 +03:00
a99be221b2 externals: Update vulkan-headers 2022-10-28 23:05:37 +03:00
f656610a41 common: Remove concepts usage 2022-10-28 23:05:37 +03:00
cfa1a7b91c citra_qt: Include unordered_map to fix macOS compilation 2022-10-28 23:05:37 +03:00
52b1fc4889 renderer_vulkan: Fix shader hash type 2022-10-28 23:05:37 +03:00
01e2b6cdaa code: Remove usages of std::ranges
* MacOS is still runining my C++ 20 fun
2022-10-28 23:05:37 +03:00
f75380fc93 renderer_vulkan: Prefer immediate over mailbox present mode 2022-10-28 23:05:37 +03:00
18af49a0ca renderer_vulkan: Bump vertex buffer size
* So software shaders don't crash
2022-10-28 23:05:37 +03:00
c7e64f6c7b renderer_vulkan: Add more microprofile targets 2022-10-28 23:05:37 +03:00
0a40a513a6 renderer_vulkan: Improve StreamBuffer API and use it in TextureRuntime
* Also use separate upload and download buffers optimized for write and readback respectively. This gives a huge 20+ FPS boost in most games which were bottlenecked by slow reads
2022-10-28 23:05:37 +03:00
a4dc6a55b7 renderer_vulkan: Fix allocation caching bug 2022-10-28 23:05:37 +03:00
7dce5be263 renderer_opengl: Port scaled upload/download code from vulkan 2022-10-28 23:05:37 +03:00
3f7d97da4c renderer_vulkan: Include algorithm in vk_common
* Appears to be a bug in vulkan-hpp
2022-10-28 23:05:37 +03:00
a11b4dd051 renderer_vulkan: Use linear filtering when possible
* Fixes blocky artifacts in Samus Returns
2022-10-28 23:05:37 +03:00
c78847b2b6 renderer_vulkan: Abstract descriptor management
* The pipeline cache was starting to get cluttered
2022-10-28 23:05:37 +03:00
8faa7a6e02 renderer_vulkan: Bump descriptor set allocation limit 2022-10-28 23:05:37 +03:00
acf4b4e5fb renderer_vulkan: Fix storage descriptor binding and respect color mask
* RGBA8 surfaces now expose an additional R32Uint view used for storage descriptors. The format is guaranteed by the spec to support atomic loads/stores. This requires the mutable flag which incurs a performance cost, but might be better than breaking the current renderpass each draw when rendering shadows, especially on mobile

* Color mask is also implemented which fixes Street Fighter and Monster Hunter Stories
2022-10-28 23:05:37 +03:00
3a0ca63d91 renderer_vulkan: Implement depth uploads with blit 2022-10-28 23:05:37 +03:00
1e96775203 renderer_vulkan: Use intermediate copy when framebuffer is used both as attachment and shader input 2022-10-28 23:05:37 +03:00
6d27e8be8d renderer_vulkan: Respect disk shader option 2022-10-28 23:05:37 +03:00
c357a8b9b6 renderer_vulkan: Fix staging buffer size 2022-10-28 23:05:37 +03:00
7ad982f123 renderer_vulkan: Catch and log more runtime errors
* Also add the ability to enable command buffer dumping which is very useful
2022-10-28 23:05:37 +03:00
dd3d24bfec renderer_vulkan: Batch allocate descriptor sets
* Less driver calls should lead to better performance
2022-10-28 23:05:37 +03:00
489bbb98b2 renderer_vulkan: Emulate border color if possible 2022-10-28 23:05:37 +03:00
5c9543e39d renderer_vulkan: Implement scaled uploads and downloads
* This commit includes large changes to have textures are handling. Instead of using ImageAlloc, Surface is used instead which provides multiple benefits: automatic recycling on destruction and ability to use the TextureRuntime interface to simplify operations

* Layout tracking is also implemented which allows transitioning of individual mip levels without errors

* This fixes graphical errors in multiple games which relied on framebuffer uploads
2022-10-28 23:05:37 +03:00
49085d400c renderer_vulkan: Fix renderpass issues
* The cache didn't take into account the framebuffer and render area used, so if these changed the renderpass wouldn't restart. This caused graphical bugs in Pokemon X/Y
2022-10-28 23:05:37 +03:00
8be9ea4f4a renderer_vulkan: Update stencil compare mask 2022-10-28 23:05:37 +03:00
a71c288252 citra_qt: Fix graphics api indicator alignment 2022-10-28 23:04:38 +03:00
159809eb32 renderer_opengl: Fix OpenGLES issues
* Always request a 4.4 context until I figure out how to get Qt to cooperate

* Use RGBA for BGR since the converted table will do that conversion
2022-10-28 23:04:38 +03:00
2a4f0ce8de renderer_vulkan: Report perf stats 2022-10-28 23:04:38 +03:00
4c8f1c83c8 renderer_vulkan: Better error handling 2022-10-28 23:04:38 +03:00
98f6d697d8 renderer_vulkan: Allow direct allocation of images 2022-10-28 23:04:38 +03:00
4636735783 renderer_vulkan: Fix incorrect depth format detection
* Intel iGPUs don't support blit on all depth/stencil formats which caused issues since the runtime checks for this while the renderpass cache does not
2022-10-28 23:04:38 +03:00
8a2770bf83 renderer_vulkan: Actually minize state changes
* Keep track of the current state and only update it when needed. Previously games would set the same state over and over cluttering renderdoc logs
2022-10-28 23:04:37 +03:00
f1e09c1ea1 renderer_vulkan: Fix broken sync without timeline semaphores 2022-10-28 23:04:37 +03:00
2423e645f1 renderer_vulkan: Allocate descriptor sets during reinterpretation 2022-10-28 23:04:37 +03:00
0eaae31f9f renderer_vulkan: Enable logic ops and fix swapchain resizing 2022-10-28 23:04:37 +03:00
4f9b545296 renderer_vulkan: Clear stencil with renderpass
* Fixes outline retension in pokemon games
2022-10-28 23:04:37 +03:00
628d70e112 renderer_vulkan: Fix pipeline cache crashes 2022-10-28 23:04:37 +03:00
9991b9b12b renderer_vulkan: Optimize tiled format convertion + fix vertex buffer alignment
* Integrate format convertion to the morton copy function, removing the need for an intermediate copy and convertion pass. This should be beneficial for performance especially since most games use tiled textures

* Also bump vertex buffer size to avoid crashes with hardware shaders and provide correct offset on normal draws which fixes glitches in pokemon Y

* Reduce the local group size to 8 in the D24S8 compute shader which fixes graphical issues in the afformentioned pokemon games at native resolution

* Set LOD to 0 instead of 0.25 to fix another glitch in pokemon y
2022-10-28 23:04:37 +03:00
e4bcf73c5a renderer_opengl: Fix broken texture copy
* Resolves graphical bugs in Professor Layton vs Ace Attorney when using OpenGL
2022-10-28 23:04:37 +03:00
b693d205e4 renderer_vulkan: Pipeline cache fixes
* Delete cache file if found invalid

* Name it after the vendor/device ids so each physical devices gets a separate cache
2022-10-28 23:04:37 +03:00
91621ec202 video_core: Fix renderpass cache bug and introduce RGBA -> BGR converter 2022-10-28 23:04:37 +03:00
948f72d320 renderer_opengl: Specify precision in compute shader and add RGB5A1 converter
* Fixes OpenGLES crash
2022-10-28 23:04:37 +03:00
8c5b417486 renderer_vulkan: Complete hardware shader support
* With these changes all commercial games I tested work fine and get a massive performance boost
2022-10-28 23:04:37 +03:00
51685ee2db renderer_vulkan: Begin hardware shader support
* Still experimental and works only with homebrew
2022-10-28 23:04:37 +03:00
079e4aa205 citra: Fix build issues with MinGW and MSVC 2022-10-28 23:04:37 +03:00
48edfb891b renderer_vulkan: Fix warnings and cleanup 2022-10-28 23:04:37 +03:00
915406354c code: Run clang-format 2022-10-28 23:04:31 +03:00
6f3fc32a93 code: Address build issues 2022-10-28 23:03:18 +03:00
ebfa98d31d video_core: Re-implement format reinterpretation
* Same as before but D24S8 to RGBA8 is switched to a compute shader which should provide better throughput and is much simpler to implement in Vulkan
2022-10-28 23:03:18 +03:00
3095ee91a8 citra_qt: Add physical device selection dialog 2022-10-28 23:03:18 +03:00
fadeecfe6d code: Resolve unused variable warnings 2022-10-28 23:03:16 +03:00
2a1598036e renderer_opengl: Unbind unused framebuffer targets
* Fixes graphical glitches in many games for some reason
2022-10-28 23:02:23 +03:00
58f01112c5 renderer_opengl: Emulate texture copy with blit for now 2022-10-28 23:02:23 +03:00
7e7b3dc18c renderer_opengl: Address buffer overflow 2022-10-28 23:02:23 +03:00
d4a3f60575 video_core: Small code improvements 2022-10-28 23:02:23 +03:00
f8cbf783cb renderer_vulkan: Don't sample from mipmaps when using texture cubes
* Mipmaps for texture cubes are unimplemented in the rasterizer cache, so sampling from mipmaps will return nothing
2022-10-28 23:02:23 +03:00
dc0cddb7de citra_qt: Switch all strings to multiarg 2022-10-28 23:02:23 +03:00
9cef9d4c58 code: Address more compiler warnings 2022-10-28 23:02:23 +03:00
dada05801f citra_qt: Fix more warnings/deprecated functions 2022-10-28 23:02:23 +03:00
9bc71a3307 input_common: Small fix 2022-10-28 23:02:23 +03:00
98274273b1 citra_qt: Improve graphics API intergration
* Add renderer debug option which toggles debug output in OpenGL/validation layers in Vulkan

* Fix many warnings and replace deprecated Qt functionailty with newer alternatives
2022-10-28 23:02:23 +03:00
269db2bfb8 rasterizer_cache: Code cleanup
* Merge utils and types to a single header
2022-10-28 23:02:23 +03:00
d27c1c8606 texture_decode: Prefer std::memcpy where possible 2022-10-28 23:02:23 +03:00
891b4bff18 renderer_vulkan: Rework format handling
* This is a pretty large commit that aims to solve some issues with the current format system
* The instance now builds at application initialization an array of format traits for each pixel format
  that includes information such as blit/attachment/storage support and fallback formats
* The runtime doesn't ask the instance for formats but receives these traits and can dedice on its own what to build
  For now we do the same as before, we require both blit and attachment support

* Morton swizzling also sees many bug fixes. The previous code was very hacky and didn't work for partial
  texture updates. It was also inconsistent, as it would take a tiled_buffer and write to the middle of linear
* Now the functions have been greatly simplified and adjusted to work better with std::span. This fixes out of bounds
  errors and texture glitches (like the display in Mario Kart 7)
2022-10-28 23:02:23 +03:00
eeccdc02fc renderer_vulkan: Handle scheduler switches properly 2022-10-28 23:02:23 +03:00
29ee94c3f5 vk_platform: Fix wayland build 2022-10-28 23:02:23 +03:00
8936641841 renderer_vulkan: Rewrite stream buffer + other fixes
* Emulate blend color and clip planes correctly

* Don't hack the depth in the vertex shader, use VK_EXT_depth_clip_control for now to set the range to -1, 1

* Rewrite the stream buffer to remove flickering problems. The new implementation doesn't try to be smart about holding memory. It divides the allocation in SCHEDULER_COMMAND_COUNT buckets and automatically switches between them based on the current slot index
2022-10-28 23:02:23 +03:00
e1f6b88e7b vk_rasterizer: Bump vertex buffer size
* Helps with the stuttering, indicating the issue is with the vertex buffer somehow
2022-10-28 23:02:23 +03:00
64d809f06a pica_to_vk: Set cull mode correctly 2022-10-28 23:02:23 +03:00
ebd23026a0 renderer_vulkan: Minimize state changes
* Store current renderpass/pipelines and only rebind when they change

* Enable extended dynamic state support and only apply them when they change
2022-10-28 23:02:23 +03:00
6e1bfe9949 rasterizer_cache: Explicitely pass end_offset to swizzle functions
* This addresses overflow issues
2022-10-28 23:02:23 +03:00
854092ce4f renderer_vulkan: Implement partial color/depth clears 2022-10-28 23:02:23 +03:00
90d24caaf8 renderer_vulkan: Add second screen and remove renderpass breakage 2022-10-28 23:02:23 +03:00
65400936c7 renderer_vulkan: Improve task scheduler synchronization
* Use multiple semaphores for swapchain sync and improve the Submit API
2022-10-28 23:02:23 +03:00
3f9e5a2b42 renderer_vulkan: Use timeline semaphores if available 2022-10-28 23:02:23 +03:00
34ba320c3d renderer_vulkan: Pipeline cache fixes 2022-10-28 23:02:23 +03:00
ec9f1902f5 renderer_vulkan: Isolate surface creation to vk_platform.cpp
* Also cleanup the init code somewhat
2022-10-28 23:02:23 +03:00
c72a365d78 renderer_vulkan: Add ABGR -> RGBA byteswap
* Vulkan doesn't support VK_FORMAT_R8G8B8A8_UNORM_PACK32 unfortunately. Fixes graphical issues on the gpusprites demo
2022-10-28 23:02:23 +03:00
8f211613a3 externals: Trim down glslang build
* When the install option is turned on, glslang will override the install dir which causes SDL2 to fail
2022-10-28 23:02:23 +03:00
30885b72be common: math_util: Include <compare> 2022-10-28 23:02:23 +03:00
beb078a71b cmake: Lower cmake requirement to 3.14 2022-10-28 23:02:23 +03:00
a65f9ea5a8 renderer_vulkan: Address more validation errors and stop memory leakage
* The transition settings are temporary until I write a proper layout tracking system
2022-10-28 23:02:23 +03:00
f9c11eab96 renderer_vulkan: Fix some validation errors
* Temporarily add glm until I figure out how to fix the alignment
2022-10-28 23:02:23 +03:00
794f6e4a67 renderer_vulkan: Implement renderer and rasterizer classes
* Also WIP. Vulkan crashes when allocating command buffers, need to investigate...
2022-10-28 23:02:23 +03:00
c85731f3ae renderer_vulkan: Add experimental Vulkan renderer
* Stil extremelly WIP and missing the rasterizer/renderer classes
2022-10-28 23:02:23 +03:00
e1542cea84 externals: Add vulkan headers and vma 2022-10-28 23:02:23 +03:00
887ef51f04 rasterizer_cache: Refactor texture cube interface
* Reuse our Surface class instead of having a separate one, to avoid reimplementing stuff in the backend
2022-10-28 23:02:23 +03:00
d809687aeb gl_texture_runtime: Clean up texture upload/download code
* Improve readability and code clarity
2022-10-28 23:02:23 +03:00
96ec85a72e rasterizer_cache: Use Common::Rectangle everywhere
* Make a nice alias for it and use it instead of having Rect2D/Region2D. Makes the new design less intrusive to the current cache
2022-10-28 23:02:23 +03:00
0ed4d493ad rasterizer_cache: Make into template
* This is the final step, now RasterizerCache is compltely decoupled from OpenGL (technically not yet, but that's talking details). For now texture filtering and some GLES paths have been disabled and will be reimplemented in the following commits
2022-10-28 23:02:23 +03:00
78be1e7c17 rasterizer_cache: Use PBO staging buffer cache for texture uploads/downloads 2022-10-28 23:02:23 +03:00
2963682722 rasterizer_cache: Reorder methods 2022-10-28 23:02:23 +03:00
98eea4dcca rasterizer_cache: Remove remnants of cached_pages 2022-10-28 23:02:23 +03:00
98a4a18201 rasterizer_cache: Fix texture cube blitting
* The target was GL_TEXTURE_2D instead of GL_TEXTURE_CUBE_MAP_*
2022-10-28 23:02:23 +03:00
3619bd33b1 morton_swizzle: Implement texture formats in UNSWIZZLE_TABLE
* I can now remove that loop that has been messing with my OCD
2022-10-28 23:02:23 +03:00
fa870be263 morton_swizzle: Use tiled_buffer instead of reading data from g_memory
* It's much safer and removes hardcoded global state usage
2022-10-28 23:02:23 +03:00
3a6d19f51f rasterizer_accelerated: Zero intialize cached_pages
* Resolves random crashes because count takes random values
2022-10-28 23:02:23 +03:00
73d6a9d585 texture_runtime: Add staging buffer lock mechanism 2022-10-28 23:02:22 +03:00
5d48107dd6 cached_surface: Remove custom texture logic
* Makes things more complicated and is in the way. It's probably already
broken by recent changes, so I'll need to reimplement it anyway
2022-10-28 23:01:42 +03:00
a306931e1c renderer_opengl: Add driver class to report info/bugs 2022-10-28 23:01:42 +03:00
b3803c5002 rasterizer_cache: Add staging buffer cache for uploads/downloads
*  In addition bump context version to 4.4 to enforce ARB_buffer_storage and use EXT_buffer_storage for GLES which is support on many mobile devices
2022-10-28 23:01:42 +03:00
c412c116d8 rasterizer_cache: Improve TextureRuntime API
* This makes every operation more explicit and mimics more the Vulkan API
2022-10-28 23:01:42 +03:00
6ce4493e14 renderer_opengl: Encapsulate sync objects in OGLSync 2022-10-28 23:01:04 +03:00
d6e545932a code: Use std::numbers::pi 2022-10-28 23:01:04 +03:00
542bae4581 code: dodge PAGE_SIZE #define
Some header files, specifically for OSX and Musl libc define PAGE_SIZE to be a number
This is great except in citra we're using PAGE_SIZE as a variable

Specific example
`static constexpr u64 PAGE_SIZE = u64(1) << PAGE_BITS;`

PAGE_SIZE PAGE_BITS PAGE_MASK are all similar variables.
Simply deleted the underscores, and then added CITRA_ prefix
2022-10-28 23:01:02 +03:00
307154a06f morton_swizzle: Optimize and use std::span 2022-10-28 22:56:47 +03:00
725afe33ef morton_swizzle: Avoid buffer underflow
* Check the y coordinate before decrementing linear_buffer
2022-10-28 22:56:47 +03:00
bb58056ebe morton_swizzle: Move out of bounds texture check out of the decode loop
* Running relative expensive checks like this on a hot path causes small but measurable performance loss. Tested SMD wit this and it doesn't crash
2022-10-28 22:56:47 +03:00
f69a33574c rasterizer_cache: Use SurfaceType instead of Aspect
* It was doing pointless enum conversions when both enums described the same thing
2022-10-28 22:56:47 +03:00
1a48cf7e7d rasterizer_cache: Separate texture swizzling to utils 2022-10-28 22:56:47 +03:00
2833d94a3b rasterizer_cache: Remove OpenGL references from morton_swizzle 2022-10-28 22:56:47 +03:00
9b0aa5135e rasterizer_cache: microprofile: Rename OpenGL to RasterizerCache 2022-10-28 22:56:47 +03:00
9787efc7ee citra_qt: Forbid renderer change during runtime
* It's an endless source of problems and isn't usefull
2022-10-28 22:56:47 +03:00
623293d272 rasterizer_cache: Touch up MatchFlags comments 2022-10-28 22:56:47 +03:00
5ab5fdcc22 rasterizer_cache: Drop OpenGL postfix 2022-10-28 22:56:47 +03:00
1b1988a37a rasterizer_cache: Shorten filenames and general cleanup
* AllocateSurfaceTexture now takes the PixelFormat directly as FormatTuple is an OpenGL struct and will be moved there
2022-10-28 22:56:47 +03:00
f584d143ff video_core: Move UpdatePagesCachedCount to RasterizerAccelerated 2022-10-28 22:56:47 +03:00
56c679595f citra_qt: Prepare GUI for Vulkan support 2022-10-28 22:56:45 +03:00
375 changed files with 9719 additions and 17729 deletions

View File

@ -17,7 +17,7 @@ then
echo "Signing apk..."
base64 --decode <<< "${ANDROID_KEYSTORE_B64}" > ks.jks
apksigner sign --ks ks.jks \
java -jar $(which apksigner) sign --ks ks.jks \
--ks-key-alias "${ANDROID_KEY_ALIAS}" \
--ks-pass env:ANDROID_KEYSTORE_PASS "artifacts/${REV_NAME}.apk"
fi

View File

@ -3,7 +3,7 @@
brew update
brew unlink python@2 || true
rm '/usr/local/bin/2to3' || true
brew install qt5 molten-vk glslang vulkan-loader p7zip ccache ninja || true
brew install qt5 p7zip ccache ninja || true
pip3 install macpack
export SDL_VER=2.0.16

View File

@ -12,37 +12,20 @@ cp build/bin/Release/citra "$REV_NAME"
cp -r build/bin/Release/citra-qt.app "$REV_NAME"
cp build/bin/Release/citra-room "$REV_NAME"
BUNDLE_PATH="$REV_NAME/citra-qt.app"
BUNDLE_CONTENTS_PATH="$BUNDLE_PATH/Contents"
BUNDLE_EXECUTABLE_PATH="$BUNDLE_CONTENTS_PATH/MacOS/citra-qt"
BUNDLE_LIB_PATH="$BUNDLE_CONTENTS_PATH/lib"
BUNDLE_RESOURCES_PATH="$BUNDLE_CONTENTS_PATH/Resources"
CITRA_STANDALONE_PATH="$REV_NAME/citra"
# move libs into folder for deployment
macpack $BUNDLE_EXECUTABLE_PATH -d "../Frameworks"
macpack "${REV_NAME}/citra-qt.app/Contents/MacOS/citra-qt" -d "../Frameworks"
# move qt frameworks into app bundle for deployment
$(brew --prefix)/opt/qt5/bin/macdeployqt $BUNDLE_PATH -executable=$BUNDLE_EXECUTABLE_PATH
$(brew --prefix)/opt/qt5/bin/macdeployqt "${REV_NAME}/citra-qt.app" -executable="${REV_NAME}/citra-qt.app/Contents/MacOS/citra-qt"
# move libs into folder for deployment
macpack $CITRA_STANDALONE_PATH -d "libs"
# bundle MoltenVK
VULKAN_LOADER_PATH=$(brew --prefix vulkan-loader)
MOLTENVK_PATH=$(brew --prefix molten-vk)
mkdir $BUNDLE_LIB_PATH
cp $VULKAN_LOADER_PATH/lib/libvulkan.dylib $BUNDLE_LIB_PATH
cp $MOLTENVK_PATH/lib/libMoltenVK.dylib $BUNDLE_LIB_PATH
cp -r $MOLTENVK_PATH/share/vulkan $BUNDLE_RESOURCES_PATH
install_name_tool -add_rpath "@loader_path/../lib/" $BUNDLE_EXECUTABLE_PATH
macpack "${REV_NAME}/citra" -d "libs"
# workaround for libc++
install_name_tool -change @loader_path/../Frameworks/libc++.1.0.dylib /usr/lib/libc++.1.dylib $BUNDLE_EXECUTABLE_PATH
install_name_tool -change @loader_path/libs/libc++.1.0.dylib /usr/lib/libc++.1.dylib $CITRA_STANDALONE_PATH
install_name_tool -change @loader_path/../Frameworks/libc++.1.0.dylib /usr/lib/libc++.1.dylib "${REV_NAME}/citra-qt.app/Contents/MacOS/citra-qt"
install_name_tool -change @loader_path/libs/libc++.1.0.dylib /usr/lib/libc++.1.dylib "${REV_NAME}/citra"
# Make the launching script executable
chmod +x $BUNDLE_EXECUTABLE_PATH
chmod +x ${REV_NAME}/citra-qt.app/Contents/MacOS/citra-qt
# Verify loader instructions
find "$REV_NAME" -type f -exec otool -L {} \;

View File

@ -1,18 +1,7 @@
#!/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 \
-DCITRA_USE_BUNDLED_QT=1 \
-DENABLE_QT_TRANSLATION=OFF \
-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
cmake .. -DCMAKE_BUILD_TYPE=Release -G Ninja -DCMAKE_TOOLCHAIN_FILE="$(pwd)/../CMakeModules/MSVCCache.cmake" -DCITRA_USE_CCACHE=ON -DCITRA_USE_BUNDLED_QT=1 -DCITRA_USE_BUNDLED_SDL2=1 -DCITRA_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DUSE_DISCORD_PRESENCE=ON -DENABLE_MF=ON -DENABLE_FFMPEG_VIDEO_DUMPER=ON
ninja
# show the caching efficiency

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 ( $GIT_TAG_NAME ) {
$RELEASE_NAME = ${GIT_TAG_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"

View File

@ -95,13 +95,6 @@ jobs:
env:
MACOSX_DEPLOYMENT_TARGET: "10.13"
ENABLE_COMPATIBILITY_REPORTING: "ON"
- name: Pack
run: ./.ci/macos/upload.sh
- name: Upload
uses: actions/upload-artifact@v3
with:
name: macos
path: artifacts/
windows:
runs-on: windows-latest
steps:
@ -115,34 +108,16 @@ jobs:
key: ${{ runner.os }}-win-${{ github.sha }}
restore-keys: |
${{ runner.os }}-win-
- name: Query tag name
uses: little-core-labs/get-git-tag@v3.0.2
id: tagName
- name: Install dependencies
run: ./.ci/windows-msvc/deps.sh
shell: bash
- name: Set up MSVC
uses: ilammy/msvc-dev-cmd@v1
- 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: Build
run: ./.ci/windows-msvc/build.sh
shell: bash
env:
ENABLE_COMPATIBILITY_REPORTING: "ON"
- name: Pack
run: ./.ci/windows-msvc/upload.ps1
- name: Upload
uses: actions/upload-artifact@v3
with:
name: msvc
path: artifacts/
android:
runs-on: ubuntu-latest
steps:
@ -165,7 +140,7 @@ jobs:
- name: Deps
run: |
sudo apt-get update
sudo apt-get install glslang-tools ccache apksigner -y
sudo apt-get install ccache apksigner -y
- name: Build
run: ./.ci/android/build.sh
- name: Copy and sign artifacts
@ -193,7 +168,7 @@ jobs:
TRANSIFEX_API_TOKEN: ${{ secrets.TRANSIFEX_API_TOKEN }}
release:
runs-on: ubuntu-latest
needs: [build, android, macos, source, windows]
needs: [build, android, macos, source]
if: ${{ startsWith(github.ref, 'refs/tags/') }}
steps:
- uses: actions/download-artifact@v3

3
.gitmodules vendored
View File

@ -67,6 +67,3 @@
[submodule "glm"]
path = externals/glm
url = https://github.com/g-truc/glm
[submodule "sirit"]
path = externals/sirit
url = https://github.com/GPUCode/sirit

View File

@ -1,5 +1,5 @@
# CMake 3.12 required for 20 to be a valid value for CXX_STANDARD
cmake_minimum_required(VERSION 3.15)
cmake_minimum_required(VERSION 3.14)
# Don't override the warning flags in MSVC:
cmake_policy(SET CMP0092 NEW)
@ -43,8 +43,6 @@ CMAKE_DEPENDENT_OPTION(CITRA_USE_BUNDLED_FFMPEG "Download bundled FFmpeg binarie
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(COMPILE_WITH_DWARF "Add DWARF debugging information" ON "MINGW" OFF)
@ -53,23 +51,6 @@ option(USE_SYSTEM_BOOST "Use the system Boost libs (instead of the bundled ones)
CMAKE_DEPENDENT_OPTION(ENABLE_FDK "Use FDK AAC decoder" OFF "NOT ENABLE_FFMPEG_AUDIO_DECODER;NOT ENABLE_MF" OFF)
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()
if (CITRA_USE_PRECOMPILED_HEADERS)
message(STATUS "Using Precompiled Headers.")
set(CMAKE_PCH_INSTANTIATE_TEMPLATES ON)
endif()
if(NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/hooks/pre-commit)
message(STATUS "Copying pre-commit hook")
file(COPY hooks/pre-commit
@ -177,8 +158,6 @@ message(STATUS "Target architecture: ${ARCHITECTURE}")
# Configure C++ standard
# ===========================
# boost asio's concept usage doesn't play nicely with some compilers yet.
add_definitions(-DBOOST_ASIO_DISABLE_CONCEPTS)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
@ -195,8 +174,8 @@ find_package(Threads REQUIRED)
if (ENABLE_QT)
if (CITRA_USE_BUNDLED_QT)
if (MSVC_VERSION GREATER_EQUAL 1920 AND ARCHITECTURE_x86_64)
set(QT_VER qt-5.15.7-msvc2019_64)
if (MSVC_VERSION GREATER_EQUAL 1930 AND ARCHITECTURE_x86_64)
set(QT_VER qt-5.15.5-msvc2022_64)
else()
message(FATAL_ERROR "No bundled Qt binaries for your toolchain. Disable CITRA_USE_BUNDLED_QT and provide your own.")
endif()
@ -316,15 +295,13 @@ if (CLANG_FORMAT)
set(SRCS ${PROJECT_SOURCE_DIR}/src)
set(CCOMMENT "Running clang format against all the .h and .cpp files in src/")
if (WIN32)
if(MINGW)
add_custom_target(clang-format
COMMAND find `cygpath -u ${SRCS}` -iname *.h -o -iname *.cpp -o -iname *.mm | xargs `cygpath -u ${CLANG_FORMAT}` -i
COMMENT ${CCOMMENT})
else()
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()
add_custom_target(clang-format
COMMAND powershell.exe -Command "Get-ChildItem '${SRCS}/*' -Include *.cpp,*.h,*.mm -Recurse | Foreach {&'${CLANG_FORMAT}' -i $_.fullname}"
COMMENT ${CCOMMENT})
elseif(MINGW)
add_custom_target(clang-format
COMMAND find `cygpath -u ${SRCS}` -iname *.h -o -iname *.cpp -o -iname *.mm | xargs `cygpath -u ${CLANG_FORMAT}` -i
COMMENT ${CCOMMENT})
else()
add_custom_target(clang-format
COMMAND find ${SRCS} -iname *.h -o -iname *.cpp -o -iname *.mm | xargs ${CLANG_FORMAT} -i

View File

@ -67,9 +67,6 @@ set(ENABLE_SPVREMAPPER OFF)
set(ENABLE_CTEST OFF)
add_subdirectory(glslang)
# Sirit
add_subdirectory(sirit)
# glm
add_subdirectory(glm)

View File

@ -22,7 +22,7 @@ function(windows_copy_files TARGET SOURCE_DIR DEST_DIR)
# 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 if not exist ${DEST_DIR} mkdir ${DEST_DIR} 2> nul
COMMAND robocopy ${SOURCE_DIR} ${DEST_DIR} ${ARGN} /NJH /NJS /NDL /NFL /NC /NS /NP || cmd /c "exit /b 0"
)
endfunction()
endfunction()

View File

@ -834,7 +834,7 @@ struct MicroProfile
inline int MicroProfileLogType(MicroProfileLogEntry Index)
{
return (int)(((MP_LOG_BEGIN_MASK & Index)>>62) & 0x3ULL);
return ((MP_LOG_BEGIN_MASK & Index)>>62) & 0x3;
}
inline uint64_t MicroProfileLogTimerIndex(MicroProfileLogEntry Index)
@ -881,12 +881,12 @@ T MicroProfileMax(T a, T b)
inline int64_t MicroProfileMsToTick(float fMs, int64_t nTicksPerSecond)
{
return (int64_t)(fMs*0.001f*(float)nTicksPerSecond);
return (int64_t)(fMs*0.001f*nTicksPerSecond);
}
inline float MicroProfileTickToMsMultiplier(int64_t nTicksPerSecond)
{
return 1000.f / (float)nTicksPerSecond;
return 1000.f / nTicksPerSecond;
}
inline uint16_t MicroProfileGetGroupIndex(MicroProfileToken t)
@ -902,10 +902,8 @@ inline uint16_t MicroProfileGetGroupIndex(MicroProfileToken t)
#include <windows.h>
#define snprintf _snprintf
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4244)
#endif
int64_t MicroProfileTicksPerSecondCpu()
{
static int64_t nTicksPerSecond = 0;
@ -931,14 +929,14 @@ typedef void* (*MicroProfileThreadFunc)(void*);
#ifndef _WIN32
typedef pthread_t MicroProfileThread;
inline void MicroProfileThreadStart(MicroProfileThread* pThread, MicroProfileThreadFunc Func)
void MicroProfileThreadStart(MicroProfileThread* pThread, MicroProfileThreadFunc Func)
{
pthread_attr_t Attr;
int r = pthread_attr_init(&Attr);
MP_ASSERT(r == 0);
pthread_create(pThread, &Attr, Func, 0);
}
inline void MicroProfileThreadJoin(MicroProfileThread* pThread)
void MicroProfileThreadJoin(MicroProfileThread* pThread)
{
int r = pthread_join(*pThread, 0);
MP_ASSERT(r == 0);
@ -955,11 +953,11 @@ DWORD _stdcall ThreadTrampoline(void* pFunc)
return static_cast<DWORD>(reinterpret_cast<uint64_t>(F(0)));
}
inline void MicroProfileThreadStart(MicroProfileThread* pThread, MicroProfileThreadFunc Func)
void MicroProfileThreadStart(MicroProfileThread* pThread, MicroProfileThreadFunc Func)
{
*pThread = CreateThread(0, 0, ThreadTrampoline, Func, 0, 0);
}
inline void MicroProfileThreadJoin(MicroProfileThread* pThread)
void MicroProfileThreadJoin(MicroProfileThread* pThread)
{
WaitForSingleObject(*pThread, INFINITE);
CloseHandle(*pThread);
@ -1156,7 +1154,7 @@ inline void MicroProfileSetThreadLog(MicroProfileThreadLog* pLog)
pthread_setspecific(g_MicroProfileThreadLogKey, pLog);
}
#else
inline MicroProfileThreadLog* MicroProfileGetThreadLog()
MicroProfileThreadLog* MicroProfileGetThreadLog()
{
return g_MicroProfileThreadLog;
}
@ -1272,7 +1270,7 @@ MicroProfileToken MicroProfileFindToken(const char* pGroup, const char* pName)
return MICROPROFILE_INVALID_TOKEN;
}
inline uint16_t MicroProfileGetGroup(const char* pGroup, MicroProfileTokenType Type)
uint16_t MicroProfileGetGroup(const char* pGroup, MicroProfileTokenType Type)
{
for(uint32_t i = 0; i < S.nGroupCount; ++i)
{
@ -1301,7 +1299,7 @@ inline uint16_t MicroProfileGetGroup(const char* pGroup, MicroProfileTokenType T
return nGroupIndex;
}
inline void MicroProfileRegisterGroup(const char* pGroup, const char* pCategory, uint32_t nColor)
void MicroProfileRegisterGroup(const char* pGroup, const char* pCategory, uint32_t nColor)
{
int nCategoryIndex = -1;
for(uint32_t i = 0; i < S.nCategoryCount; ++i)
@ -1467,7 +1465,7 @@ void MicroProfileGpuLeave(MicroProfileToken nToken_, uint64_t nTickStart)
}
}
inline void MicroProfileContextSwitchPut(MicroProfileContextSwitch* pContextSwitch)
void MicroProfileContextSwitchPut(MicroProfileContextSwitch* pContextSwitch)
{
if(S.nRunning || pContextSwitch->nTicks <= S.nPauseTicks)
{
@ -1748,10 +1746,10 @@ void MicroProfileFlip()
}
}
}
for(uint32_t j = 0; j < MICROPROFILE_MAX_GROUPS; ++j)
for(uint32_t i = 0; i < MICROPROFILE_MAX_GROUPS; ++i)
{
pLog->nGroupTicks[j] += nGroupTicks[j];
pFrameGroup[j] += nGroupTicks[j];
pLog->nGroupTicks[i] += nGroupTicks[i];
pFrameGroup[i] += nGroupTicks[i];
}
pLog->nStackPos = nStackPos;
}
@ -1919,7 +1917,7 @@ void MicroProfileSetEnableAllGroups(bool bEnableAllGroups)
S.nAllGroupsWanted = bEnableAllGroups ? 1 : 0;
}
inline void MicroProfileEnableCategory(const char* pCategory, bool bEnabled)
void MicroProfileEnableCategory(const char* pCategory, bool bEnabled)
{
int nCategoryIndex = -1;
for(uint32_t i = 0; i < S.nCategoryCount; ++i)
@ -2029,7 +2027,7 @@ void MicroProfileForceDisableGroup(const char* pGroup, MicroProfileTokenType Typ
}
inline void MicroProfileCalcAllTimers(float* pTimers, float* pAverage, float* pMax, float* pCallAverage, float* pExclusive, float* pAverageExclusive, float* pMaxExclusive, float* pTotal, uint32_t nSize)
void MicroProfileCalcAllTimers(float* pTimers, float* pAverage, float* pMax, float* pCallAverage, float* pExclusive, float* pAverageExclusive, float* pMaxExclusive, float* pTotal, uint32_t nSize)
{
for(uint32_t i = 0; i < S.nTotalTimers && i < nSize; ++i)
{
@ -3334,7 +3332,7 @@ bool MicroProfileIsLocalThread(uint32_t nThreadId)
#endif
#else
bool MicroProfileIsLocalThread([[maybe_unused]] uint32_t nThreadId) { return false; }
bool MicroProfileIsLocalThread(uint32_t nThreadId){return false;}
void MicroProfileStopContextSwitchTrace(){}
void MicroProfileStartContextSwitchTrace(){}
@ -3582,7 +3580,7 @@ int MicroProfileGetGpuTickReference(int64_t* pOutCpu, int64_t* pOutGpu)
#undef S
#ifdef _MSC_VER
#ifdef _WIN32
#pragma warning(pop)
#endif

1
externals/sirit vendored

Submodule externals/sirit deleted from f0b6bbe55b

View File

@ -46,21 +46,11 @@ if (MSVC)
# Warnings
/W3
/we4062 # enumerator 'identifier' in a switch of enum 'enumeration' is not handled
/we4101 # 'identifier': unreferenced local variable
/we4265 # 'class': class has virtual functions, but destructor is not virtual
/we4267 # 'var': conversion from 'size_t' to 'type', possible loss of data
/we4388 # signed/unsigned mismatch
/we4547 # 'operator' : operator before comma has no effect; expected operator with side-effect
/we4549 # 'operator1': operator before comma has no effect; did you intend 'operator2'?
/we4555 # Expression has no effect; expected expression with side-effect
/we4834 # Discarding return value of function with 'nodiscard' attribute
/we5038 # data member 'member1' will be initialized after data member 'member2'
)
else()
add_compile_options(
/MP
/Zo
/permissive-
/EHsc
/volatile:iso
@ -74,26 +64,17 @@ if (MSVC)
# Warnings
/W3
/we4062 # enumerator 'identifier' in a switch of enum 'enumeration' is not handled
/we4101 # 'identifier': unreferenced local variable
/we4265 # 'class': class has virtual functions, but destructor is not virtual
/we4267 # 'var': conversion from 'size_t' to 'type', possible loss of data
/we4388 # signed/unsigned mismatch
/we4547 # 'operator' : operator before comma has no effect; expected operator with side-effect
/we4549 # 'operator1': operator before comma has no effect; did you intend 'operator2'?
/we4555 # Expression has no effect; expected expression with side-effect
/we4834 # Discarding return value of function with 'nodiscard' attribute
/we5038 # data member 'member1' will be initialized after data member 'member2'
)
endif()
# 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
add_compile_options(/Z7)
else()
add_compile_options(/Zi)
if (NOT CITRA_USE_CCACHE)
add_compile_options(
/Zi
/Zo
)
endif()
# /GS- - No stack buffer overflow checks

View File

@ -30,8 +30,7 @@
android:supportsRtl="true"
android:isGame="true"
android:banner="@mipmap/ic_launcher"
android:requestLegacyExternalStorage="true"
android:debuggable="true">
android:requestLegacyExternalStorage="true">
<activity
android:name="org.citra.citra_emu.ui.main.MainActivity"

View File

@ -192,15 +192,11 @@ public final class SettingsFragmentPresenter {
Setting language = systemSection.getSetting(SettingsFile.KEY_LANGUAGE);
Setting systemClock = systemSection.getSetting(SettingsFile.KEY_INIT_CLOCK);
Setting dateTime = systemSection.getSetting(SettingsFile.KEY_INIT_TIME);
Setting pluginLoader = systemSection.getSetting(SettingsFile.KEY_PLUGIN_LOADER);
Setting allowPluginLoader = systemSection.getSetting(SettingsFile.KEY_ALLOW_PLUGIN_LOADER);
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 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 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));
}
private void addCameraSettings(ArrayList<SettingsItem> sl) {

View File

@ -78,8 +78,6 @@ public final class SettingsFile {
public static final String KEY_IS_NEW_3DS = "is_new_3ds";
public static final String KEY_REGION_VALUE = "region_value";
public static final String KEY_LANGUAGE = "language";
public static final String KEY_PLUGIN_LOADER = "plugin_loader";
public static final String KEY_ALLOW_PLUGIN_LOADER = "allow_plugin_loader";
public static final String KEY_INIT_CLOCK = "init_clock";
public static final String KEY_INIT_TIME = "init_time";

View File

@ -8,7 +8,7 @@ import org.citra.citra_emu.CitraApplication;
public class EmulationMenuSettings {
private static SharedPreferences mPreferences = PreferenceManager.getDefaultSharedPreferences(CitraApplication.getAppContext());
// These must match what is defined in src/common/settings.h
// These must match what is defined in src/core/settings.h
public static final int LayoutOption_Default = 0;
public static final int LayoutOption_SingleScreen = 1;
public static final int LayoutOption_LargeScreen = 2;

View File

@ -19,8 +19,6 @@ add_library(citra-android SHARED
default_ini.h
emu_window/emu_window.cpp
emu_window/emu_window.h
emu_window/emu_window_vk.cpp
emu_window/emu_window_vk.h
game_info.cpp
game_info.h
game_settings.cpp

View File

@ -11,10 +11,10 @@
#include "common/file_util.h"
#include "common/logging/log.h"
#include "common/param_package.h"
#include "common/settings.h"
#include "core/core.h"
#include "core/hle/service/cfg/cfg.h"
#include "core/hle/service/service.h"
#include "core/settings.h"
#include "input_common/main.h"
#include "input_common/udp/client.h"
#include "jni/camera/ndk_camera.h"
@ -25,7 +25,7 @@
Config::Config() {
// TODO: Don't hardcode the path; let the frontend decide where to put the config files.
sdl2_config_loc = FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir) + "config.ini";
sdl2_config_loc = Common::FS::GetUserPath(Common::FS::UserPath::ConfigDir) + "config.ini";
sdl2_config = std::make_unique<INIReader>(sdl2_config_loc);
Reload();
@ -38,8 +38,8 @@ bool Config::LoadINI(const std::string& default_contents, bool retry) {
if (sdl2_config->ParseError() < 0) {
if (retry) {
LOG_WARNING(Config, "Failed to load {}. Creating file from defaults...", location);
FileUtil::CreateFullPath(location);
FileUtil::WriteStringToFile(true, location, default_contents);
Common::FS::CreateFullPath(location);
Common::FS::WriteStringToFile(true, location, default_contents);
sdl2_config = std::make_unique<INIReader>(location); // Reopen file
return LoadINI(default_contents, false);
@ -114,13 +114,7 @@ void Config::ReadValues() {
sdl2_config->GetString("Premium", "texture_filter_name", "none");
// Renderer
Settings::values.graphics_api =
static_cast<Settings::GraphicsAPI>(sdl2_config->GetInteger("Renderer", "graphics_api", 2));
Settings::values.async_command_recording =
sdl2_config->GetBoolean("Renderer", "async_command_recording", true);
Settings::values.spirv_shader_gen =
sdl2_config->GetBoolean("Renderer", "spirv_shader_gen", true);
Settings::values.renderer_debug = sdl2_config->GetBoolean("Renderer", "renderer_debug", false);
Settings::values.use_gles = sdl2_config->GetBoolean("Renderer", "use_gles", true);
Settings::values.use_hw_renderer = sdl2_config->GetBoolean("Renderer", "use_hw_renderer", true);
Settings::values.use_hw_shader = sdl2_config->GetBoolean("Renderer", "use_hw_shader", true);
Settings::values.shaders_accurate_mul =
@ -145,9 +139,9 @@ void Config::ReadValues() {
Settings::values.factor_3d =
static_cast<u8>(sdl2_config->GetInteger("Renderer", "factor_3d", 0));
std::string default_shader = "none (builtin)";
if (Settings::values.render_3d.GetValue() == Settings::StereoRenderOption::Anaglyph)
if (Settings::values.render_3d == Settings::StereoRenderOption::Anaglyph)
default_shader = "dubois (builtin)";
else if (Settings::values.render_3d.GetValue() == Settings::StereoRenderOption::Interlaced)
else if (Settings::values.render_3d == Settings::StereoRenderOption::Interlaced)
default_shader = "horizontal (builtin)";
Settings::values.pp_shader_name =
sdl2_config->GetString("Renderer", "pp_shader_name", default_shader);
@ -192,9 +186,9 @@ void Config::ReadValues() {
sdl2_config->GetBoolean("Utility", "preload_textures", false);
// Audio
Settings::values.audio_emulation =
static_cast<Settings::AudioEmulation>(sdl2_config->GetInteger(
"Audio", "audio_emulation", static_cast<int>(Settings::AudioEmulation::HLE)));
Settings::values.enable_dsp_lle = sdl2_config->GetBoolean("Audio", "enable_dsp_lle", false);
Settings::values.enable_dsp_lle_multithread =
sdl2_config->GetBoolean("Audio", "enable_dsp_lle_multithread", false);
Settings::values.sink_id = sdl2_config->GetString("Audio", "output_engine", "auto");
Settings::values.enable_audio_stretching =
sdl2_config->GetBoolean("Audio", "enable_audio_stretching", true);
@ -235,10 +229,6 @@ void Config::ReadValues() {
std::chrono::system_clock::from_time_t(std::mktime(&t)).time_since_epoch())
.count();
}
Settings::values.plugin_loader_enabled =
sdl2_config->GetBoolean("System", "plugin_loader", false);
Settings::values.allow_plugin_loader =
sdl2_config->GetBoolean("System", "allow_plugin_loader", true);
// Camera
using namespace Service::CAM;

View File

@ -281,11 +281,6 @@ init_clock =
# Note: 3DS can only handle times later then Jan 1 2000
init_time =
# Plugin loader state, if enabled plugins will be loaded from the SD card.
# You can also set if homebrew apps are allowed to enable the plugin loader
plugin_loader =
allow_plugin_loader =
[Camera]
# Which camera engine to use for the right outer camera
# blank: a dummy camera that always returns black image

View File

@ -11,7 +11,7 @@
#include <glad/glad.h>
#include "common/logging/log.h"
#include "common/settings.h"
#include "core/settings.h"
#include "input_common/main.h"
#include "jni/emu_window/emu_window.h"
#include "jni/id_cache.h"

View File

@ -1,176 +0,0 @@
// Copyright 2019 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <algorithm>
#include <array>
#include <cstdlib>
#include <string>
#include <android/native_window_jni.h>
#include "common/logging/log.h"
#include "common/settings.h"
#include "input_common/main.h"
#include "jni/emu_window/emu_window_vk.h"
#include "jni/id_cache.h"
#include "jni/input_manager.h"
#include "network/network.h"
#include "video_core/renderer_base.h"
#include "video_core/video_core.h"
static bool IsPortraitMode() {
return JNI_FALSE != IDCache::GetEnvForThread()->CallStaticBooleanMethod(
IDCache::GetNativeLibraryClass(), IDCache::GetIsPortraitMode());
}
static void UpdateLandscapeScreenLayout() {
Settings::values.layout_option =
static_cast<Settings::LayoutOption>(IDCache::GetEnvForThread()->CallStaticIntMethod(
IDCache::GetNativeLibraryClass(), IDCache::GetLandscapeScreenLayout()));
}
void EmuWindow_Android_Vulkan::OnSurfaceChanged(ANativeWindow* surface) {
render_window = surface;
StopPresenting();
}
bool EmuWindow_Android_Vulkan::OnTouchEvent(int x, int y, bool pressed) {
if (pressed) {
return TouchPressed((unsigned)std::max(x, 0), (unsigned)std::max(y, 0));
}
TouchReleased();
return true;
}
void EmuWindow_Android_Vulkan::OnTouchMoved(int x, int y) {
TouchMoved((unsigned)std::max(x, 0), (unsigned)std::max(y, 0));
}
void EmuWindow_Android_Vulkan::OnFramebufferSizeChanged() {
UpdateLandscapeScreenLayout();
const bool is_portrait_mode{IsPortraitMode()};
const int bigger{window_width > window_height ? window_width : window_height};
const int smaller{window_width < window_height ? window_width : window_height};
if (is_portrait_mode) {
UpdateCurrentFramebufferLayout(smaller, bigger, is_portrait_mode);
} else {
UpdateCurrentFramebufferLayout(bigger, smaller, is_portrait_mode);
}
}
EmuWindow_Android_Vulkan::EmuWindow_Android_Vulkan(ANativeWindow* surface) {
LOG_DEBUG(Frontend, "Initializing EmuWindow_Android_Vulkan");
if (!surface) {
LOG_CRITICAL(Frontend, "surface is nullptr");
return;
}
Network::Init();
host_window = surface;
CreateWindowSurface();
if (core_context = CreateSharedContext(); !core_context) {
LOG_CRITICAL(Frontend, "CreateSharedContext() failed");
return;
}
OnFramebufferSizeChanged();
}
bool EmuWindow_Android_Vulkan::CreateWindowSurface() {
if (!host_window) {
return true;
}
window_info.type = Frontend::WindowSystemType::Android;
window_info.render_surface = host_window;
return true;
}
void EmuWindow_Android_Vulkan::DestroyWindowSurface() {
/*if (!egl_surface) {
return;
}
if (eglGetCurrentSurface(EGL_DRAW) == egl_surface) {
eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
}
if (!eglDestroySurface(egl_display, egl_surface)) {
LOG_CRITICAL(Frontend, "eglDestroySurface() failed");
}
egl_surface = EGL_NO_SURFACE;*/
}
void EmuWindow_Android_Vulkan::DestroyContext() {
/*if (!egl_context) {
return;
}
if (eglGetCurrentContext() == egl_context) {
eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
}
if (!eglDestroyContext(egl_display, egl_context)) {
LOG_CRITICAL(Frontend, "eglDestroySurface() failed");
}
if (!eglTerminate(egl_display)) {
LOG_CRITICAL(Frontend, "eglTerminate() failed");
}
egl_context = EGL_NO_CONTEXT;
egl_display = EGL_NO_DISPLAY;*/
}
EmuWindow_Android_Vulkan::~EmuWindow_Android_Vulkan() {
DestroyWindowSurface();
DestroyContext();
}
std::unique_ptr<Frontend::GraphicsContext> EmuWindow_Android_Vulkan::CreateSharedContext() const {
return std::make_unique<SharedContext_Android>();
}
void EmuWindow_Android_Vulkan::StopPresenting() {
/*if (presenting_state == PresentingState::Running) {
eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
}*/
presenting_state = PresentingState::Stopped;
}
void EmuWindow_Android_Vulkan::TryPresenting() {
if (presenting_state != PresentingState::Running) {
if (presenting_state == PresentingState::Initial) {
/*eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);*/
presenting_state = PresentingState::Running;
} else {
return;
}
}
/*eglSwapInterval(egl_display, Settings::values.use_vsync_new ? 1 : 0);
if (VideoCore::g_renderer) {
VideoCore::g_renderer->TryPresent(0);
eglSwapBuffers(egl_display, egl_surface);
}*/
}
void EmuWindow_Android_Vulkan::PollEvents() {
if (!render_window) {
return;
}
host_window = render_window;
render_window = nullptr;
DestroyWindowSurface();
CreateWindowSurface();
OnFramebufferSizeChanged();
presenting_state = PresentingState::Initial;
}
void EmuWindow_Android_Vulkan::MakeCurrent() {
core_context->MakeCurrent();
}
void EmuWindow_Android_Vulkan::DoneCurrent() {
core_context->DoneCurrent();
}

View File

@ -1,59 +0,0 @@
// Copyright 2022 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <vector>
#include "core/frontend/emu_window.h"
struct ANativeWindow;
class SharedContext_Android : public Frontend::GraphicsContext {};
class EmuWindow_Android_Vulkan : public Frontend::EmuWindow {
public:
EmuWindow_Android_Vulkan(ANativeWindow* surface);
~EmuWindow_Android_Vulkan();
void Present();
/// Called by the onSurfaceChanges() method to change the surface
void OnSurfaceChanged(ANativeWindow* surface);
/// Handles touch event that occur.(Touched or released)
bool OnTouchEvent(int x, int y, bool pressed);
/// Handles movement of touch pointer
void OnTouchMoved(int x, int y);
void PollEvents() override;
void MakeCurrent() override;
void DoneCurrent() override;
void TryPresenting();
void StopPresenting();
std::unique_ptr<GraphicsContext> CreateSharedContext() const override;
private:
void OnFramebufferSizeChanged();
bool CreateWindowSurface();
void DestroyWindowSurface();
void DestroyContext();
ANativeWindow* render_window{};
ANativeWindow* host_window{};
int window_width{1080};
int window_height{2220};
std::unique_ptr<Frontend::GraphicsContext> core_context;
enum class PresentingState {
Initial,
Running,
Stopped,
};
PresentingState presenting_state{};
};

View File

@ -35,7 +35,7 @@ std::vector<u8> GetSMDHData(std::string physical_name) {
std::string update_path = Service::AM::GetTitleContentPath(
Service::FS::MediaType::SDMC, program_id + 0x0000000E'00000000);
if (!FileUtil::Exists(update_path))
if (!Common::FS::Exists(update_path))
return original_smdh;
std::unique_ptr<Loader::AppLoader> update_loader = Loader::GetLoader(update_path);

View File

@ -2,7 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/settings.h"
#include "core/settings.h"
namespace GameSettings {

View File

@ -6,7 +6,7 @@
#include "common/logging/backend.h"
#include "common/logging/filter.h"
#include "common/logging/log.h"
#include "common/settings.h"
#include "core/settings.h"
#include "jni/applets/mii_selector.h"
#include "jni/applets/swkbd.h"
#include "jni/camera/still_image_camera.h"
@ -156,12 +156,12 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
// Initialize Logger
Log::Filter log_filter;
log_filter.ParseFilterString(Settings::values.log_filter.GetValue());
log_filter.ParseFilterString(Settings::values.log_filter);
Log::SetGlobalFilter(log_filter);
Log::AddBackend(std::make_unique<Log::LogcatBackend>());
FileUtil::CreateFullPath(FileUtil::GetUserPath(FileUtil::UserPath::LogDir));
Common::FS::CreateFullPath(Common::FS::GetUserPath(Common::FS::UserPath::LogDir));
Log::AddBackend(std::make_unique<Log::FileBackend>(
FileUtil::GetUserPath(FileUtil::UserPath::LogDir) + LOG_FILE));
Common::FS::GetUserPath(Common::FS::UserPath::LogDir) + LOG_FILE));
LOG_INFO(Frontend, "Logging backend initialised");
// Initialize misc classes

View File

@ -17,7 +17,6 @@
#include "common/microprofile.h"
#include "common/scm_rev.h"
#include "common/scope_exit.h"
#include "common/settings.h"
#include "common/string_util.h"
#include "core/core.h"
#include "core/frontend/applets/default_applets.h"
@ -26,13 +25,14 @@
#include "core/hle/service/am/am.h"
#include "core/hle/service/nfc/nfc.h"
#include "core/savestate.h"
#include "core/settings.h"
#include "jni/android_common/android_common.h"
#include "jni/applets/mii_selector.h"
#include "jni/applets/swkbd.h"
#include "jni/camera/ndk_camera.h"
#include "jni/camera/still_image_camera.h"
#include "jni/config.h"
#include "jni/emu_window/emu_window_vk.h"
#include "jni/emu_window/emu_window.h"
#include "jni/game_info.h"
#include "jni/game_settings.h"
#include "jni/id_cache.h"
@ -48,7 +48,7 @@ namespace {
ANativeWindow* s_surf;
std::unique_ptr<EmuWindow_Android_Vulkan> window;
std::unique_ptr<EmuWindow_Android> window;
std::atomic<bool> stop_run{true};
std::atomic<bool> pause_emulation{false};
@ -146,7 +146,7 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) {
return Core::System::ResultStatus::ErrorLoader;
}
window = std::make_unique<EmuWindow_Android_Vulkan>(s_surf);
window = std::make_unique<EmuWindow_Android>(s_surf);
Core::System& system{Core::System::GetInstance()};
@ -154,7 +154,7 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) {
Config{};
// Replace with game-specific settings
u64 program_id{};
FileUtil::SetCurrentRomPath(filepath);
Common::FS::SetCurrentRomPath(filepath);
auto app_loader = Loader::GetLoader(filepath);
if (app_loader) {
app_loader->ReadProgramId(program_id);
@ -237,7 +237,7 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) {
}
} else {
// Ensure no audio bleeds out while game is paused
const float volume = Settings::values.volume.GetValue();
const float volume = Settings::values.volume;
SCOPE_EXIT({ Settings::values.volume = volume; });
Settings::values.volume = 0;
@ -305,18 +305,18 @@ void Java_org_citra_citra_1emu_NativeLibrary_SwapScreens(JNIEnv* env, [[maybe_un
void Java_org_citra_citra_1emu_NativeLibrary_SetUserDirectory(JNIEnv* env,
[[maybe_unused]] jclass clazz,
jstring j_directory) {
FileUtil::SetCurrentDir(GetJString(env, j_directory));
Common::FS::SetCurrentDir(GetJString(env, j_directory));
}
jobjectArray Java_org_citra_citra_1emu_NativeLibrary_GetInstalledGamePaths(
JNIEnv* env, [[maybe_unused]] jclass clazz) {
std::vector<std::string> games;
const FileUtil::DirectoryEntryCallable ScanDir =
const Common::FS::DirectoryEntryCallable ScanDir =
[&games, &ScanDir](u64*, const std::string& directory, const std::string& virtual_name) {
std::string path = directory + virtual_name;
if (FileUtil::IsDirectory(path)) {
if (Common::FS::IsDirectory(path)) {
path += '/';
FileUtil::ForeachDirectoryEntry(nullptr, path, ScanDir);
Common::FS::ForeachDirectoryEntry(nullptr, path, ScanDir);
} else {
auto loader = Loader::GetLoader(path);
if (loader) {
@ -330,12 +330,12 @@ jobjectArray Java_org_citra_citra_1emu_NativeLibrary_GetInstalledGamePaths(
return true;
};
ScanDir(nullptr, "",
FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir) +
Common::FS::GetUserPath(Common::FS::UserPath::SDMCDir) +
"Nintendo "
"3DS/00000000000000000000000000000000/"
"00000000000000000000000000000000/title/00040000");
ScanDir(nullptr, "",
FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) +
Common::FS::GetUserPath(Common::FS::UserPath::NANDDir) +
"00000000000000000000000000000000/title/00040010");
jobjectArray jgames = env->NewObjectArray(static_cast<jsize>(games.size()),
env->FindClass("java/lang/String"), nullptr);

View File

@ -37,10 +37,6 @@
<string name="init_time_description">Si el \"Tipo del reloj del sistema\" está en \"Reloj emulado\", ésto cambia la fecha y hora de inicio.</string>
<string name="emulated_region">Región emulada</string>
<string name="emulated_language">Idioma emulado</string>
<string name="plugin_loader">Activar \"3GX Plugin Loader\"</string>
<string name="plugin_loader_description">Carga \"3GX plugins\" de la SD emulada si están disponibles.</string>
<string name="allow_plugin_loader">Permiter que apps cambien el estado del \"plugin loader\"</string>
<string name="allow_plugin_loader_description">Permite a las aplicaciones homebrew activar el \"plugin loader\" incluso si está desactivado.</string>
<!-- Camera settings strings -->
<string name="inner_camera">Cámara interior</string>

View File

@ -51,10 +51,6 @@
<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>
<!-- Camera settings strings -->
<string name="inner_camera">Inner Camera</string>

View File

@ -7,7 +7,7 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.3.1'
classpath 'com.android.tools.build:gradle:7.2.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files

View File

@ -23,7 +23,6 @@ add_library(audio_core STATIC
interpolate.cpp
interpolate.h
null_sink.h
precompiled_headers.h
sink.h
sink_details.cpp
sink_details.h
@ -90,7 +89,3 @@ if(ENABLE_CUBEB)
target_link_libraries(audio_core PRIVATE cubeb)
target_compile_definitions(audio_core PUBLIC HAVE_CUBEB)
endif()
if (CITRA_USE_PRECOMPILED_HEADERS)
target_precompile_headers(audio_core PRIVATE precompiled_headers.h)
endif()

View File

@ -7,18 +7,17 @@
#include "audio_core/sink.h"
#include "audio_core/sink_details.h"
#include "common/assert.h"
#include "common/settings.h"
#include "core/core.h"
#include "core/dumping/backend.h"
#include "core/settings.h"
namespace AudioCore {
DspInterface::DspInterface() = default;
DspInterface::~DspInterface() = default;
void DspInterface::SetSink(std::string_view sink_id, std::string_view audio_device) {
sink = CreateSinkFromID(Settings::values.sink_id.GetValue(),
Settings::values.audio_device_id.GetValue());
void DspInterface::SetSink(const std::string& sink_id, const std::string& audio_device) {
sink = CreateSinkFromID(Settings::values.sink_id, Settings::values.audio_device_id);
sink->SetCallback(
[this](s16* buffer, std::size_t num_frames) { OutputCallback(buffer, num_frames); });
time_stretcher.SetOutputSampleRate(sink->GetNativeSampleRate());
@ -87,7 +86,7 @@ void DspInterface::OutputCallback(s16* buffer, std::size_t num_frames) {
// Implementation of the hardware volume slider
// A cubic curve is used to approximate a linear change in human-perceived loudness
const float linear_volume = std::clamp(Settings::Volume(), 0.0f, 1.0f);
const float linear_volume = std::clamp(Settings::values.volume, 0.0f, 1.0f);
if (linear_volume != 1.0) {
const float volume_scale_factor = linear_volume * linear_volume * linear_volume;
for (std::size_t i = 0; i < num_frames; i++) {

View File

@ -94,7 +94,7 @@ public:
virtual void UnloadComponent() = 0;
/// Select the sink to use based on sink id.
void SetSink(std::string_view sink_id, std::string_view audio_device);
void SetSink(const std::string& sink_id, const std::string& audio_device);
/// Get the current sink
Sink& GetSink();
/// Enable/Disable audio stretching.

View File

@ -43,8 +43,8 @@ FuncDL<int(AVCodecParserContext*, AVCodecContext*, uint8_t**, int*, const uint8_
FuncDL<void(AVCodecParserContext*)> av_parser_close_dl;
bool InitFFmpegDL() {
std::string dll_path = FileUtil::GetUserPath(FileUtil::UserPath::DLLDir);
FileUtil::CreateDir(dll_path);
std::string dll_path = Common::FS::GetUserPath(Common::FS::UserPath::DLLDir);
Common::FS::CreateDir(dll_path);
std::wstring w_dll_path = Common::UTF8ToUTF16W(dll_path);
SetDllDirectoryW(w_dll_path.c_str());

View File

@ -1,7 +0,0 @@
// Copyright 2022 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "common/common_precompiled_headers.h"

View File

@ -10,7 +10,6 @@ add_executable(citra
emu_window/emu_window_sdl2.h
lodepng_image_interface.cpp
lodepng_image_interface.h
precompiled_headers.h
resource.h
)
@ -31,7 +30,3 @@ if (MSVC)
include(CopyCitraSDLDeps)
copy_citra_SDL_deps(citra)
endif()
if (CITRA_USE_PRECOMPILED_HEADERS)
target_precompile_headers(citra PRIVATE precompiled_headers.h)
endif()

View File

@ -19,7 +19,6 @@
#include "common/microprofile.h"
#include "common/scm_rev.h"
#include "common/scope_exit.h"
#include "common/settings.h"
#include "common/string_util.h"
#include "core/core.h"
#include "core/dumping/backend.h"
@ -28,7 +27,7 @@
#include "core/hle/service/am/am.h"
#include "core/hle/service/cfg/cfg.h"
#include "core/movie.h"
#include "input_common/main.h"
#include "core/settings.h"
#include "network/network.h"
#include "video_core/renderer_base.h"
@ -133,8 +132,7 @@ static void OnNetworkError(const Network::RoomMember::Error& error) {
LOG_ERROR(Network, "You have been banned by the host");
break;
default:
LOG_ERROR(Network, "Unknown network error: {}", error);
break;
LOG_ERROR(Network, "Unknown network error {}", error);
}
}
@ -167,13 +165,13 @@ static void OnStatusMessageReceived(const Network::StatusMessageEntry& msg) {
static void InitializeLogging() {
Log::Filter log_filter(Log::Level::Debug);
log_filter.ParseFilterString(Settings::values.log_filter.GetValue());
log_filter.ParseFilterString(Settings::values.log_filter);
Log::SetGlobalFilter(log_filter);
Log::AddBackend(std::make_unique<Log::ColorConsoleBackend>());
const std::string& log_dir = FileUtil::GetUserPath(FileUtil::UserPath::LogDir);
FileUtil::CreateFullPath(log_dir);
const std::string& log_dir = Common::FS::GetUserPath(Common::FS::UserPath::LogDir);
Common::FS::CreateFullPath(log_dir);
Log::AddBackend(std::make_unique<Log::FileBackend>(log_dir + LOG_FILE));
#ifdef _WIN32
Log::AddBackend(std::make_unique<Log::DebuggerBackend>());
@ -185,8 +183,8 @@ int main(int argc, char** argv) {
Common::DetachedTasks detached_tasks;
Config config;
int option_index = 0;
bool use_gdbstub = Settings::values.use_gdbstub.GetValue();
u32 gdb_port = static_cast<u32>(Settings::values.gdbstub_port.GetValue());
bool use_gdbstub = Settings::values.use_gdbstub;
u32 gdb_port = static_cast<u32>(Settings::values.gdbstub_port);
std::string movie_record;
std::string movie_record_author;
std::string movie_play;
@ -353,23 +351,11 @@ int main(int argc, char** argv) {
// Register generic image interface
Core::System::GetInstance().RegisterImageInterface(std::make_shared<LodePNGImageInterface>());
EmuWindow_SDL2::InitializeSDL2();
const auto emu_window{std::make_unique<EmuWindow_SDL2>(fullscreen, false)};
const bool use_secondary_window{Settings::values.layout_option.GetValue() ==
Settings::LayoutOption::SeparateWindows};
const auto secondary_window =
use_secondary_window ? std::make_unique<EmuWindow_SDL2>(false, true) : nullptr;
std::unique_ptr<EmuWindow_SDL2> emu_window{std::make_unique<EmuWindow_SDL2>(fullscreen)};
const auto scope = emu_window->Acquire();
LOG_INFO(Frontend, "Citra Version: {} | {}-{}", Common::g_build_fullname, Common::g_scm_branch,
Common::g_scm_desc);
Settings::LogSettings();
Core::System& system = Core::System::GetInstance();
const Core::System::ResultStatus load_result{
system.Load(*emu_window, filepath, secondary_window.get())};
const Core::System::ResultStatus load_result{system.Load(*emu_window, filepath)};
switch (load_result) {
case Core::System::ResultStatus::ErrorGetLoader:
@ -437,12 +423,7 @@ int main(int argc, char** argv) {
system.VideoDumper().StartDumping(dump_video, layout);
}
std::thread main_render_thread([&emu_window] { emu_window->Present(); });
std::thread secondary_render_thread([&secondary_window] {
if (secondary_window) {
secondary_window->Present();
}
});
std::thread render_thread([&emu_window] { emu_window->Present(); });
std::atomic_bool stop_run;
system.Renderer().Rasterizer()->LoadDiskResources(
@ -451,11 +432,7 @@ int main(int argc, char** argv) {
total);
});
const auto secondary_is_open = [&secondary_window] {
// if the secondary window isn't created, it shouldn't affect the main loop
return secondary_window ? secondary_window->IsOpen() : true;
};
while (emu_window->IsOpen() && secondary_is_open()) {
while (emu_window->IsOpen()) {
const auto result = system.RunLoop();
switch (result) {
@ -469,21 +446,13 @@ int main(int argc, char** argv) {
break;
}
}
emu_window->RequestClose();
if (secondary_window) {
secondary_window->RequestClose();
}
main_render_thread.join();
secondary_render_thread.join();
render_thread.join();
Core::Movie::GetInstance().Shutdown();
if (system.VideoDumper().IsDumping()) {
system.VideoDumper().StopDumping();
}
Network::Shutdown();
InputCommon::Shutdown();
system.Shutdown();
detached_tasks.WaitForAllTasks();

View File

@ -13,16 +13,16 @@
#include "common/file_util.h"
#include "common/logging/log.h"
#include "common/param_package.h"
#include "common/settings.h"
#include "core/frontend/mic.h"
#include "core/hle/service/service.h"
#include "core/settings.h"
#include "input_common/main.h"
#include "input_common/udp/client.h"
#include "network/network_settings.h"
Config::Config() {
// TODO: Don't hardcode the path; let the frontend decide where to put the config files.
sdl2_config_loc = FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir) + "sdl2-config.ini";
sdl2_config_loc = Common::FS::GetUserPath(Common::FS::UserPath::ConfigDir) + "sdl2-config.ini";
sdl2_config = std::make_unique<INIReader>(sdl2_config_loc);
Reload();
@ -35,8 +35,8 @@ bool Config::LoadINI(const std::string& default_contents, bool retry) {
if (sdl2_config->ParseError() < 0) {
if (retry) {
LOG_WARNING(Config, "Failed to load {}. Creating file from defaults...", location);
FileUtil::CreateFullPath(location);
FileUtil::WriteStringToFile(true, location, default_contents);
Common::FS::CreateFullPath(location);
Common::FS::WriteStringToFile(true, location, default_contents);
sdl2_config = std::make_unique<INIReader>(location); // Reopen file
return LoadINI(default_contents, false);
@ -129,23 +129,24 @@ void Config::ReadValues() {
sdl2_config->GetBoolean("Renderer", "use_disk_shader_cache", true);
Settings::values.frame_limit =
static_cast<u16>(sdl2_config->GetInteger("Renderer", "frame_limit", 100));
Settings::values.use_frame_limit_alternate =
sdl2_config->GetBoolean("Renderer", "use_frame_limit_alternate", false);
Settings::values.frame_limit_alternate =
static_cast<u16>(sdl2_config->GetInteger("Renderer", "frame_limit_alternate", 200));
Settings::values.use_vsync_new =
static_cast<u16>(sdl2_config->GetInteger("Renderer", "use_vsync_new", 1));
Settings::values.texture_filter_name =
sdl2_config->GetString("Renderer", "texture_filter_name", "none");
Settings::values.mono_render_option = static_cast<Settings::MonoRenderOption>(
sdl2_config->GetInteger("Renderer", "mono_render_option", 0));
Settings::values.render_3d = static_cast<Settings::StereoRenderOption>(
sdl2_config->GetInteger("Renderer", "render_3d", 0));
Settings::values.factor_3d =
static_cast<u8>(sdl2_config->GetInteger("Renderer", "factor_3d", 0));
std::string default_shader = "none (builtin)";
if (Settings::values.render_3d.GetValue() == Settings::StereoRenderOption::Anaglyph)
if (Settings::values.render_3d == Settings::StereoRenderOption::Anaglyph)
default_shader = "dubois (builtin)";
else if (Settings::values.render_3d.GetValue() == Settings::StereoRenderOption::Interlaced ||
Settings::values.render_3d.GetValue() ==
Settings::StereoRenderOption::ReverseInterlaced)
else if (Settings::values.render_3d == Settings::StereoRenderOption::Interlaced ||
Settings::values.render_3d == Settings::StereoRenderOption::ReverseInterlaced)
default_shader = "horizontal (builtin)";
Settings::values.pp_shader_name =
sdl2_config->GetString("Renderer", "pp_shader_name", default_shader);
@ -186,8 +187,9 @@ void Config::ReadValues() {
sdl2_config->GetBoolean("Utility", "preload_textures", false);
// Audio
Settings::values.audio_emulation = static_cast<Settings::AudioEmulation>(
sdl2_config->GetInteger("Audio", "audio_emulation", 0));
Settings::values.enable_dsp_lle = sdl2_config->GetBoolean("Audio", "enable_dsp_lle", false);
Settings::values.enable_dsp_lle_multithread =
sdl2_config->GetBoolean("Audio", "enable_dsp_lle_multithread", false);
Settings::values.sink_id = sdl2_config->GetString("Audio", "output_engine", "auto");
Settings::values.enable_audio_stretching =
sdl2_config->GetBoolean("Audio", "enable_audio_stretching", true);
@ -206,9 +208,9 @@ void Config::ReadValues() {
sdl2_config->GetBoolean("Data Storage", "use_custom_storage", false);
if (Settings::values.use_custom_storage) {
FileUtil::UpdateUserPath(FileUtil::UserPath::NANDDir,
Common::FS::UpdateUserPath(Common::FS::UserPath::NANDDir,
sdl2_config->GetString("Data Storage", "nand_directory", ""));
FileUtil::UpdateUserPath(FileUtil::UserPath::SDMCDir,
Common::FS::UpdateUserPath(Common::FS::UserPath::SDMCDir,
sdl2_config->GetString("Data Storage", "sdmc_directory", ""));
}
@ -239,58 +241,6 @@ void Config::ReadValues() {
.count();
}
{
constexpr const char* default_init_time_offset = "0 00:00:00";
std::string offset_string =
sdl2_config->GetString("System", "init_time_offset", default_init_time_offset);
size_t sep_index = offset_string.find(' ');
if (sep_index == std::string::npos) {
LOG_ERROR(Config, "Failed to parse init_time_offset. Using 0 00:00:00");
offset_string = default_init_time_offset;
sep_index = offset_string.find(' ');
}
std::string day_string = offset_string.substr(0, sep_index);
long long days = 0;
try {
days = std::stoll(day_string);
} catch (std::logic_error&) {
LOG_ERROR(Config, "Failed to parse days in init_time_offset. Using 0");
days = 0;
}
long long days_in_seconds = days * 86400;
std::tm t;
t.tm_sec = 0;
t.tm_min = 0;
t.tm_hour = 0;
t.tm_mday = 1;
t.tm_mon = 0;
t.tm_year = 100;
t.tm_isdst = 0;
std::istringstream string_stream(offset_string.substr(sep_index + 1));
string_stream >> std::get_time(&t, "%H:%M:%S");
if (string_stream.fail()) {
LOG_ERROR(Config,
"Failed to parse hours, minutes and seconds in init_time_offset. 00:00:00");
}
auto time_offset =
std::chrono::system_clock::from_time_t(std::mktime(&t)).time_since_epoch();
auto secs = std::chrono::duration_cast<std::chrono::seconds>(time_offset).count();
Settings::values.init_time_offset = static_cast<long long>(secs) + days_in_seconds;
}
// Camera
using namespace Service::CAM;
Settings::values.camera_name[OuterRightCamera] =

View File

@ -166,10 +166,6 @@ render_3d =
# 0 - 100: Intensity. 0 (default)
factor_3d =
# Change Default Eye to Render When in Monoscopic Mode
# 0 (default): Left, 1: Right
mono_render_option =
# The name of the post processing shader to apply.
# Loaded from shaders if render_3d is off or side by side.
# Loaded from shaders/anaglyph if render_3d is anaglyph
@ -182,11 +178,7 @@ filter_mode =
[Layout]
# Layout for the screen inside the render window.
# 0 (default): Default Top Bottom Screen
# 1: Single Screen Only
# 2: Large Screen Small Screen
# 3: Side by Side
# 4: Separate Windows
# 0 (default): Default Top Bottom Screen, 1: Single Screen Only, 2: Large Screen Small Screen, 3: Side by Side
layout_option =
# Toggle custom layout (using the settings below) on or off.

View File

@ -12,9 +12,9 @@
#include "citra/emu_window/emu_window_sdl2.h"
#include "common/logging/log.h"
#include "common/scm_rev.h"
#include "common/settings.h"
#include "core/3ds.h"
#include "core/core.h"
#include "core/settings.h"
#include "input_common/keyboard.h"
#include "input_common/main.h"
#include "input_common/motion_emu.h"
@ -135,10 +135,19 @@ void EmuWindow_SDL2::Fullscreen() {
SDL_MaximizeWindow(render_window);
}
EmuWindow_SDL2::EmuWindow_SDL2(bool fullscreen, bool is_secondary) : EmuWindow(is_secondary) {
EmuWindow_SDL2::EmuWindow_SDL2(bool fullscreen) {
// Initialize the window
const bool is_opengles =
Settings::values.graphics_api.GetValue() == Settings::GraphicsAPI::OpenGLES;
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER) < 0) {
LOG_CRITICAL(Frontend, "Failed to initialize SDL2: {}! Exiting...", SDL_GetError());
exit(1);
}
InputCommon::Init();
Network::Init();
SDL_SetMainReady();
const bool is_opengles = Settings::values.graphics_api == Settings::GraphicsAPI::OpenGLES;
if (is_opengles) {
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
@ -193,7 +202,6 @@ EmuWindow_SDL2::EmuWindow_SDL2(bool fullscreen, bool is_secondary) : EmuWindow(i
exit(1);
}
render_window_id = SDL_GetWindowID(render_window);
auto gl_load_func = is_opengles ? gladLoadGLES2Loader : gladLoadGLLoader;
if (!gl_load_func(static_cast<GLADloadproc>(SDL_GL_GetProcAddress))) {
@ -204,26 +212,19 @@ EmuWindow_SDL2::EmuWindow_SDL2(bool fullscreen, bool is_secondary) : EmuWindow(i
OnResize();
OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size);
SDL_PumpEvents();
LOG_INFO(Frontend, "Citra Version: {} | {}-{}", Common::g_build_fullname, Common::g_scm_branch,
Common::g_scm_desc);
Settings::LogSettings();
}
EmuWindow_SDL2::~EmuWindow_SDL2() {
core_context.reset();
Network::Shutdown();
InputCommon::Shutdown();
SDL_GL_DeleteContext(window_context);
SDL_Quit();
}
void EmuWindow_SDL2::InitializeSDL2() {
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER) < 0) {
LOG_CRITICAL(Frontend, "Failed to initialize SDL2: {}! Exiting...", SDL_GetError());
exit(1);
}
InputCommon::Init();
Network::Init();
SDL_SetMainReady();
}
std::unique_ptr<Frontend::GraphicsContext> EmuWindow_SDL2::CreateSharedContext() const {
return std::make_unique<SharedContext_SDL2>();
}
@ -240,7 +241,7 @@ void EmuWindow_SDL2::Present() {
SDL_GL_MakeCurrent(render_window, window_context);
SDL_GL_SetSwapInterval(1);
while (IsOpen()) {
VideoCore::g_renderer->TryPresent(100, is_secondary);
VideoCore::g_renderer->TryPresent(100);
SDL_GL_SwapWindow(render_window);
}
SDL_GL_MakeCurrent(render_window, nullptr);
@ -248,14 +249,9 @@ void EmuWindow_SDL2::Present() {
void EmuWindow_SDL2::PollEvents() {
SDL_Event event;
std::vector<SDL_Event> other_window_events;
// SDL_PollEvent returns 0 when there are no more events in the event queue
while (SDL_PollEvent(&event)) {
if (event.window.windowID != render_window_id) {
other_window_events.push_back(event);
continue;
}
switch (event.type) {
case SDL_WINDOWEVENT:
switch (event.window.event) {
@ -304,13 +300,16 @@ void EmuWindow_SDL2::PollEvents() {
break;
}
}
for (auto& e : other_window_events) {
// This is a somewhat hacky workaround to re-emit window events meant for another window
// since SDL_PollEvent() is global but we poll events per window.
SDL_PushEvent(&e);
}
if (!is_secondary) {
UpdateFramerateCounter();
const u32 current_time = SDL_GetTicks();
if (current_time > last_time + 2000) {
const auto results = Core::System::GetInstance().GetAndResetPerfStats();
const auto title =
fmt::format("Citra {} | {}-{} | FPS: {:.0f} ({:.0f}%)", Common::g_build_fullname,
Common::g_scm_branch, Common::g_scm_desc, results.game_fps,
results.emulation_speed * 100.0f);
SDL_SetWindowTitle(render_window, title.c_str());
last_time = current_time;
}
}
@ -325,16 +324,3 @@ void EmuWindow_SDL2::DoneCurrent() {
void EmuWindow_SDL2::OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) {
SDL_SetWindowMinimumSize(render_window, minimal_size.first, minimal_size.second);
}
void EmuWindow_SDL2::UpdateFramerateCounter() {
const u32 current_time = SDL_GetTicks();
if (current_time > last_time + 2000) {
const auto results = Core::System::GetInstance().GetAndResetPerfStats();
const auto title =
fmt::format("Citra {} | {}-{} | FPS: {:.0f} ({:.0f}%)", Common::g_build_fullname,
Common::g_scm_branch, Common::g_scm_desc, results.game_fps,
results.emulation_speed * 100.0f);
SDL_SetWindowTitle(render_window, title.c_str());
last_time = current_time;
}
}

View File

@ -29,11 +29,9 @@ private:
class EmuWindow_SDL2 : public Frontend::EmuWindow {
public:
explicit EmuWindow_SDL2(bool fullscreen, bool is_secondary);
explicit EmuWindow_SDL2(bool fullscreen);
~EmuWindow_SDL2();
static void InitializeSDL2();
void Present();
/// Polls window events
@ -90,18 +88,12 @@ private:
/// Called when a configuration change affects the minimal size of the window
void OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) override;
/// Called when polling to update framerate
void UpdateFramerateCounter();
/// Is the window still open?
bool is_open = true;
/// Internal SDL2 render window
SDL_Window* render_window;
/// Internal SDL2 window ID
int render_window_id{};
/// Fake hidden window for the core context
SDL_Window* dummy_window;

View File

@ -1,7 +0,0 @@
// Copyright 2022 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "common/common_precompiled_headers.h"

View File

@ -38,8 +38,6 @@ add_executable(citra-qt
configuration/config.cpp
configuration/config.h
configuration/configure.ui
configuration/configuration_shared.cpp
configuration/configuration_shared.h
configuration/configure_audio.cpp
configuration/configure_audio.h
configuration/configure_audio.ui
@ -69,9 +67,6 @@ add_executable(citra-qt
configuration/configure_motion_touch.cpp
configuration/configure_motion_touch.h
configuration/configure_motion_touch.ui
configuration/configure_per_game.cpp
configuration/configure_per_game.h
configuration/configure_per_game.ui
configuration/configure_storage.cpp
configuration/configure_storage.h
configuration/configure_storage.ui
@ -164,7 +159,6 @@ add_executable(citra-qt
multiplayer/state.cpp
multiplayer/state.h
multiplayer/validation.h
precompiled_headers.h
uisettings.cpp
uisettings.h
qt_image_interface.cpp
@ -250,8 +244,6 @@ if (APPLE)
set_target_properties(citra-qt PROPERTIES MACOSX_BUNDLE TRUE)
set_target_properties(citra-qt PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist)
target_sources(citra-qt PRIVATE
applesurfacehelper.h
applesurfacehelper.mm
macos_authorization.h
macos_authorization.mm
)
@ -326,7 +318,3 @@ if (MSVC)
copy_citra_FFmpeg_deps(citra-qt)
endif()
endif()
if (CITRA_USE_PRECOMPILED_HEADERS)
target_precompile_headers(citra-qt PRIVATE precompiled_headers.h)
endif()

View File

@ -1,11 +0,0 @@
// Copyright 2022 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
namespace AppleSurfaceHelper {
void* GetSurfaceLayer(void* surface);
} // namespace AppleSurfaceHelper

View File

@ -1,16 +0,0 @@
// Copyright 2022 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#import <Cocoa/Cocoa.h>
#include "citra_qt/applesurfacehelper.h"
namespace AppleSurfaceHelper {
void* GetSurfaceLayer(void* surface) {
NSView* view = static_cast<NSView*>(surface);
return view.layer;
}
} // AppleSurfaceHelper

View File

@ -15,19 +15,15 @@
#include "citra_qt/main.h"
#include "common/microprofile.h"
#include "common/scm_rev.h"
#include "common/settings.h"
#include "core/3ds.h"
#include "core/core.h"
#include "core/settings.h"
#include "input_common/keyboard.h"
#include "input_common/main.h"
#include "input_common/motion_emu.h"
#include "video_core/renderer_base.h"
#include "video_core/video_core.h"
#if defined(__APPLE__)
#include "citra_qt/applesurfacehelper.h"
#endif
#if !defined(WIN32)
#include <qpa/qplatformnativeinterface.h>
#endif
@ -148,7 +144,7 @@ public:
// disable vsync for any shared contexts
auto format = share_context->format();
format.setSwapInterval(main_surface ? Settings::values.use_vsync_new.GetValue() : 0);
format.setSwapInterval(main_surface ? Settings::values.use_vsync_new : 0);
context = std::make_unique<QOpenGLContext>();
context->setShareContext(share_context);
@ -281,8 +277,7 @@ private:
class OpenGLRenderWidget : public RenderWidget {
public:
explicit OpenGLRenderWidget(GRenderWindow* parent, bool is_secondary)
: RenderWidget(parent), is_secondary(is_secondary) {
explicit OpenGLRenderWidget(GRenderWindow* parent) : RenderWidget(parent) {
windowHandle()->setSurfaceType(QWindow::OpenGLSurface);
}
@ -300,14 +295,13 @@ public:
context->MakeCurrent();
const auto f = context->GetShareContext()->extraFunctions();
f->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
VideoCore::g_renderer->TryPresent(100, is_secondary);
VideoCore::g_renderer->TryPresent(100);
context->SwapBuffers();
f->glFinish();
}
private:
std::unique_ptr<OpenGLSharedContext> context{};
bool is_secondary;
};
class VulkanRenderWidget : public RenderWidget {
@ -326,8 +320,6 @@ static Frontend::WindowSystemType GetWindowSystemType() {
return Frontend::WindowSystemType::X11;
else if (platform_name == QStringLiteral("wayland"))
return Frontend::WindowSystemType::Wayland;
else if (platform_name == QStringLiteral("cocoa"))
return Frontend::WindowSystemType::MacOS;
LOG_CRITICAL(Frontend, "Unknown Qt platform!");
return Frontend::WindowSystemType::Windows;
@ -338,12 +330,8 @@ static Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window
wsi.type = GetWindowSystemType();
// Our Win32 Qt external doesn't have the private API.
#if defined(WIN32)
#if defined(WIN32) || defined(__APPLE__)
wsi.render_surface = window ? reinterpret_cast<void*>(window->winId()) : nullptr;
#elif defined(__APPLE__)
wsi.render_surface =
window ? AppleSurfaceHelper::GetSurfaceLayer(reinterpret_cast<void*>(window->winId()))
: nullptr;
#else
QPlatformNativeInterface* pni = QGuiApplication::platformNativeInterface();
wsi.display_connection = pni->nativeResourceForWindow("display", window);
@ -357,8 +345,8 @@ static Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window
return wsi;
}
GRenderWindow::GRenderWindow(QWidget* parent_, EmuThread* emu_thread, bool is_secondary_)
: QWidget(parent_), EmuWindow(is_secondary_), emu_thread(emu_thread) {
GRenderWindow::GRenderWindow(QWidget* parent_, EmuThread* emu_thread)
: QWidget(parent_), emu_thread(emu_thread) {
setWindowTitle(QStringLiteral("Citra %1 | %2-%3")
.arg(QString::fromUtf8(Common::g_build_name),
@ -368,6 +356,7 @@ GRenderWindow::GRenderWindow(QWidget* parent_, EmuThread* emu_thread, bool is_se
auto layout = new QHBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
setLayout(layout);
InputCommon::Init();
this->setMouseTracking(true);
@ -375,7 +364,9 @@ GRenderWindow::GRenderWindow(QWidget* parent_, EmuThread* emu_thread, bool is_se
connect(this, &GRenderWindow::FirstFrameDisplayed, parent, &GMainWindow::OnLoadComplete);
}
GRenderWindow::~GRenderWindow() = default;
GRenderWindow::~GRenderWindow() {
InputCommon::Shutdown();
}
void GRenderWindow::MakeCurrent() {
main_context->MakeCurrent();
@ -540,12 +531,6 @@ bool GRenderWindow::event(QEvent* event) {
void GRenderWindow::focusOutEvent(QFocusEvent* event) {
QWidget::focusOutEvent(event);
InputCommon::GetKeyboard()->ReleaseAllKeys();
has_focus = false;
}
void GRenderWindow::focusInEvent(QFocusEvent* event) {
QWidget::focusInEvent(event);
has_focus = true;
}
void GRenderWindow::resizeEvent(QResizeEvent* event) {
@ -554,7 +539,7 @@ void GRenderWindow::resizeEvent(QResizeEvent* event) {
}
std::unique_ptr<Frontend::GraphicsContext> GRenderWindow::CreateSharedContext() const {
const Settings::GraphicsAPI graphics_api = Settings::values.graphics_api.GetValue();
const Settings::GraphicsAPI graphics_api = Settings::values.graphics_api;
if (graphics_api == Settings::GraphicsAPI::OpenGL ||
graphics_api == Settings::GraphicsAPI::OpenGLES) {
auto c = static_cast<OpenGLSharedContext*>(main_context.get());
@ -578,7 +563,7 @@ bool GRenderWindow::InitRenderTarget() {
first_frame = false;
const Settings::GraphicsAPI graphics_api = Settings::values.graphics_api.GetValue();
const Settings::GraphicsAPI graphics_api = Settings::values.graphics_api;
switch (graphics_api) {
case Settings::GraphicsAPI::OpenGL:
case Settings::GraphicsAPI::OpenGLES:
@ -622,11 +607,11 @@ void GRenderWindow::ReleaseRenderTarget() {
void GRenderWindow::CaptureScreenshot(u32 res_scale, const QString& screenshot_path) {
if (res_scale == 0)
res_scale = VideoCore::GetResolutionScaleFactor();
const auto layout{Layout::FrameLayoutFromResolutionScale(res_scale, is_secondary)};
const Layout::FramebufferLayout layout{Layout::FrameLayoutFromResolutionScale(res_scale)};
screenshot_image = QImage(QSize(layout.width, layout.height), QImage::Format_RGB32);
VideoCore::RequestScreenshot(
screenshot_image.bits(),
[this, screenshot_path] {
[this, &screenshot_path] {
const std::string std_screenshot_path = screenshot_path.toStdString();
if (screenshot_image.mirrored(false, true).save(screenshot_path)) {
LOG_INFO(Frontend, "Screenshot saved to \"{}\"", std_screenshot_path);
@ -644,7 +629,7 @@ void GRenderWindow::OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal
bool GRenderWindow::InitializeOpenGL() {
// TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground,
// WA_DontShowOnScreen, WA_DeleteOnClose
auto child = new OpenGLRenderWidget(this, is_secondary);
auto child = new OpenGLRenderWidget(this);
child_widget = child;
child_widget->windowHandle()->create();
auto context = std::make_shared<OpenGLSharedContext>(child->windowHandle());

View File

@ -117,7 +117,7 @@ class GRenderWindow : public QWidget, public Frontend::EmuWindow {
Q_OBJECT
public:
GRenderWindow(QWidget* parent, EmuThread* emu_thread, bool is_secondary);
GRenderWindow(QWidget* parent, EmuThread* emu_thread);
~GRenderWindow() override;
// EmuWindow implementation.
@ -147,10 +147,6 @@ public:
bool event(QEvent* event) override;
void focusOutEvent(QFocusEvent* event) override;
void focusInEvent(QFocusEvent* event) override;
bool HasFocus() const {
return has_focus;
}
bool InitRenderTarget();
@ -204,7 +200,6 @@ private:
QWidget* child_widget = nullptr;
bool first_frame = false;
bool has_focus = false;
protected:
void showEvent(QShowEvent* event) override;

View File

@ -19,31 +19,25 @@ namespace Camera {
QList<QVideoFrame::PixelFormat> QtCameraSurface::supportedPixelFormats(
[[maybe_unused]] QAbstractVideoBuffer::HandleType handleType) const {
return QList<QVideoFrame::PixelFormat>()
<< QVideoFrame::Format_RGB32 << QVideoFrame::Format_RGB24
<< QVideoFrame::Format_ARGB32_Premultiplied << QVideoFrame::Format_ARGB32
<< QVideoFrame::Format_RGB565 << QVideoFrame::Format_RGB555
<< QVideoFrame::Format_Jpeg
// the following formats are supported via Qt internal conversions
<< QVideoFrame::Format_ARGB8565_Premultiplied << QVideoFrame::Format_BGRA32
<< QVideoFrame::Format_BGRA32_Premultiplied << QVideoFrame::Format_BGR32
<< QVideoFrame::Format_BGR24 << QVideoFrame::Format_BGR565 << QVideoFrame::Format_BGR555
<< QVideoFrame::Format_AYUV444 << QVideoFrame::Format_YUV444
<< QVideoFrame::Format_YUV420P << QVideoFrame::Format_YV12 << QVideoFrame::Format_UYVY
<< QVideoFrame::Format_YUYV << QVideoFrame::Format_NV12
<< QVideoFrame::Format_NV21; // Supporting all the QImage convertible formats, ordered by
// QImage decoding performance
<< QVideoFrame::Format_ARGB32 << QVideoFrame::Format_ARGB32_Premultiplied
<< QVideoFrame::Format_RGB32 << QVideoFrame::Format_RGB24 << QVideoFrame::Format_RGB565
<< QVideoFrame::Format_RGB555 << QVideoFrame::Format_ARGB8565_Premultiplied
<< QVideoFrame::Format_BGRA32 << QVideoFrame::Format_BGRA32_Premultiplied
<< QVideoFrame::Format_BGR32 << QVideoFrame::Format_BGR24 << QVideoFrame::Format_BGR565
<< QVideoFrame::Format_BGR555 << QVideoFrame::Format_BGRA5658_Premultiplied
<< QVideoFrame::Format_AYUV444 << QVideoFrame::Format_AYUV444_Premultiplied
<< QVideoFrame::Format_YUV444 << QVideoFrame::Format_YUV420P << QVideoFrame::Format_YV12
<< QVideoFrame::Format_UYVY << QVideoFrame::Format_YUYV << QVideoFrame::Format_NV12
<< QVideoFrame::Format_NV21 << QVideoFrame::Format_IMC1 << QVideoFrame::Format_IMC2
<< QVideoFrame::Format_IMC3 << QVideoFrame::Format_IMC4 << QVideoFrame::Format_Y8
<< QVideoFrame::Format_Y16 << QVideoFrame::Format_Jpeg << QVideoFrame::Format_CameraRaw
<< QVideoFrame::Format_AdobeDng; // Supporting all the formats
}
bool QtCameraSurface::present(const QVideoFrame& frame) {
if (!frame.isValid()) {
return false;
}
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
QMutexLocker locker(&mutex);
// In Qt 5.15, the image is already flipped
current_frame = frame.image();
locker.unlock();
#else
QVideoFrame cloneFrame(frame);
cloneFrame.map(QAbstractVideoBuffer::ReadOnly);
const QImage image(cloneFrame.bits(), cloneFrame.width(), cloneFrame.height(),
@ -52,7 +46,6 @@ bool QtCameraSurface::present(const QVideoFrame& frame) {
current_frame = image.mirrored(true, true);
locker.unlock();
cloneFrame.unmap();
#endif
return true;
}
@ -206,7 +199,6 @@ void QtMultimediaCameraHandler::StartCamera() {
camera->setViewfinderSettings(settings);
camera->start();
started = true;
paused = false;
}
bool QtMultimediaCameraHandler::CameraAvailable() const {
@ -218,14 +210,13 @@ void QtMultimediaCameraHandler::StopCameras() {
for (auto& handler : handlers) {
if (handler && handler->started) {
handler->StopCamera();
handler->paused = true;
}
}
}
void QtMultimediaCameraHandler::ResumeCameras() {
for (auto& handler : handlers) {
if (handler && handler->paused) {
if (handler && handler->started) {
handler->StartCamera();
}
}
@ -237,7 +228,6 @@ void QtMultimediaCameraHandler::ReleaseHandlers() {
for (std::size_t i = 0; i < handlers.size(); i++) {
status[i] = false;
handlers[i]->started = false;
handlers[i]->paused = false;
}
}

View File

@ -90,7 +90,6 @@ private:
QtCameraSurface camera_surface{};
QCameraViewfinderSettings settings;
bool started = false;
bool paused = false; // was previously started but was paused, to be resumed
static std::array<std::shared_ptr<QtMultimediaCameraHandler>, 3> handlers;
static std::array<bool, 3> status;

File diff suppressed because it is too large Load Diff

View File

@ -8,16 +8,13 @@
#include <memory>
#include <string>
#include <QVariant>
#include "common/settings.h"
#include "core/settings.h"
class QSettings;
class Config {
public:
enum class ConfigType : u32 { GlobalConfig, PerGameConfig };
explicit Config(const std::string& config_name = "qt-config",
ConfigType config_type = ConfigType::GlobalConfig);
Config();
~Config();
void Reload();
@ -27,8 +24,6 @@ public:
static const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs> default_analogs;
private:
void Initialize(const std::string& config_name);
void ReadValues();
void ReadAudioValues();
void ReadCameraValues();
@ -73,78 +68,11 @@ private:
void SaveWebServiceValues();
void SaveVideoDumpingValues();
/**
* Reads a setting from the qt_config.
*
* @param name The setting's identifier
* @param default_value The value to use when the setting is not already present in the config
*/
QVariant ReadSetting(const QString& name) const;
QVariant ReadSetting(const QString& name, const QVariant& default_value) const;
/**
* Only reads a setting from the qt_config if the current config is a global config, or if the
* current config is a custom config and the setting is overriding the global setting. Otherwise
* it does nothing.
*
* @param setting The variable to be modified
* @param name The setting's identifier
* @param default_value The value to use when the setting is not already present in the config
*/
template <typename Type>
void ReadSettingGlobal(Type& setting, const QString& name, const QVariant& default_value) const;
/**
* Writes a setting to the qt_config.
*
* @param name The setting's idetentifier
* @param value Value of the setting
* @param default_value Default of the setting if not present in qt_config
* @param use_global Specifies if the custom or global config should be in use, for custom
* configs
*/
void WriteSetting(const QString& name, const QVariant& value);
void WriteSetting(const QString& name, const QVariant& value, const QVariant& default_value);
void WriteSetting(const QString& name, const QVariant& value, const QVariant& default_value,
bool use_global);
/**
* Reads a value from the qt_config and applies it to the setting, using its label and default
* value. If the config is a custom config, this will also read the global state of the setting
* and apply that information to it.
*
* @param The setting
*/
template <typename Type, bool ranged>
void ReadGlobalSetting(Settings::SwitchableSetting<Type, ranged>& setting);
/**
* Sets a value to the qt_config using the setting's label and default value. If the config is a
* custom config, it will apply the global state, and the custom value if needed.
*
* @param The setting
*/
template <typename Type, bool ranged>
void WriteGlobalSetting(const Settings::SwitchableSetting<Type, ranged>& setting);
/**
* Reads a value from the qt_config using the setting's label and default value and applies the
* value to the setting.
*
* @param The setting
*/
template <typename Type, bool ranged>
void ReadBasicSetting(Settings::Setting<Type, ranged>& setting);
/** Sets a value from the setting in the qt_config using the setting's label and default value.
*
* @param The setting
*/
template <typename Type, bool ranged>
void WriteBasicSetting(const Settings::Setting<Type, ranged>& setting);
ConfigType type;
std::unique_ptr<QSettings> qt_config;
std::string qt_config_loc;
bool global;
};

View File

@ -1,95 +0,0 @@
// Copyright 2020 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <QCheckBox>
#include <QObject>
#include <QString>
#include "citra_qt/configuration/configuration_shared.h"
#include "citra_qt/configuration/configure_per_game.h"
#include "common/settings.h"
void ConfigurationShared::ApplyPerGameSetting(Settings::SwitchableSetting<bool>* setting,
const QCheckBox* checkbox,
const CheckState& tracker) {
if (Settings::IsConfiguringGlobal() && setting->UsingGlobal()) {
setting->SetValue(checkbox->checkState());
} else if (!Settings::IsConfiguringGlobal()) {
if (tracker == CheckState::Global) {
setting->SetGlobal(true);
} else {
setting->SetGlobal(false);
setting->SetValue(checkbox->checkState());
}
}
}
void ConfigurationShared::SetPerGameSetting(QCheckBox* checkbox,
const Settings::SwitchableSetting<bool>* setting) {
if (setting->UsingGlobal()) {
checkbox->setCheckState(Qt::PartiallyChecked);
} else {
checkbox->setCheckState(setting->GetValue() ? Qt::Checked : Qt::Unchecked);
}
}
void ConfigurationShared::SetHighlight(QWidget* widget, bool highlighted) {
if (highlighted) {
widget->setStyleSheet(QStringLiteral("QWidget#%1 { background-color:rgba(0,203,255,0.5) }")
.arg(widget->objectName()));
} else {
widget->setStyleSheet(QStringLiteral("QWidget#%1 { background-color:rgba(0,0,0,0) }")
.arg(widget->objectName()));
}
widget->show();
}
void ConfigurationShared::SetColoredTristate(QCheckBox* checkbox,
const Settings::SwitchableSetting<bool>& setting,
CheckState& tracker) {
if (setting.UsingGlobal()) {
tracker = CheckState::Global;
} else {
tracker = (setting.GetValue() == setting.GetValue(true)) ? CheckState::On : CheckState::Off;
}
SetHighlight(checkbox, tracker != CheckState::Global);
QObject::connect(checkbox, &QCheckBox::clicked, checkbox, [checkbox, setting, &tracker] {
tracker = static_cast<CheckState>((static_cast<int>(tracker) + 1) %
static_cast<int>(CheckState::Count));
if (tracker == CheckState::Global) {
checkbox->setChecked(setting.GetValue(true));
}
SetHighlight(checkbox, tracker != CheckState::Global);
});
}
void ConfigurationShared::SetColoredTristate(QCheckBox* checkbox, bool global, bool state,
bool global_state, CheckState& tracker) {
if (global) {
tracker = CheckState::Global;
} else {
tracker = (state == global_state) ? CheckState::On : CheckState::Off;
}
SetHighlight(checkbox, tracker != CheckState::Global);
QObject::connect(checkbox, &QCheckBox::clicked, checkbox, [checkbox, global_state, &tracker] {
tracker = static_cast<CheckState>((static_cast<int>(tracker) + 1) %
static_cast<int>(CheckState::Count));
if (tracker == CheckState::Global) {
checkbox->setChecked(global_state);
}
SetHighlight(checkbox, tracker != CheckState::Global);
});
}
void ConfigurationShared::SetColoredComboBox(QComboBox* combobox, QWidget* target, int global) {
InsertGlobalItem(combobox, global);
QObject::connect(combobox, qOverload<int>(&QComboBox::activated), target,
[target](int index) { SetHighlight(target, index != 0); });
}
void ConfigurationShared::InsertGlobalItem(QComboBox* combobox, int global_index) {
const QString use_global_text =
ConfigurePerGame::tr("Use global configuration (%1)").arg(combobox->itemText(global_index));
combobox->insertItem(ConfigurationShared::USE_GLOBAL_INDEX, use_global_text);
combobox->insertSeparator(ConfigurationShared::USE_GLOBAL_SEPARATOR_INDEX);
}

View File

@ -1,98 +0,0 @@
// Copyright 2020 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <QCheckBox>
#include <QComboBox>
#include "common/settings.h"
namespace ConfigurationShared {
constexpr int USE_GLOBAL_INDEX =
0; ///< The index of the "Use global configuration" option in checkboxes
constexpr int USE_GLOBAL_SEPARATOR_INDEX = 1;
constexpr int USE_GLOBAL_OFFSET = 2;
/// CheckBoxes require a tracker for their state since we emulate a tristate CheckBox
enum class CheckState {
Off, ///< Checkbox overrides to off/false
On, ///< Checkbox overrides to on/true
Global, ///< Checkbox defers to the global state
Count, ///< Simply the number of states, not a valid checkbox state
};
/**
* @brief ApplyPerGameSetting given a setting and a Qt UI element, properly applies a Setting
* taking into account the global/per-game check state. This is used for configuring checkboxes
* @param setting
* @param checkbox
* @param tracker
*/
void ApplyPerGameSetting(Settings::SwitchableSetting<bool>* setting, const QCheckBox* checkbox,
const CheckState& tracker);
/**
* @brief ApplyPerGameSetting given a setting and a Qt UI element, properly applies a Setting
* taking into account the global/per-game check state. This is used for both combo boxes
* as well as any other widget that is accompanied by a combo box in per-game settings.
* @param setting The setting class that stores the desired option
* @param combobox The Qt combo box that stores the value/per-game status
* @param transform A function that accepts the combo box index and transforms it to the
* desired settings value. When used with sliders/edit the user can ignore the input value
* and set a custom value this making this function useful for these widgets as well
*/
template <typename Type, bool ranged>
void ApplyPerGameSetting(Settings::SwitchableSetting<Type, ranged>* setting,
const QComboBox* combobox, auto transform) {
if (Settings::IsConfiguringGlobal() && setting->UsingGlobal()) {
setting->SetValue(static_cast<Type>(transform(combobox->currentIndex())));
} else if (!Settings::IsConfiguringGlobal()) {
if (combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
setting->SetGlobal(true);
} else {
setting->SetGlobal(false);
setting->SetValue(static_cast<Type>(
transform(combobox->currentIndex() - ConfigurationShared::USE_GLOBAL_OFFSET)));
}
}
}
/// Simpler version of ApplyPerGameSetting without a transform parameter
template <typename Type, bool ranged>
void ApplyPerGameSetting(Settings::SwitchableSetting<Type, ranged>* setting,
const QComboBox* combobox) {
const auto transform = [](s32 index) { return index; };
return ApplyPerGameSetting(setting, combobox, transform);
}
/// Sets a Qt UI element given a Settings::Setting
void SetPerGameSetting(QCheckBox* checkbox, const Settings::SwitchableSetting<bool>* setting);
template <typename Type, bool ranged>
void SetPerGameSetting(QComboBox* combobox,
const Settings::SwitchableSetting<Type, ranged>* setting) {
combobox->setCurrentIndex(setting->UsingGlobal() ? ConfigurationShared::USE_GLOBAL_INDEX
: static_cast<int>(setting->GetValue()) +
ConfigurationShared::USE_GLOBAL_OFFSET);
}
/// Given a Qt widget sets the background color to indicate whether the setting
/// is per-game overriden (highlighted) or global (non-highlighted)
void SetHighlight(QWidget* widget, bool highlighted);
/// Sets up a QCheckBox like a tristate one, given a Setting
void SetColoredTristate(QCheckBox* checkbox, const Settings::SwitchableSetting<bool>& setting,
CheckState& tracker);
void SetColoredTristate(QCheckBox* checkbox, bool global, bool state, bool global_state,
CheckState& tracker);
/// Sets up coloring of a QWidget `target` based on the state of a QComboBox, and calls
/// InsertGlobalItem
void SetColoredComboBox(QComboBox* combobox, QWidget* target, int global);
/// Adds the "Use Global Configuration" selection and separator to the beginning of a QComboBox
void InsertGlobalItem(QComboBox* combobox, int global_index);
} // namespace ConfigurationShared

View File

@ -9,11 +9,10 @@
#endif
#include "audio_core/sink.h"
#include "audio_core/sink_details.h"
#include "citra_qt/configuration/configuration_shared.h"
#include "citra_qt/configuration/configure_audio.h"
#include "common/settings.h"
#include "core/core.h"
#include "core/frontend/mic.h"
#include "core/settings.h"
#include "ui_configure_audio.h"
#if defined(__APPLE__)
@ -32,30 +31,25 @@ ConfigureAudio::ConfigureAudio(QWidget* parent)
ui->output_sink_combo_box->addItem(QString::fromUtf8(id));
}
const bool is_running = Core::System::GetInstance().IsPoweredOn();
ui->emulation_combo_box->setEnabled(!is_running);
ui->emulation_combo_box->addItem(tr("HLE (fast)"));
ui->emulation_combo_box->addItem(tr("LLE (accurate)"));
ui->emulation_combo_box->addItem(tr("LLE multi-core"));
ui->emulation_combo_box->setEnabled(!Core::System::GetInstance().IsPoweredOn());
connect(ui->volume_slider, &QSlider::valueChanged, this,
&ConfigureAudio::SetVolumeIndicatorText);
ui->input_device_combo_box->clear();
ui->input_device_combo_box->addItem(tr("Default"));
#ifdef HAVE_CUBEB
for (const auto& device : AudioCore::ListCubebInputDevices()) {
ui->input_device_combo_box->addItem(QString::fromStdString(device));
}
#endif
connect(ui->input_type_combo_box, qOverload<int>(&QComboBox::currentIndexChanged), this,
&ConfigureAudio::UpdateAudioInputDevices);
ui->volume_label->setVisible(Settings::IsConfiguringGlobal());
ui->volume_combo_box->setVisible(!Settings::IsConfiguringGlobal());
SetupPerGameUI();
SetConfiguration();
connect(ui->output_sink_combo_box, qOverload<int>(&QComboBox::currentIndexChanged), this,
&ConfigureAudio::UpdateAudioOutputDevices);
}
@ -67,35 +61,27 @@ void ConfigureAudio::SetConfiguration() {
// The device list cannot be pre-populated (nor listed) until the output sink is known.
UpdateAudioOutputDevices(ui->output_sink_combo_box->currentIndex());
SetAudioDeviceFromDeviceID();
ui->toggle_audio_stretching->setChecked(Settings::values.enable_audio_stretching.GetValue());
const s32 volume =
static_cast<s32>(Settings::values.volume.GetValue() * ui->volume_slider->maximum());
ui->volume_slider->setValue(volume);
ui->toggle_audio_stretching->setChecked(Settings::values.enable_audio_stretching);
ui->volume_slider->setValue(
static_cast<int>(Settings::values.volume * ui->volume_slider->maximum()));
SetVolumeIndicatorText(ui->volume_slider->sliderPosition());
if (!Settings::IsConfiguringGlobal()) {
if (Settings::values.volume.UsingGlobal()) {
ui->volume_combo_box->setCurrentIndex(0);
ui->volume_slider->setEnabled(false);
int selection;
if (Settings::values.enable_dsp_lle) {
if (Settings::values.enable_dsp_lle_multithread) {
selection = 2;
} else {
ui->volume_combo_box->setCurrentIndex(1);
ui->volume_slider->setEnabled(true);
selection = 1;
}
ConfigurationShared::SetHighlight(ui->volume_layout,
!Settings::values.volume.UsingGlobal());
ConfigurationShared::SetHighlight(ui->widget_emulation,
!Settings::values.audio_emulation.UsingGlobal());
ConfigurationShared::SetPerGameSetting(ui->emulation_combo_box,
&Settings::values.audio_emulation);
} else {
s32 selection = static_cast<s32>(Settings::values.audio_emulation.GetValue());
ui->emulation_combo_box->setCurrentIndex(selection);
selection = 0;
}
ui->emulation_combo_box->setCurrentIndex(selection);
s32 index = static_cast<s32>(Settings::values.mic_input_type.GetValue());
int index = static_cast<int>(Settings::values.mic_input_type);
ui->input_type_combo_box->setCurrentIndex(index);
UpdateAudioInputDevices(index);
@ -104,7 +90,7 @@ void ConfigureAudio::SetConfiguration() {
void ConfigureAudio::SetOutputSinkFromSinkID() {
int new_sink_index = 0;
const QString sink_id = QString::fromStdString(Settings::values.sink_id.GetValue());
const QString sink_id = QString::fromStdString(Settings::values.sink_id);
for (int index = 0; index < ui->output_sink_combo_box->count(); index++) {
if (ui->output_sink_combo_box->itemText(index) == sink_id) {
new_sink_index = index;
@ -118,7 +104,7 @@ void ConfigureAudio::SetOutputSinkFromSinkID() {
void ConfigureAudio::SetAudioDeviceFromDeviceID() {
int new_device_index = -1;
const QString device_id = QString::fromStdString(Settings::values.audio_device_id.GetValue());
const QString device_id = QString::fromStdString(Settings::values.audio_device_id);
for (int index = 0; index < ui->audio_device_combo_box->count(); index++) {
if (ui->audio_device_combo_box->itemText(index) == device_id) {
new_device_index = index;
@ -134,31 +120,24 @@ void ConfigureAudio::SetVolumeIndicatorText(int percentage) {
}
void ConfigureAudio::ApplyConfiguration() {
ConfigurationShared::ApplyPerGameSetting(&Settings::values.enable_audio_stretching,
ui->toggle_audio_stretching, audio_stretching);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.audio_emulation,
ui->emulation_combo_box);
ConfigurationShared::ApplyPerGameSetting(
&Settings::values.volume, ui->volume_combo_box, [this](s32) {
return static_cast<float>(ui->volume_slider->value()) / ui->volume_slider->maximum();
});
Settings::values.sink_id =
ui->output_sink_combo_box->itemText(ui->output_sink_combo_box->currentIndex())
.toStdString();
Settings::values.enable_audio_stretching = ui->toggle_audio_stretching->isChecked();
Settings::values.audio_device_id =
ui->audio_device_combo_box->itemText(ui->audio_device_combo_box->currentIndex())
.toStdString();
Settings::values.volume =
static_cast<float>(ui->volume_slider->sliderPosition()) / ui->volume_slider->maximum();
Settings::values.enable_dsp_lle = ui->emulation_combo_box->currentIndex() != 0;
Settings::values.enable_dsp_lle_multithread = ui->emulation_combo_box->currentIndex() == 2;
Settings::values.mic_input_type =
static_cast<Settings::MicInputType>(ui->input_type_combo_box->currentIndex());
if (Settings::IsConfiguringGlobal()) {
Settings::values.sink_id =
ui->output_sink_combo_box->itemText(ui->output_sink_combo_box->currentIndex())
.toStdString();
Settings::values.audio_device_id =
ui->audio_device_combo_box->itemText(ui->audio_device_combo_box->currentIndex())
.toStdString();
Settings::values.mic_input_type =
static_cast<Settings::MicInputType>(ui->input_type_combo_box->currentIndex());
if (ui->input_device_combo_box->currentIndex() == DEFAULT_INPUT_DEVICE_INDEX) {
Settings::values.mic_input_device = Frontend::Mic::default_device_name;
} else {
Settings::values.mic_input_device =
ui->input_device_combo_box->currentText().toStdString();
}
if (ui->input_device_combo_box->currentIndex() == DEFAULT_INPUT_DEVICE_INDEX) {
Settings::values.mic_input_device = Frontend::Mic::default_device_name;
} else {
Settings::values.mic_input_device = ui->input_device_combo_box->currentText().toStdString();
}
}
@ -178,41 +157,12 @@ void ConfigureAudio::UpdateAudioInputDevices(int index) {
AppleAuthorization::CheckAuthorizationForMicrophone();
}
#endif
if (Settings::values.mic_input_device.GetValue() != Frontend::Mic::default_device_name) {
if (Settings::values.mic_input_device != Frontend::Mic::default_device_name) {
ui->input_device_combo_box->setCurrentText(
QString::fromStdString(Settings::values.mic_input_device.GetValue()));
QString::fromStdString(Settings::values.mic_input_device));
}
}
void ConfigureAudio::RetranslateUI() {
ui->retranslateUi(this);
}
void ConfigureAudio::SetupPerGameUI() {
if (Settings::IsConfiguringGlobal()) {
ui->volume_slider->setEnabled(Settings::values.volume.UsingGlobal());
return;
}
ui->output_sink_combo_box->setVisible(false);
ui->output_sink_label->setVisible(false);
ui->audio_device_combo_box->setVisible(false);
ui->audio_device_label->setVisible(false);
ui->input_type_label->setVisible(false);
ui->input_type_combo_box->setVisible(false);
ui->input_device_label->setVisible(false);
ui->input_device_combo_box->setVisible(false);
ui->microphone_layout->setVisible(false);
connect(ui->volume_combo_box, qOverload<int>(&QComboBox::activated), this, [this](int index) {
ui->volume_slider->setEnabled(index == 1);
ConfigurationShared::SetHighlight(ui->volume_layout, index == 1);
});
ConfigurationShared::SetColoredComboBox(
ui->emulation_combo_box, ui->widget_emulation,
static_cast<u32>(Settings::values.audio_emulation.GetValue(true)));
ConfigurationShared::SetColoredTristate(
ui->toggle_audio_stretching, Settings::values.enable_audio_stretching, audio_stretching);
}

View File

@ -11,10 +11,6 @@ namespace Ui {
class ConfigureAudio;
}
namespace ConfigurationShared {
enum class CheckState;
}
class ConfigureAudio : public QWidget {
Q_OBJECT
@ -34,8 +30,5 @@ private:
void SetAudioDeviceFromDeviceID();
void SetVolumeIndicatorText(int percentage);
void SetupPerGameUI();
ConfigurationShared::CheckState audio_stretching;
std::unique_ptr<Ui::ConfigureAudio> ui;
};

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>696</width>
<height>527</height>
<width>329</width>
<height>344</height>
</rect>
</property>
<layout class="QVBoxLayout">
@ -18,53 +18,26 @@
</property>
<layout class="QVBoxLayout">
<item>
<widget class="QWidget" name="widget_emulation" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_emulation">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_emulation">
<property name="text">
<string>Emulation:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="emulation_combo_box">
<item>
<property name="text">
<string>HLE (fast)</string>
</property>
</item>
<item>
<property name="text">
<string>LLE (accurate)</string>
</property>
</item>
<item>
<property name="text">
<string>LLE multi-core</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
<layout class="QHBoxLayout" name="horizontalLayout_emulation">
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_emulation">
<property name="text">
<string>Emulation:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="emulation_combo_box"/>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="output_engine_layout">
<layout class="QHBoxLayout">
<item>
<widget class="QLabel" name="output_sink_label">
<widget class="QLabel" name="label1">
<property name="text">
<string>Output Engine</string>
</property>
@ -86,9 +59,9 @@
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="audio_device_layout">
<layout class="QHBoxLayout">
<item>
<widget class="QLabel" name="audio_device_label">
<widget class="QLabel" name="label2">
<property name="text">
<string>Audio Device</string>
</property>
@ -100,97 +73,72 @@
</layout>
</item>
<item>
<widget class="QWidget" name="volume_layout" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QComboBox" name="volume_combo_box">
<item>
<property name="text">
<string>Use global volume</string>
</property>
</item>
<item>
<property name="text">
<string>Set volume:</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QLabel" name="volume_label">
<property name="text">
<string>Volume:</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>30</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QSlider" name="volume_slider">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximum">
<number>100</number>
</property>
<property name="pageStep">
<number>5</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="volume_indicator">
<property name="minimumSize">
<size>
<width>32</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>0 %</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="topMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Volume:</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QSlider" name="volume_slider">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximum">
<number>100</number>
</property>
<property name="pageStep">
<number>10</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="volume_indicator">
<property name="minimumSize">
<size>
<width>32</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>0 %</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="microphone_layout">
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Microphone</string>
</property>
@ -198,7 +146,7 @@
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="input_type_label">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Input Type</string>
</property>
@ -228,7 +176,7 @@
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="input_device_label">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Input Device</string>
</property>

View File

@ -9,10 +9,10 @@
#include <QMessageBox>
#include <QWidget>
#include "citra_qt/configuration/configure_camera.h"
#include "common/settings.h"
#include "core/frontend/camera/factory.h"
#include "core/frontend/camera/interface.h"
#include "core/hle/service/cam/cam.h"
#include "core/settings.h"
#include "ui_configure_camera.h"
#if defined(__APPLE__)

View File

@ -3,15 +3,15 @@
// Refer to the license.txt file included.
#include <QDesktopServices>
#include <QMessageBox>
#include <QUrl>
#include <QMessageBox>
#include "citra_qt/configuration/configure_debug.h"
#include "citra_qt/debugger/console.h"
#include "citra_qt/uisettings.h"
#include "common/file_util.h"
#include "common/logging/log.h"
#include "common/settings.h"
#include "core/core.h"
#include "core/settings.h"
#include "qcheckbox.h"
#include "ui_configure_debug.h"
#include "video_core/renderer_vulkan/vk_instance.h"
@ -22,36 +22,36 @@ ConfigureDebug::ConfigureDebug(QWidget* parent)
SetConfiguration();
connect(ui->open_log_button, &QPushButton::clicked, []() {
QString path = QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::LogDir));
QString path = QString::fromStdString(Common::FS::GetUserPath(Common::FS::UserPath::LogDir));
QDesktopServices::openUrl(QUrl::fromLocalFile(path));
});
connect(ui->toggle_renderer_debug, &QCheckBox::clicked, this, [this](bool checked) {
if (checked && Settings::values.graphics_api.GetValue() == Settings::GraphicsAPI::Vulkan) {
if (checked && Settings::values.graphics_api == Settings::GraphicsAPI::Vulkan) {
try {
Vulkan::Instance debug_inst{true};
} catch (vk::LayerNotPresentError&) {
} catch (vk::LayerNotPresentError& err) {
ui->toggle_renderer_debug->toggle();
QMessageBox::warning(this, tr("Validation layer not available"),
tr("Unable to enable debug renderer because the layer "
"<strong>VK_LAYER_KHRONOS_validation</strong> is missing. "
"Please install the Vulkan SDK or the appropriate package "
"of your distribution"));
QMessageBox::warning(
this, tr("Validation layer not available"),
tr("Unable to enable debug renderer because the layer "
"<strong>VK_LAYER_KHRONOS_validation</strong> is missing. "
"Please install the Vulkan SDK or the appropriate package of your distribution"));
}
}
});
connect(ui->toggle_dump_command_buffers, &QCheckBox::clicked, this, [this](bool checked) {
if (checked && Settings::values.graphics_api.GetValue() == Settings::GraphicsAPI::Vulkan) {
if (checked && Settings::values.graphics_api == Settings::GraphicsAPI::Vulkan) {
try {
Vulkan::Instance debug_inst{false, true};
} catch (vk::LayerNotPresentError&) {
} catch (vk::LayerNotPresentError& err) {
ui->toggle_dump_command_buffers->toggle();
QMessageBox::warning(this, tr("Command buffer dumping not available"),
tr("Unable to enable command buffer dumping because the layer "
"<strong>VK_LAYER_LUNARG_api_dump</strong> is missing. "
"Please install the Vulkan SDK or the appropriate package "
"of your distribution"));
QMessageBox::warning(
this, tr("Command buffer dumping not available"),
tr("Unable to enable command buffer dumping because the layer "
"<strong>VK_LAYER_LUNARG_api_dump</strong> is missing. "
"Please install the Vulkan SDK or the appropriate package of your distribution"));
}
}
});
@ -65,15 +65,15 @@ ConfigureDebug::ConfigureDebug(QWidget* parent)
ConfigureDebug::~ConfigureDebug() = default;
void ConfigureDebug::SetConfiguration() {
ui->toggle_gdbstub->setChecked(Settings::values.use_gdbstub.GetValue());
ui->gdbport_spinbox->setEnabled(Settings::values.use_gdbstub.GetValue());
ui->gdbport_spinbox->setValue(Settings::values.gdbstub_port.GetValue());
ui->toggle_gdbstub->setChecked(Settings::values.use_gdbstub);
ui->gdbport_spinbox->setEnabled(Settings::values.use_gdbstub);
ui->gdbport_spinbox->setValue(Settings::values.gdbstub_port);
ui->toggle_console->setEnabled(!Core::System::GetInstance().IsPoweredOn());
ui->toggle_console->setChecked(UISettings::values.show_console.GetValue());
ui->log_filter_edit->setText(QString::fromStdString(Settings::values.log_filter.GetValue()));
ui->toggle_cpu_jit->setChecked(Settings::values.use_cpu_jit.GetValue());
ui->toggle_renderer_debug->setChecked(Settings::values.renderer_debug.GetValue());
ui->toggle_dump_command_buffers->setChecked(Settings::values.dump_command_buffers.GetValue());
ui->toggle_console->setChecked(UISettings::values.show_console);
ui->log_filter_edit->setText(QString::fromStdString(Settings::values.log_filter));
ui->toggle_cpu_jit->setChecked(Settings::values.use_cpu_jit);
ui->toggle_renderer_debug->setChecked(Settings::values.renderer_debug);
ui->toggle_dump_command_buffers->setChecked(Settings::values.dump_command_buffers);
}
void ConfigureDebug::ApplyConfiguration() {
@ -83,7 +83,7 @@ void ConfigureDebug::ApplyConfiguration() {
Settings::values.log_filter = ui->log_filter_edit->text().toStdString();
Debugger::ToggleConsole();
Log::Filter filter;
filter.ParseFilterString(Settings::values.log_filter.GetValue());
filter.ParseFilterString(Settings::values.log_filter);
Log::SetGlobalFilter(filter);
Settings::values.use_cpu_jit = ui->toggle_cpu_jit->isChecked();
Settings::values.renderer_debug = ui->toggle_renderer_debug->isChecked();

View File

@ -7,13 +7,11 @@
#include "citra_qt/configuration/config.h"
#include "citra_qt/configuration/configure_dialog.h"
#include "citra_qt/hotkeys.h"
#include "common/settings.h"
#include "core/settings.h"
#include "ui_configure.h"
ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry, bool enable_web_config)
: QDialog(parent), ui(std::make_unique<Ui::ConfigureDialog>()), registry(registry) {
Settings::SetConfiguringGlobal(true);
ui->setupUi(this);
ui->hotkeysTab->Populate(registry);
ui->webTab->SetWebServiceConfigEnabled(enable_web_config);

View File

@ -4,8 +4,8 @@
#include <QColorDialog>
#include "citra_qt/configuration/configure_enhancements.h"
#include "common/settings.h"
#include "core/core.h"
#include "core/settings.h"
#include "ui_configure_enhancements.h"
#include "video_core/renderer_opengl/post_processing_opengl.h"
#include "video_core/renderer_opengl/texture_filters/texture_filterer.h"
@ -21,7 +21,7 @@ ConfigureEnhancements::ConfigureEnhancements(QWidget* parent)
ui->layoutBox->setEnabled(!Settings::values.custom_layout);
ui->resolution_factor_combobox->setEnabled(Settings::values.use_hw_renderer.GetValue());
ui->resolution_factor_combobox->setEnabled(Settings::values.use_hw_renderer);
connect(ui->render_3d_combobox,
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
@ -50,31 +50,26 @@ ConfigureEnhancements::ConfigureEnhancements(QWidget* parent)
}
void ConfigureEnhancements::SetConfiguration() {
ui->resolution_factor_combobox->setCurrentIndex(Settings::values.resolution_factor.GetValue());
ui->render_3d_combobox->setCurrentIndex(
static_cast<int>(Settings::values.render_3d.GetValue()));
ui->factor_3d->setValue(Settings::values.factor_3d.GetValue());
ui->mono_rendering_eye->setCurrentIndex(
static_cast<int>(Settings::values.mono_render_option.GetValue()));
updateShaders(Settings::values.render_3d.GetValue());
ui->toggle_linear_filter->setChecked(Settings::values.filter_mode.GetValue());
ui->resolution_factor_combobox->setCurrentIndex(Settings::values.resolution_factor);
ui->render_3d_combobox->setCurrentIndex(static_cast<int>(Settings::values.render_3d));
ui->factor_3d->setValue(Settings::values.factor_3d);
updateShaders(Settings::values.render_3d);
ui->toggle_linear_filter->setChecked(Settings::values.filter_mode);
int tex_filter_idx = ui->texture_filter_combobox->findText(
QString::fromStdString(Settings::values.texture_filter_name.GetValue()));
QString::fromStdString(Settings::values.texture_filter_name));
if (tex_filter_idx == -1) {
ui->texture_filter_combobox->setCurrentIndex(0);
} else {
ui->texture_filter_combobox->setCurrentIndex(tex_filter_idx);
}
ui->layout_combobox->setCurrentIndex(
static_cast<int>(Settings::values.layout_option.GetValue()));
ui->swap_screen->setChecked(Settings::values.swap_screen.GetValue());
ui->upright_screen->setChecked(Settings::values.upright_screen.GetValue());
ui->toggle_dump_textures->setChecked(Settings::values.dump_textures.GetValue());
ui->toggle_custom_textures->setChecked(Settings::values.custom_textures.GetValue());
ui->toggle_preload_textures->setChecked(Settings::values.preload_textures.GetValue());
bg_color =
QColor::fromRgbF(Settings::values.bg_red.GetValue(), Settings::values.bg_green.GetValue(),
Settings::values.bg_blue.GetValue());
ui->layout_combobox->setCurrentIndex(static_cast<int>(Settings::values.layout_option));
ui->swap_screen->setChecked(Settings::values.swap_screen);
ui->upright_screen->setChecked(Settings::values.upright_screen);
ui->toggle_dump_textures->setChecked(Settings::values.dump_textures);
ui->toggle_custom_textures->setChecked(Settings::values.custom_textures);
ui->toggle_preload_textures->setChecked(Settings::values.preload_textures);
bg_color = QColor::fromRgbF(Settings::values.bg_red, Settings::values.bg_green,
Settings::values.bg_blue);
QPixmap pixmap(ui->bg_button->size());
pixmap.fill(bg_color);
const QIcon color_icon(pixmap);
@ -97,7 +92,7 @@ void ConfigureEnhancements::updateShaders(Settings::StereoRenderOption stereo_op
for (const auto& shader : OpenGL::GetPostProcessingShaderList(
stereo_option == Settings::StereoRenderOption::Anaglyph)) {
ui->shader_combobox->addItem(QString::fromStdString(shader));
if (Settings::values.pp_shader_name.GetValue() == shader)
if (Settings::values.pp_shader_name == shader)
ui->shader_combobox->setCurrentIndex(ui->shader_combobox->count() - 1);
}
}
@ -112,8 +107,6 @@ void ConfigureEnhancements::ApplyConfiguration() {
Settings::values.render_3d =
static_cast<Settings::StereoRenderOption>(ui->render_3d_combobox->currentIndex());
Settings::values.factor_3d = ui->factor_3d->value();
Settings::values.mono_render_option =
static_cast<Settings::MonoRenderOption>(ui->mono_rendering_eye->currentIndex());
Settings::values.pp_shader_name =
ui->shader_combobox->itemText(ui->shader_combobox->currentIndex()).toStdString();
Settings::values.filter_mode = ui->toggle_linear_filter->isChecked();

View File

@ -6,10 +6,9 @@
#include <memory>
#include <QWidget>
#include "common/common_types.h"
namespace Settings {
enum class StereoRenderOption : u32;
enum class StereoRenderOption;
}
namespace Ui {

View File

@ -207,31 +207,6 @@
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_9">
<item>
<widget class="QLabel" name="label_6">
<property name="text">
<string>Eye to Render in Monoscopic Mode</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="mono_rendering_eye">
<item>
<property name="text">
<string>Left Eye (default)</string>
</property>
</item>
<item>
<property name="text">
<string>Right Eye</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
@ -272,11 +247,6 @@
<string>Side by Side</string>
</property>
</item>
<item>
<property name="text">
<string>Separate Windows</string>
</property>
</item>
</widget>
</item>
</layout>
@ -380,7 +350,6 @@
<tabstop>texture_filter_combobox</tabstop>
<tabstop>render_3d_combobox</tabstop>
<tabstop>factor_3d</tabstop>
<tabstop>mono_rendering_eye</tabstop>
<tabstop>layout_combobox</tabstop>
<tabstop>swap_screen</tabstop>
<tabstop>upright_screen</tabstop>

View File

@ -6,11 +6,10 @@
#include <QFileDialog>
#include <QMessageBox>
#include <QUrl>
#include "citra_qt/configuration/configuration_shared.h"
#include "citra_qt/configuration/configure_general.h"
#include "citra_qt/uisettings.h"
#include "common/file_util.h"
#include "common/settings.h"
#include "core/core.h"
#include "core/settings.h"
#include "ui_configure_general.h"
// The QSlider doesn't have an easy way to set a custom step amount,
@ -32,17 +31,14 @@ ConfigureGeneral::ConfigureGeneral(QWidget* parent)
// Set a minimum width for the label to prevent the slider from changing size.
// This scales across DPIs, and is acceptable for uncapitalized strings.
ui->emulation_speed_display_label->setMinimumWidth(tr("unthrottled").size() * 6);
ui->emulation_speed_combo->setVisible(!Settings::IsConfiguringGlobal());
ui->screenshot_combo->setVisible(!Settings::IsConfiguringGlobal());
SetupPerGameUI();
SetConfiguration();
ui->updateBox->setVisible(UISettings::values.updater_found);
connect(ui->button_reset_defaults, &QPushButton::clicked, this,
&ConfigureGeneral::ResetDefaults);
connect(ui->frame_limit, &QSlider::valueChanged, this, [&](int value) {
connect(ui->frame_limit, &QSlider::valueChanged, [&](int value) {
if (value == ui->frame_limit->maximum()) {
ui->emulation_speed_display_label->setText(tr("unthrottled"));
} else {
@ -53,6 +49,17 @@ ConfigureGeneral::ConfigureGeneral(QWidget* parent)
}
});
connect(ui->frame_limit_alternate, &QSlider::valueChanged, [&](int value) {
if (value == ui->frame_limit_alternate->maximum()) {
ui->emulation_speed_alternate_display_label->setText(tr("unthrottled"));
} else {
ui->emulation_speed_alternate_display_label->setText(
QStringLiteral("%1%")
.arg(SliderToSettings(value))
.rightJustified(tr("unthrottled").size()));
}
});
connect(ui->change_screenshot_dir, &QToolButton::clicked, this, [this] {
const QString dir_path = QFileDialog::getExistingDirectory(
this, tr("Select Screenshot Directory"), ui->screenshot_dir_path->text(),
@ -66,21 +73,20 @@ ConfigureGeneral::ConfigureGeneral(QWidget* parent)
ConfigureGeneral::~ConfigureGeneral() = default;
void ConfigureGeneral::SetConfiguration() {
if (Settings::IsConfiguringGlobal()) {
ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing.GetValue());
ui->toggle_background_pause->setChecked(
UISettings::values.pause_when_in_background.GetValue());
ui->toggle_hide_mouse->setChecked(UISettings::values.hide_mouse.GetValue());
ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing);
ui->toggle_background_pause->setChecked(UISettings::values.pause_when_in_background);
ui->toggle_hide_mouse->setChecked(UISettings::values.hide_mouse);
ui->toggle_update_check->setChecked(
UISettings::values.check_for_update_on_start.GetValue());
ui->toggle_auto_update->setChecked(UISettings::values.update_on_close.GetValue());
}
ui->toggle_update_check->setChecked(UISettings::values.check_for_update_on_start);
ui->toggle_auto_update->setChecked(UISettings::values.update_on_close);
if (Settings::values.frame_limit.GetValue() == 0) {
// The first item is "auto-select" with actual value -1, so plus one here will do the trick
ui->region_combobox->setCurrentIndex(Settings::values.region_value + 1);
if (Settings::values.frame_limit == 0) {
ui->frame_limit->setValue(ui->frame_limit->maximum());
} else {
ui->frame_limit->setValue(SettingsToSlider(Settings::values.frame_limit.GetValue()));
ui->frame_limit->setValue(SettingsToSlider(Settings::values.frame_limit));
}
if (ui->frame_limit->value() == ui->frame_limit->maximum()) {
ui->emulation_speed_display_label->setText(tr("unthrottled"));
@ -91,48 +97,32 @@ void ConfigureGeneral::SetConfiguration() {
.rightJustified(tr("unthrottled").size()));
}
if (!Settings::IsConfiguringGlobal()) {
if (Settings::values.frame_limit.UsingGlobal()) {
ui->emulation_speed_combo->setCurrentIndex(0);
ui->frame_limit->setEnabled(false);
} else {
ui->emulation_speed_combo->setCurrentIndex(1);
ui->frame_limit->setEnabled(true);
}
if (UISettings::values.screenshot_path.UsingGlobal()) {
ui->screenshot_combo->setCurrentIndex(0);
ui->screenshot_dir_path->setEnabled(false);
ui->change_screenshot_dir->setEnabled(false);
} else {
ui->screenshot_combo->setCurrentIndex(1);
ui->screenshot_dir_path->setEnabled(true);
ui->change_screenshot_dir->setEnabled(true);
}
ConfigurationShared::SetHighlight(ui->widget_screenshot,
!UISettings::values.screenshot_path.UsingGlobal());
ConfigurationShared::SetHighlight(ui->emulation_speed_layout,
!Settings::values.frame_limit.UsingGlobal());
ConfigurationShared::SetHighlight(ui->widget_region,
!Settings::values.region_value.UsingGlobal());
const bool is_region_global = Settings::values.region_value.UsingGlobal();
ui->region_combobox->setCurrentIndex(
is_region_global ? ConfigurationShared::USE_GLOBAL_INDEX
: static_cast<int>(Settings::values.region_value.GetValue()) +
ConfigurationShared::USE_GLOBAL_OFFSET + 1);
ui->toggle_alternate_speed->setChecked(Settings::values.use_frame_limit_alternate);
if (Settings::values.frame_limit_alternate == 0) {
ui->frame_limit_alternate->setValue(ui->frame_limit_alternate->maximum());
} else {
// The first item is "auto-select" with actual value -1, so plus one here will do the trick
ui->region_combobox->setCurrentIndex(Settings::values.region_value.GetValue() + 1);
ui->frame_limit_alternate->setValue(
SettingsToSlider(Settings::values.frame_limit_alternate));
}
if (ui->frame_limit_alternate->value() == ui->frame_limit_alternate->maximum()) {
ui->emulation_speed_alternate_display_label->setText(tr("unthrottled"));
} else {
ui->emulation_speed_alternate_display_label->setText(
QStringLiteral("%1%")
.arg(SliderToSettings(ui->frame_limit_alternate->value()))
.rightJustified(tr("unthrottled").size()));
}
UISettings::values.screenshot_path.SetGlobal(ui->screenshot_combo->currentIndex() ==
ConfigurationShared::USE_GLOBAL_INDEX);
std::string screenshot_path = UISettings::values.screenshot_path.GetValue();
if (screenshot_path.empty()) {
screenshot_path = FileUtil::GetUserPath(FileUtil::UserPath::UserDir) + "screenshots/";
FileUtil::CreateFullPath(screenshot_path);
QString screenshot_path = UISettings::values.screenshot_path;
if (screenshot_path.isEmpty()) {
screenshot_path =
QString::fromStdString(Common::FS::GetUserPath(Common::FS::UserPath::UserDir));
screenshot_path.append(QStringLiteral("screenshots/"));
Common::FS::CreateFullPath(screenshot_path.toStdString());
UISettings::values.screenshot_path = screenshot_path;
}
ui->screenshot_dir_path->setText(QString::fromStdString(screenshot_path));
ui->screenshot_dir_path->setText(screenshot_path);
}
void ConfigureGeneral::ResetDefaults() {
@ -141,67 +131,39 @@ void ConfigureGeneral::ResetDefaults() {
tr("Are you sure you want to <b>reset your settings</b> and close Citra?"),
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
if (answer == QMessageBox::No) {
if (answer == QMessageBox::No)
return;
}
FileUtil::Delete(FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir) + "qt-config.ini");
FileUtil::DeleteDirRecursively(FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir) + "custom");
Common::FS::Delete(Common::FS::GetUserPath(Common::FS::UserPath::ConfigDir) + "qt-config.ini");
std::exit(0);
}
void ConfigureGeneral::ApplyConfiguration() {
ConfigurationShared::ApplyPerGameSetting(&Settings::values.region_value, ui->region_combobox,
[](s32 index) { return index - 1; });
UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked();
UISettings::values.pause_when_in_background = ui->toggle_background_pause->isChecked();
UISettings::values.hide_mouse = ui->toggle_hide_mouse->isChecked();
ConfigurationShared::ApplyPerGameSetting(
&Settings::values.frame_limit, ui->emulation_speed_combo, [this](s32) {
const bool is_maximum = ui->frame_limit->value() == ui->frame_limit->maximum();
return is_maximum ? 0 : SliderToSettings(ui->frame_limit->value());
});
UISettings::values.check_for_update_on_start = ui->toggle_update_check->isChecked();
UISettings::values.update_on_close = ui->toggle_auto_update->isChecked();
ConfigurationShared::ApplyPerGameSetting(
&UISettings::values.screenshot_path, ui->screenshot_combo,
[this](s32) { return ui->screenshot_dir_path->text().toStdString(); });
UISettings::values.screenshot_path = ui->screenshot_dir_path->text();
if (Settings::IsConfiguringGlobal()) {
UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked();
UISettings::values.pause_when_in_background = ui->toggle_background_pause->isChecked();
UISettings::values.hide_mouse = ui->toggle_hide_mouse->isChecked();
Settings::values.region_value = ui->region_combobox->currentIndex() - 1;
UISettings::values.check_for_update_on_start = ui->toggle_update_check->isChecked();
UISettings::values.update_on_close = ui->toggle_auto_update->isChecked();
if (ui->frame_limit->value() == ui->frame_limit->maximum()) {
Settings::values.frame_limit = 0;
} else {
Settings::values.frame_limit = SliderToSettings(ui->frame_limit->value());
}
Settings::values.use_frame_limit_alternate = ui->toggle_alternate_speed->isChecked();
if (ui->frame_limit_alternate->value() == ui->frame_limit_alternate->maximum()) {
Settings::values.frame_limit_alternate = 0;
} else {
Settings::values.frame_limit_alternate =
SliderToSettings(ui->frame_limit_alternate->value());
}
}
void ConfigureGeneral::RetranslateUI() {
ui->retranslateUi(this);
}
void ConfigureGeneral::SetupPerGameUI() {
if (Settings::IsConfiguringGlobal()) {
ui->region_combobox->setEnabled(Settings::values.region_value.UsingGlobal());
ui->frame_limit->setEnabled(Settings::values.frame_limit.UsingGlobal());
return;
}
connect(ui->emulation_speed_combo, qOverload<int>(&QComboBox::activated), this,
[this](int index) {
ui->frame_limit->setEnabled(index == 1);
ConfigurationShared::SetHighlight(ui->emulation_speed_layout, index == 1);
});
connect(ui->screenshot_combo, qOverload<int>(&QComboBox::activated), this, [this](int index) {
ui->screenshot_dir_path->setEnabled(index == 1);
ui->change_screenshot_dir->setEnabled(index == 1);
ConfigurationShared::SetHighlight(ui->widget_screenshot, index == 1);
});
ui->general_group->setVisible(false);
ui->updateBox->setVisible(false);
ui->button_reset_defaults->setVisible(false);
ConfigurationShared::SetColoredComboBox(
ui->region_combobox, ui->widget_region,
static_cast<u32>(Settings::values.region_value.GetValue(true) + 1));
}

View File

@ -25,8 +25,6 @@ public:
void RetranslateUI();
void SetConfiguration();
void SetupPerGameUI();
private:
std::unique_ptr<Ui::ConfigureGeneral> ui;
};

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>524</width>
<height>578</height>
<width>408</width>
<height>436</height>
</rect>
</property>
<property name="windowTitle">
@ -17,7 +17,7 @@
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="general_group">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>General</string>
</property>
@ -70,152 +70,144 @@
</widget>
</item>
<item>
<widget class="QGroupBox" name="emulation_group">
<widget class="QGroupBox" name="groupBox_4">
<property name="title">
<string>Emulation</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QWidget" name="widget_region" native="true">
<layout class="QHBoxLayout" name="region_layout">
<property name="leftMargin">
<number>0</number>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="2">
<widget class="QComboBox" name="region_combobox">
<item>
<property name="text">
<string>Auto-select</string>
</property>
<property name="topMargin">
<number>0</number>
</item>
<item>
<property name="text">
<string notr="true">JPN</string>
</property>
<property name="rightMargin">
<number>0</number>
</item>
<item>
<property name="text">
<string notr="true">USA</string>
</property>
<property name="bottomMargin">
<number>0</number>
</item>
<item>
<property name="text">
<string notr="true">EUR</string>
</property>
<item>
<widget class="QLabel" name="region_label">
<property name="text">
<string>Region:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="region_combobox">
<item>
<property name="text">
<string>Auto-select</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">JPN</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">USA</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">EUR</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">AUS</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">CHN</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">KOR</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">TWN</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item>
<property name="text">
<string notr="true">AUS</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">CHN</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">KOR</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">TWN</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QWidget" name="emulation_speed_layout" native="true">
<layout class="QHBoxLayout" name="emulation_speed_layout_inner">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QComboBox" name="emulation_speed_combo">
<item>
<property name="text">
<string>Use global emulation speed</string>
</property>
</item>
<item>
<property name="text">
<string>Set emulation speed:</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QLabel" name="label_emulation_speed">
<property name="text">
<string>Emulation Speed:</string>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="frame_limit">
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>199</number>
</property>
<property name="singleStep">
<number>5</number>
</property>
<property name="pageStep">
<number>15</number>
</property>
<property name="value">
<number>19</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="tickPosition">
<enum>QSlider::TicksBelow</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="emulation_speed_display_label">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
<item row="1" column="0">
<widget class="QLabel" name="label_emulation_speed">
<property name="text">
<string>Emulation Speed:</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="toggle_alternate_speed">
<property name="text">
<string>Use Alternate Speed:</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QSlider" name="frame_limit">
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>199</number>
</property>
<property name="singleStep">
<number>5</number>
</property>
<property name="pageStep">
<number>15</number>
</property>
<property name="value">
<number>19</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="tickPosition">
<enum>QSlider::TicksBelow</enum>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="emulation_speed_display_label">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Region:</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QSlider" name="frame_limit_alternate">
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>199</number>
</property>
<property name="singleStep">
<number>5</number>
</property>
<property name="pageStep">
<number>15</number>
</property>
<property name="value">
<number>39</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="tickPosition">
<enum>QSlider::TicksBelow</enum>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="emulation_speed_alternate_display_label">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
@ -226,57 +218,23 @@
<property name="title">
<string>Screenshots</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="verticalSpacing">
<number>0</number>
</property>
<item row="0" column="1">
<widget class="QWidget" name="widget_screenshot" native="true">
<layout class="QHBoxLayout" name="screenshot_layout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QComboBox" name="screenshot_combo">
<item>
<property name="text">
<string>Use global screenshot path</string>
</property>
</item>
<item>
<property name="text">
<string>Set screenshot path:</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QLabel" name="screenshot_dir_label">
<property name="text">
<string>Save Screenshots To</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="screenshot_dir_path"/>
</item>
<item>
<widget class="QToolButton" name="change_screenshot_dir">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Save Screenshots To</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="screenshot_dir_path">
</widget>
</item>
<item>
<widget class="QToolButton" name="change_screenshot_dir">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
@ -312,6 +270,12 @@
<tabstop>toggle_hide_mouse</tabstop>
<tabstop>toggle_update_check</tabstop>
<tabstop>toggle_auto_update</tabstop>
<tabstop>region_combobox</tabstop>
<tabstop>frame_limit</tabstop>
<tabstop>toggle_alternate_speed</tabstop>
<tabstop>frame_limit_alternate</tabstop>
<tabstop>screenshot_dir_path</tabstop>
<tabstop>change_screenshot_dir</tabstop>
<tabstop>button_reset_defaults</tabstop>
</tabstops>
<resources/>

View File

@ -6,19 +6,16 @@
#ifdef __APPLE__
#include <QMessageBox>
#endif
#include "citra_qt/configuration/configuration_shared.h"
#include "citra_qt/configuration/configure_graphics.h"
#include "common/settings.h"
#include "core/core.h"
#include "core/settings.h"
#include "ui_configure_graphics.h"
#include "video_core/renderer_vulkan/vk_instance.h"
ConfigureGraphics::ConfigureGraphics(QWidget* parent)
: QWidget(parent), ui(std::make_unique<Ui::ConfigureGraphics>()) {
ui->setupUi(this);
DiscoverPhysicalDevices();
SetupPerGameUI();
SetConfiguration();
const bool not_running = !Core::System::GetInstance().IsPoweredOn();
@ -29,6 +26,7 @@ ConfigureGraphics::ConfigureGraphics(QWidget* parent)
ui->graphics_api_combo->setEnabled(not_running);
ui->toggle_shader_jit->setEnabled(not_running);
ui->toggle_disk_shader_cache->setEnabled(hw_renderer_enabled && not_running);
ui->toggle_async_recording->setEnabled(hw_renderer_enabled && not_running);
ui->physical_device_combo->setEnabled(not_running);
SetPhysicalDeviceComboVisibility(ui->graphics_api_combo->currentIndex());
@ -36,7 +34,7 @@ ConfigureGraphics::ConfigureGraphics(QWidget* parent)
&ConfigureGraphics::SetPhysicalDeviceComboVisibility);
connect(ui->toggle_hw_renderer, &QCheckBox::toggled, this, [this] {
const bool checked = ui->toggle_hw_renderer->isChecked();
auto checked = ui->toggle_hw_renderer->isChecked();
ui->hw_renderer_group->setEnabled(checked);
ui->toggle_disk_shader_cache->setEnabled(checked && ui->toggle_hw_shader->isChecked());
});
@ -77,85 +75,36 @@ ConfigureGraphics::ConfigureGraphics(QWidget* parent)
ConfigureGraphics::~ConfigureGraphics() = default;
void ConfigureGraphics::SetConfiguration() {
ui->toggle_hw_renderer->setChecked(Settings::values.use_hw_renderer.GetValue());
ui->toggle_hw_shader->setChecked(Settings::values.use_hw_shader.GetValue());
ui->toggle_separable_shader->setChecked(Settings::values.separable_shader.GetValue());
ui->toggle_accurate_mul->setChecked(Settings::values.shaders_accurate_mul.GetValue());
ui->toggle_disk_shader_cache->setChecked(Settings::values.use_disk_shader_cache.GetValue());
ui->toggle_vsync_new->setChecked(Settings::values.use_vsync_new.GetValue());
ui->graphics_api_combo->setCurrentIndex(
static_cast<int>(Settings::values.graphics_api.GetValue()));
ui->physical_device_combo->setCurrentIndex(
static_cast<int>(Settings::values.physical_device.GetValue()));
ui->toggle_async_recording->setChecked(Settings::values.async_command_recording.GetValue());
ui->spirv_shader_gen->setChecked(Settings::values.spirv_shader_gen.GetValue());
if (Settings::IsConfiguringGlobal()) {
ui->toggle_shader_jit->setChecked(Settings::values.use_shader_jit.GetValue());
}
ui->toggle_hw_renderer->setChecked(Settings::values.use_hw_renderer);
ui->toggle_hw_shader->setChecked(Settings::values.use_hw_shader);
ui->toggle_separable_shader->setChecked(Settings::values.separable_shader);
ui->toggle_accurate_mul->setChecked(Settings::values.shaders_accurate_mul);
ui->toggle_shader_jit->setChecked(Settings::values.use_shader_jit);
ui->toggle_disk_shader_cache->setChecked(Settings::values.use_disk_shader_cache);
ui->toggle_vsync_new->setChecked(Settings::values.use_vsync_new);
ui->graphics_api_combo->setCurrentIndex(static_cast<int>(Settings::values.graphics_api));
ui->physical_device_combo->setCurrentIndex(static_cast<int>(Settings::values.physical_device));
ui->toggle_async_recording->setChecked(Settings::values.async_command_recording);
}
void ConfigureGraphics::ApplyConfiguration() {
ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_hw_renderer,
ui->toggle_hw_renderer, use_hw_renderer);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_hw_shader, ui->toggle_hw_shader,
use_hw_shader);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.separable_shader,
ui->toggle_separable_shader, separable_shader);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.shaders_accurate_mul,
ui->toggle_accurate_mul, shaders_accurate_mul);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_disk_shader_cache,
ui->toggle_disk_shader_cache, use_disk_shader_cache);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vsync_new, ui->toggle_vsync_new,
use_vsync_new);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.graphics_api,
ui->graphics_api_combo);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.physical_device,
ui->physical_device_combo);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.async_command_recording,
ui->toggle_async_recording, async_command_recording);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.spirv_shader_gen,
ui->spirv_shader_gen, spirv_shader_gen);
if (Settings::IsConfiguringGlobal()) {
Settings::values.use_shader_jit = ui->toggle_shader_jit->isChecked();
}
Settings::values.use_hw_renderer = ui->toggle_hw_renderer->isChecked();
Settings::values.use_hw_shader = ui->toggle_hw_shader->isChecked();
Settings::values.separable_shader = ui->toggle_separable_shader->isChecked();
Settings::values.shaders_accurate_mul = ui->toggle_accurate_mul->isChecked();
Settings::values.use_shader_jit = ui->toggle_shader_jit->isChecked();
Settings::values.use_disk_shader_cache = ui->toggle_disk_shader_cache->isChecked();
Settings::values.use_vsync_new = ui->toggle_vsync_new->isChecked();
Settings::values.graphics_api =
static_cast<Settings::GraphicsAPI>(ui->graphics_api_combo->currentIndex());
Settings::values.physical_device = static_cast<u16>(ui->physical_device_combo->currentIndex());
Settings::values.async_command_recording = ui->toggle_async_recording->isChecked();
}
void ConfigureGraphics::RetranslateUI() {
ui->retranslateUi(this);
}
void ConfigureGraphics::SetupPerGameUI() {
// Block the global settings if a game is currently running that overrides them
if (Settings::IsConfiguringGlobal()) {
ui->toggle_hw_renderer->setEnabled(Settings::values.use_hw_renderer.UsingGlobal());
ui->toggle_hw_shader->setEnabled(Settings::values.use_hw_shader.UsingGlobal());
ui->toggle_separable_shader->setEnabled(Settings::values.separable_shader.UsingGlobal());
ui->toggle_accurate_mul->setEnabled(Settings::values.shaders_accurate_mul.UsingGlobal());
ui->toggle_disk_shader_cache->setEnabled(
Settings::values.use_disk_shader_cache.UsingGlobal());
ui->toggle_vsync_new->setEnabled(Settings::values.use_vsync_new.UsingGlobal());
return;
}
ui->toggle_shader_jit->setVisible(false);
ConfigurationShared::SetColoredTristate(ui->toggle_hw_renderer,
Settings::values.use_hw_renderer, use_hw_renderer);
ConfigurationShared::SetColoredTristate(ui->toggle_hw_shader, Settings::values.use_hw_shader,
use_hw_shader);
ConfigurationShared::SetColoredTristate(ui->toggle_separable_shader,
Settings::values.separable_shader, separable_shader);
ConfigurationShared::SetColoredTristate(
ui->toggle_accurate_mul, Settings::values.shaders_accurate_mul, shaders_accurate_mul);
ConfigurationShared::SetColoredTristate(ui->toggle_disk_shader_cache,
Settings::values.use_disk_shader_cache,
use_disk_shader_cache);
ConfigurationShared::SetColoredTristate(ui->toggle_vsync_new, Settings::values.use_vsync_new,
use_vsync_new);
}
void ConfigureGraphics::DiscoverPhysicalDevices() {
Vulkan::Instance instance{};
const auto physical_devices = instance.GetPhysicalDevices();
@ -172,5 +121,4 @@ void ConfigureGraphics::SetPhysicalDeviceComboVisibility(int index) {
const bool is_visible = graphics_api == Settings::GraphicsAPI::Vulkan;
ui->physical_device_label->setVisible(is_visible);
ui->physical_device_combo->setVisible(is_visible);
ui->spirv_shader_gen->setVisible(is_visible);
}

View File

@ -11,10 +11,6 @@ namespace Ui {
class ConfigureGraphics;
}
namespace ConfigurationShared {
enum class CheckState;
}
class ConfigureGraphics : public QWidget {
Q_OBJECT
@ -28,20 +24,11 @@ public:
void UpdateBackgroundColorButton(const QColor& color);
void SetupPerGameUI();
private:
void DiscoverPhysicalDevices();
void SetPhysicalDeviceComboVisibility(int index);
ConfigurationShared::CheckState use_hw_renderer;
ConfigurationShared::CheckState use_hw_shader;
ConfigurationShared::CheckState separable_shader;
ConfigurationShared::CheckState shaders_accurate_mul;
ConfigurationShared::CheckState use_disk_shader_cache;
ConfigurationShared::CheckState use_vsync_new;
ConfigurationShared::CheckState async_command_recording;
ConfigurationShared::CheckState spirv_shader_gen;
private:
std::unique_ptr<Ui::ConfigureGraphics> ui;
QColor bg_color;
};

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>400</width>
<height>513</height>
<height>430</height>
</rect>
</property>
<property name="minimumSize">
@ -70,13 +70,6 @@
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="spirv_shader_gen">
<property name="text">
<string>SPIR-V Shader Generation</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>

View File

@ -7,7 +7,7 @@
#include "citra_qt/configuration/configure_hotkeys.h"
#include "citra_qt/hotkeys.h"
#include "citra_qt/util/sequence_dialog/sequence_dialog.h"
#include "common/settings.h"
#include "core/settings.h"
#include "ui_configure_hotkeys.h"
ConfigureHotkeys::ConfigureHotkeys(QWidget* parent)

View File

@ -195,21 +195,8 @@ ConfigureInput::ConfigureInput(QWidget* parent)
connect(button_map[button_id], &QPushButton::clicked, [this, button_id]() {
HandleClick(
button_map[button_id],
[this, button_id](Common::ParamPackage params) {
// Workaround for ZL & ZR for analog triggers like on XBOX controllors.
// Analog triggers (from controllers like the XBOX controller) would not
// work due to a different range of their signals (from 0 to 255 on
// analog triggers instead of -32768 to 32768 on analog joysticks). The
// SDL driver misinterprets analog triggers as analog joysticks.
// TODO: reinterpret the signal range for analog triggers to map the
// values correctly. This is required for the correct emulation of the
// analog triggers of the GameCube controller.
if (button_id == Settings::NativeButton::ZL ||
button_id == Settings::NativeButton::ZR) {
params.Set("direction", "+");
params.Set("threshold", "0.5");
}
buttons_param[button_id] = std::move(params);
[this, button_id](const Common::ParamPackage& params) {
buttons_param[button_id] = params;
// If the user closes the dialog, the changes are reverted in
// `GMainWindow::OnConfigure()`
ApplyConfiguration();

View File

@ -13,7 +13,7 @@
#include <QKeySequence>
#include <QWidget>
#include "common/param_package.h"
#include "common/settings.h"
#include "core/settings.h"
#include "input_common/main.h"
class QKeyEvent;

View File

@ -23,9 +23,8 @@ CalibrationConfigurationDialog::CalibrationConfigurationDialog(QWidget* parent,
status_label = new QLabel(tr("Communicating with the server..."));
cancel_button = new QPushButton(tr("Cancel"));
connect(cancel_button, &QPushButton::clicked, this, [this] {
if (!completed) {
if (!completed)
job->Stop();
}
accept();
});
layout->addWidget(status_label);
@ -67,33 +66,31 @@ CalibrationConfigurationDialog::CalibrationConfigurationDialog(QWidget* parent,
CalibrationConfigurationDialog::~CalibrationConfigurationDialog() = default;
void CalibrationConfigurationDialog::UpdateLabelText(const QString& text) {
void CalibrationConfigurationDialog::UpdateLabelText(QString text) {
status_label->setText(text);
}
void CalibrationConfigurationDialog::UpdateButtonText(const QString& text) {
void CalibrationConfigurationDialog::UpdateButtonText(QString text) {
cancel_button->setText(text);
}
constexpr std::array<std::pair<const char*, const char*>, 3> MotionProviders = {{
{"motion_emu", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "Mouse (Right Click)")},
{"cemuhookudp", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "CemuhookUDP")},
{"sdl", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "SDL")},
}};
const std::array<std::pair<const char*, const char*>, 3> MotionProviders = {
{{"motion_emu", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "Mouse (Right Click)")},
{"cemuhookudp", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "CemuhookUDP")},
{"sdl", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "SDL")}}};
constexpr std::array<std::pair<const char*, const char*>, 2> TouchProviders = {{
{"emu_window", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "Emulator Window")},
{"cemuhookudp", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "CemuhookUDP")},
}};
const std::array<std::pair<const char*, const char*>, 2> TouchProviders = {
{{"emu_window", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "Emulator Window")},
{"cemuhookudp", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "CemuhookUDP")}}};
ConfigureMotionTouch::ConfigureMotionTouch(QWidget* parent)
: QDialog(parent), ui(std::make_unique<Ui::ConfigureMotionTouch>()),
timeout_timer(std::make_unique<QTimer>()), poll_timer(std::make_unique<QTimer>()) {
ui->setupUi(this);
for (const auto& [provider, name] : MotionProviders) {
for (auto [provider, name] : MotionProviders) {
ui->motion_provider->addItem(tr(name), QString::fromUtf8(provider));
}
for (const auto& [provider, name] : TouchProviders) {
for (auto [provider, name] : TouchProviders) {
ui->touch_provider->addItem(tr(name), QString::fromUtf8(provider));
}
@ -128,10 +125,10 @@ ConfigureMotionTouch::ConfigureMotionTouch(QWidget* parent)
ConfigureMotionTouch::~ConfigureMotionTouch() = default;
void ConfigureMotionTouch::SetConfiguration() {
const Common::ParamPackage motion_param(Settings::values.current_input_profile.motion_device);
const Common::ParamPackage touch_param(Settings::values.current_input_profile.touch_device);
const std::string motion_engine = motion_param.Get("engine", "motion_emu");
const std::string touch_engine = touch_param.Get("engine", "emu_window");
Common::ParamPackage motion_param(Settings::values.current_input_profile.motion_device);
Common::ParamPackage touch_param(Settings::values.current_input_profile.touch_device);
std::string motion_engine = motion_param.Get("engine", "motion_emu");
std::string touch_engine = touch_param.Get("engine", "emu_window");
ui->motion_provider->setCurrentIndex(
ui->motion_provider->findData(QString::fromStdString(motion_engine)));
@ -162,8 +159,8 @@ void ConfigureMotionTouch::SetConfiguration() {
}
void ConfigureMotionTouch::UpdateUiDisplay() {
const std::string motion_engine = ui->motion_provider->currentData().toString().toStdString();
const std::string touch_engine = ui->touch_provider->currentData().toString().toStdString();
std::string motion_engine = ui->motion_provider->currentData().toString().toStdString();
std::string touch_engine = ui->touch_provider->currentData().toString().toStdString();
if (motion_engine == "motion_emu") {
ui->motion_sensitivity_label->setVisible(true);
@ -185,8 +182,9 @@ void ConfigureMotionTouch::UpdateUiDisplay() {
ui->touch_calibration->setVisible(true);
ui->touch_calibration_config->setVisible(true);
ui->touch_calibration_label->setVisible(true);
ui->touch_calibration->setText(
QStringLiteral("(%1, %2) - (%3, %4)").arg(min_x).arg(min_y).arg(max_x).arg(max_y));
ui->touch_calibration->setText(QStringLiteral("(%1, %2) - (%3, %4)")
.arg(QString::number(min_x), QString::number(min_y),
QString::number(max_x), QString::number(max_y)));
} else {
ui->touch_calibration->setVisible(false);
ui->touch_calibration_config->setVisible(false);
@ -201,9 +199,11 @@ void ConfigureMotionTouch::UpdateUiDisplay() {
}
void ConfigureMotionTouch::ConnectEvents() {
connect(ui->motion_provider, qOverload<int>(&QComboBox::currentIndexChanged), this,
connect(ui->motion_provider,
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
[this]([[maybe_unused]] int index) { UpdateUiDisplay(); });
connect(ui->touch_provider, qOverload<int>(&QComboBox::currentIndexChanged), this,
connect(ui->touch_provider,
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
[this]([[maybe_unused]] int index) { UpdateUiDisplay(); });
connect(ui->motion_controller_button, &QPushButton::clicked, this, [this]() {
if (QMessageBox::information(this, tr("Information"),
@ -235,9 +235,8 @@ void ConfigureMotionTouch::ConnectEvents() {
connect(ui->touch_from_button_config_btn, &QPushButton::clicked, this,
&ConfigureMotionTouch::OnConfigureTouchFromButton);
connect(ui->buttonBox, &QDialogButtonBox::rejected, this, [this] {
if (CanCloseDialog()) {
if (CanCloseDialog())
reject();
}
});
}
@ -276,15 +275,15 @@ void ConfigureMotionTouch::OnCemuhookUDPTest() {
void ConfigureMotionTouch::OnConfigureTouchCalibration() {
ui->touch_calibration_config->setEnabled(false);
ui->touch_calibration_config->setText(tr("Configuring"));
CalibrationConfigurationDialog dialog(
CalibrationConfigurationDialog* dialog = new CalibrationConfigurationDialog(
this, ui->udp_server->text().toStdString(), static_cast<u16>(ui->udp_port->text().toUInt()),
static_cast<u8>(ui->udp_pad_index->currentIndex()), 24872);
dialog.exec();
if (dialog.completed) {
min_x = dialog.min_x;
min_y = dialog.min_y;
max_x = dialog.max_x;
max_y = dialog.max_y;
dialog->exec();
if (dialog->completed) {
min_x = dialog->min_x;
min_y = dialog->min_y;
max_x = dialog->max_x;
max_y = dialog->max_y;
LOG_INFO(Frontend,
"UDP touchpad calibration config success: min_x={}, min_y={}, max_x={}, max_y={}",
min_x, min_y, max_x, max_y);
@ -297,11 +296,10 @@ void ConfigureMotionTouch::OnConfigureTouchCalibration() {
}
void ConfigureMotionTouch::closeEvent(QCloseEvent* event) {
if (CanCloseDialog()) {
if (CanCloseDialog())
event->accept();
} else {
else
event->ignore();
}
}
void ConfigureMotionTouch::ShowUDPTestResult(bool result) {
@ -347,15 +345,16 @@ bool ConfigureMotionTouch::CanCloseDialog() {
}
void ConfigureMotionTouch::ApplyConfiguration() {
if (!CanCloseDialog()) {
if (!CanCloseDialog())
return;
}
std::string motion_engine = ui->motion_provider->currentData().toString().toStdString();
std::string touch_engine = ui->touch_provider->currentData().toString().toStdString();
Common::ParamPackage motion_param{};
Common::ParamPackage motion_param{}, touch_param{};
motion_param.Set("engine", motion_engine);
touch_param.Set("engine", touch_engine);
if (motion_engine == "motion_emu") {
motion_param.Set("sensitivity", static_cast<float>(ui->motion_sensitivity->value()));
} else if (motion_engine == "sdl") {
@ -363,8 +362,6 @@ void ConfigureMotionTouch::ApplyConfiguration() {
motion_param.Set("port", port);
}
Common::ParamPackage touch_param{};
touch_param.Set("engine", touch_engine);
if (touch_engine == "cemuhookudp") {
touch_param.Set("min_x", min_x);
touch_param.Set("min_y", min_y);

View File

@ -7,7 +7,7 @@
#include <memory>
#include <QDialog>
#include "common/param_package.h"
#include "common/settings.h"
#include "core/settings.h"
#include "input_common/main.h"
#include "input_common/udp/udp.h"
@ -26,11 +26,11 @@ class CalibrationConfigurationDialog : public QDialog {
public:
explicit CalibrationConfigurationDialog(QWidget* parent, const std::string& host, u16 port,
u8 pad_index, u16 client_id);
~CalibrationConfigurationDialog() override;
~CalibrationConfigurationDialog();
private:
Q_INVOKABLE void UpdateLabelText(const QString& text);
Q_INVOKABLE void UpdateButtonText(const QString& text);
Q_INVOKABLE void UpdateLabelText(QString text);
Q_INVOKABLE void UpdateButtonText(QString text);
QVBoxLayout* layout;
QLabel* status_label;
@ -39,10 +39,7 @@ private:
// Configuration results
bool completed{};
u16 min_x{};
u16 min_y{};
u16 max_x{};
u16 max_y{};
u16 min_x, min_y, max_x, max_y;
friend class ConfigureMotionTouch;
};
@ -84,10 +81,7 @@ private:
std::optional<std::function<void(const Common::ParamPackage&)>> input_setter;
// Coordinate system of the CemuhookUDP touch provider
int min_x{};
int min_y{};
int max_x{};
int max_y{};
int min_x, min_y, max_x, max_y;
bool udp_test_in_progress{};

View File

@ -1,149 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <utility>
#include <vector>
#include <QMessageBox>
#include <QPushButton>
#include <QString>
#include <fmt/format.h>
#include "citra_qt/configuration/config.h"
#include "citra_qt/configuration/configure_audio.h"
#include "citra_qt/configuration/configure_general.h"
#include "citra_qt/configuration/configure_graphics.h"
#include "citra_qt/configuration/configure_per_game.h"
#include "citra_qt/configuration/configure_system.h"
#include "citra_qt/util/util.h"
#include "common/file_util.h"
#include "core/core.h"
#include "core/loader/loader.h"
#include "core/loader/smdh.h"
#include "ui_configure_per_game.h"
ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const QString& file_name,
Core::System& system_)
: QDialog(parent), ui(std::make_unique<Ui::ConfigurePerGame>()),
filename{file_name.toStdString()}, title_id{title_id_}, system{system_} {
const auto config_file_name = title_id == 0 ? filename : fmt::format("{:016X}", title_id);
game_config = std::make_unique<Config>(config_file_name, Config::ConfigType::PerGameConfig);
audio_tab = std::make_unique<ConfigureAudio>(this);
general_tab = std::make_unique<ConfigureGeneral>(this);
graphics_tab = std::make_unique<ConfigureGraphics>(this);
system_tab = std::make_unique<ConfigureSystem>(this);
ui->setupUi(this);
ui->tabWidget->addTab(general_tab.get(), tr("General"));
ui->tabWidget->addTab(system_tab.get(), tr("System"));
ui->tabWidget->addTab(graphics_tab.get(), tr("Graphics"));
ui->tabWidget->addTab(audio_tab.get(), tr("Audio"));
setFocusPolicy(Qt::ClickFocus);
setWindowTitle(tr("Properties"));
// remove Help question mark button from the title bar
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
scene = new QGraphicsScene;
ui->icon_view->setScene(scene);
if (system.IsPoweredOn()) {
QPushButton* apply_button = ui->buttonBox->addButton(QDialogButtonBox::Apply);
connect(apply_button, &QAbstractButton::clicked, this,
&ConfigurePerGame::HandleApplyButtonClicked);
}
connect(ui->button_reset_per_game, &QPushButton::clicked, this,
&ConfigurePerGame::ResetDefaults);
LoadConfiguration();
}
ConfigurePerGame::~ConfigurePerGame() = default;
void ConfigurePerGame::ResetDefaults() {
const auto config_file_name = title_id == 0 ? filename : fmt::format("{:016X}", title_id);
QMessageBox::StandardButton answer = QMessageBox::question(
this, tr("Citra"), tr("Are you sure you want to <b>reset your settings for this game</b>?"),
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
if (answer == QMessageBox::No) {
return;
}
FileUtil::Delete(fmt::format("{}/custom/{}.ini",
FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir),
config_file_name));
close();
}
void ConfigurePerGame::ApplyConfiguration() {
general_tab->ApplyConfiguration();
system_tab->ApplyConfiguration();
graphics_tab->ApplyConfiguration();
audio_tab->ApplyConfiguration();
Settings::LogSettings();
game_config->Save();
}
void ConfigurePerGame::changeEvent(QEvent* event) {
if (event->type() == QEvent::LanguageChange) {
RetranslateUI();
}
QDialog::changeEvent(event);
}
void ConfigurePerGame::RetranslateUI() {
ui->retranslateUi(this);
}
void ConfigurePerGame::HandleApplyButtonClicked() {
ApplyConfiguration();
}
static QPixmap GetQPixmapFromSMDH(std::vector<u8>& smdh_data) {
Loader::SMDH smdh;
memcpy(&smdh, smdh_data.data(), sizeof(Loader::SMDH));
bool large = true;
std::vector<u16> icon_data = smdh.GetIcon(large);
const uchar* data = reinterpret_cast<const uchar*>(icon_data.data());
int size = large ? 48 : 24;
QImage icon(data, size, size, QImage::Format::Format_RGB16);
return QPixmap::fromImage(icon);
}
void ConfigurePerGame::LoadConfiguration() {
if (filename.empty()) {
return;
}
ui->display_title_id->setText(
QStringLiteral("%1").arg(title_id, 16, 16, QLatin1Char{'0'}).toUpper());
const auto loader = Loader::GetLoader(filename);
std::string title;
if (loader->ReadTitle(title) == Loader::ResultStatus::Success)
ui->display_name->setText(QString::fromStdString(title));
std::vector<u8> bytes;
if (loader->ReadIcon(bytes) == Loader::ResultStatus::Success) {
scene->clear();
QPixmap map = GetQPixmapFromSMDH(bytes);
scene->addPixmap(map.scaled(ui->icon_view->width(), ui->icon_view->height(),
Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
}
ui->display_filepath->setText(QString::fromStdString(filename));
ui->display_format->setText(
QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType())));
const auto valueText = ReadableByteSize(FileUtil::GetSize(filename));
ui->display_size->setText(valueText);
}

View File

@ -1,69 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <memory>
#include <string>
#include <QDialog>
#include <QList>
#include "citra_qt/configuration/config.h"
namespace Core {
class System;
}
class ConfigureAudio;
class ConfigureGeneral;
class ConfigureGraphics;
class ConfigureSystem;
class QGraphicsScene;
class QStandardItem;
class QStandardItemModel;
class QTreeView;
class QVBoxLayout;
namespace Ui {
class ConfigurePerGame;
}
class ConfigurePerGame : public QDialog {
Q_OBJECT
public:
// Cannot use std::filesystem::path due to https://bugreports.qt.io/browse/QTBUG-73263
explicit ConfigurePerGame(QWidget* parent, u64 title_id_, const QString& file_name,
Core::System& system_);
~ConfigurePerGame() override;
/// Loads all button configurations to settings file
void LoadConfiguration();
/// Save all button configurations to settings file
void ApplyConfiguration();
/// Reset the settings for this game
void ResetDefaults();
private:
void changeEvent(QEvent* event) override;
void RetranslateUI();
void HandleApplyButtonClicked();
std::unique_ptr<Ui::ConfigurePerGame> ui;
std::string filename;
u64 title_id;
QGraphicsScene* scene;
std::unique_ptr<Config> game_config;
Core::System& system;
std::unique_ptr<ConfigureAudio> audio_tab;
std::unique_ptr<ConfigureGeneral> general_tab;
std::unique_ptr<ConfigureGraphics> graphics_tab;
std::unique_ptr<ConfigureSystem> system_tab;
};

View File

@ -1,271 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ConfigurePerGame</class>
<widget class="QDialog" name="ConfigurePerGame">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>900</width>
<height>661</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>900</width>
<height>0</height>
</size>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Info</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QGraphicsView" name="icon_view">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>128</width>
<height>128</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>128</width>
<height>128</height>
</size>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="interactive">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QGridLayout" name="gridLayout_2">
<item row="4" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Size</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLineEdit" name="display_filepath">
<property name="enabled">
<bool>true</bool>
</property>
<property name="minimumSize">
<size>
<width>160</width>
<height>0</height>
</size>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Format</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Name</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="display_size">
<property name="enabled">
<bool>true</bool>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Filepath</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Title ID</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="display_title_id">
<property name="enabled">
<bool>true</bool>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="display_name">
<property name="enabled">
<bool>true</bool>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="display_format">
<property name="enabled">
<bool>true</bool>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="button_reset_per_game">
<property name="text">
<string>Reset Game Settings</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="VerticalLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout_2"/>
</item>
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="enabled">
<bool>true</bool>
</property>
<property name="currentIndex">
<number>-1</number>
</property>
<property name="usesScrollButtons">
<bool>true</bool>
</property>
<property name="documentMode">
<bool>false</bool>
</property>
<property name="tabsClosable">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>ConfigurePerGame</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>20</x>
<y>20</y>
</hint>
<hint type="destinationlabel">
<x>20</x>
<y>20</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>ConfigurePerGame</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>20</x>
<y>20</y>
</hint>
<hint type="destinationlabel">
<x>20</x>
<y>20</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -6,8 +6,8 @@
#include <QFileDialog>
#include <QUrl>
#include "citra_qt/configuration/configure_storage.h"
#include "common/settings.h"
#include "core/core.h"
#include "core/settings.h"
#include "ui_configure_storage.h"
ConfigureStorage::ConfigureStorage(QWidget* parent)
@ -16,33 +16,33 @@ ConfigureStorage::ConfigureStorage(QWidget* parent)
SetConfiguration();
connect(ui->open_nand_dir, &QPushButton::clicked, []() {
QString path = QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir));
QString path = QString::fromStdString(Common::FS::GetUserPath(Common::FS::UserPath::NANDDir));
QDesktopServices::openUrl(QUrl::fromLocalFile(path));
});
connect(ui->change_nand_dir, &QPushButton::clicked, this, [this]() {
const QString dir_path = QFileDialog::getExistingDirectory(
this, tr("Select NAND Directory"),
QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir)),
QString::fromStdString(Common::FS::GetUserPath(Common::FS::UserPath::NANDDir)),
QFileDialog::ShowDirsOnly);
if (!dir_path.isEmpty()) {
FileUtil::UpdateUserPath(FileUtil::UserPath::NANDDir, dir_path.toStdString());
Common::FS::UpdateUserPath(Common::FS::UserPath::NANDDir, dir_path.toStdString());
SetConfiguration();
}
});
connect(ui->open_sdmc_dir, &QPushButton::clicked, []() {
QString path = QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir));
QString path = QString::fromStdString(Common::FS::GetUserPath(Common::FS::UserPath::SDMCDir));
QDesktopServices::openUrl(QUrl::fromLocalFile(path));
});
connect(ui->change_sdmc_dir, &QPushButton::clicked, this, [this]() {
const QString dir_path = QFileDialog::getExistingDirectory(
this, tr("Select SDMC Directory"),
QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir)),
QString::fromStdString(Common::FS::GetUserPath(Common::FS::UserPath::SDMCDir)),
QFileDialog::ShowDirsOnly);
if (!dir_path.isEmpty()) {
FileUtil::UpdateUserPath(FileUtil::UserPath::SDMCDir, dir_path.toStdString());
Common::FS::UpdateUserPath(Common::FS::UserPath::SDMCDir, dir_path.toStdString());
SetConfiguration();
}
});
@ -60,19 +60,19 @@ ConfigureStorage::ConfigureStorage(QWidget* parent)
ConfigureStorage::~ConfigureStorage() = default;
void ConfigureStorage::SetConfiguration() {
ui->nand_group->setVisible(Settings::values.use_custom_storage.GetValue());
QString nand_path = QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir));
ui->nand_group->setVisible(Settings::values.use_custom_storage);
QString nand_path = QString::fromStdString(Common::FS::GetUserPath(Common::FS::UserPath::NANDDir));
ui->nand_dir_path->setText(nand_path);
ui->open_nand_dir->setEnabled(!nand_path.isEmpty());
ui->sdmc_group->setVisible(Settings::values.use_virtual_sd &&
Settings::values.use_custom_storage);
QString sdmc_path = QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir));
QString sdmc_path = QString::fromStdString(Common::FS::GetUserPath(Common::FS::UserPath::SDMCDir));
ui->sdmc_dir_path->setText(sdmc_path);
ui->open_sdmc_dir->setEnabled(!sdmc_path.isEmpty());
ui->toggle_virtual_sd->setChecked(Settings::values.use_virtual_sd.GetValue());
ui->toggle_custom_storage->setChecked(Settings::values.use_custom_storage.GetValue());
ui->toggle_virtual_sd->setChecked(Settings::values.use_virtual_sd);
ui->toggle_custom_storage->setChecked(Settings::values.use_custom_storage);
ui->storage_group->setEnabled(!Core::System::GetInstance().IsPoweredOn());
}
@ -82,10 +82,10 @@ void ConfigureStorage::ApplyConfiguration() {
Settings::values.use_custom_storage = ui->toggle_custom_storage->isChecked();
if (!Settings::values.use_custom_storage) {
FileUtil::UpdateUserPath(FileUtil::UserPath::NANDDir,
GetDefaultUserPath(FileUtil::UserPath::NANDDir));
FileUtil::UpdateUserPath(FileUtil::UserPath::SDMCDir,
GetDefaultUserPath(FileUtil::UserPath::SDMCDir));
Common::FS::UpdateUserPath(Common::FS::UserPath::NANDDir,
GetDefaultUserPath(Common::FS::UserPath::NANDDir));
Common::FS::UpdateUserPath(Common::FS::UserPath::SDMCDir,
GetDefaultUserPath(Common::FS::UserPath::SDMCDir));
}
}

View File

@ -4,12 +4,12 @@
#include <cstring>
#include <QMessageBox>
#include "citra_qt/configuration/configuration_shared.h"
#include "citra_qt/configuration/configure_system.h"
#include "common/settings.h"
#include "citra_qt/uisettings.h"
#include "core/core.h"
#include "core/hle/service/cfg/cfg.h"
#include "core/hle/service/ptm/ptm.h"
#include "core/settings.h"
#include "ui_configure_system.h"
static const std::array<int, 12> days_in_month = {{
@ -249,14 +249,10 @@ ConfigureSystem::ConfigureSystem(QWidget* parent)
// This scales across DPIs. (This value should be enough for "xxx%")
ui->clock_display_label->setMinimumWidth(40);
connect(ui->slider_clock_speed, &QSlider::valueChanged, this, [&](int value) {
connect(ui->slider_clock_speed, &QSlider::valueChanged, [&](int value) {
ui->clock_display_label->setText(QStringLiteral("%1%").arg(SliderToSettings(value)));
});
ui->clock_speed_label->setVisible(Settings::IsConfiguringGlobal());
ui->clock_speed_combo->setVisible(!Settings::IsConfiguringGlobal());
SetupPerGameUI();
ConfigureTime();
}
@ -265,19 +261,11 @@ ConfigureSystem::~ConfigureSystem() = default;
void ConfigureSystem::SetConfiguration() {
enabled = !Core::System::GetInstance().IsPoweredOn();
ui->combo_init_clock->setCurrentIndex(static_cast<u8>(Settings::values.init_clock.GetValue()));
ui->combo_init_clock->setCurrentIndex(static_cast<u8>(Settings::values.init_clock));
QDateTime date_time;
date_time.setTime_t(Settings::values.init_time.GetValue());
date_time.setTime_t(Settings::values.init_time);
ui->edit_init_time->setDateTime(date_time);
long long init_time_offset = Settings::values.init_time_offset.GetValue();
long long days_offset = init_time_offset / 86400;
ui->edit_init_time_offset_days->setValue(days_offset);
unsigned long long time_offset = std::abs(init_time_offset) - std::abs(days_offset * 86400);
QTime time = QTime::fromMSecsSinceStartOfDay(time_offset * 1000);
ui->edit_init_time_offset_time->setTime(time);
if (!enabled) {
cfg = Service::CFG::GetModule(Core::System::GetInstance());
ASSERT_MSG(cfg, "CFG Module missing!");
@ -291,31 +279,20 @@ void ConfigureSystem::SetConfiguration() {
ui->label_disable_info->hide();
}
if (!Settings::IsConfiguringGlobal()) {
if (Settings::values.cpu_clock_percentage.UsingGlobal()) {
ui->clock_speed_combo->setCurrentIndex(0);
ui->slider_clock_speed->setEnabled(false);
} else {
ui->clock_speed_combo->setCurrentIndex(1);
ui->slider_clock_speed->setEnabled(true);
}
ConfigurationShared::SetHighlight(ui->clock_speed_widget,
!Settings::values.cpu_clock_percentage.UsingGlobal());
}
ui->slider_clock_speed->setValue(
SettingsToSlider(Settings::values.cpu_clock_percentage.GetValue()));
ui->slider_clock_speed->setValue(SettingsToSlider(Settings::values.cpu_clock_percentage));
ui->clock_display_label->setText(
QStringLiteral("%1%").arg(Settings::values.cpu_clock_percentage.GetValue()));
ui->toggle_new_3ds->setChecked(Settings::values.is_new_3ds.GetValue());
ui->plugin_loader->setChecked(Settings::values.plugin_loader_enabled.GetValue());
ui->allow_plugin_loader->setChecked(Settings::values.allow_plugin_loader.GetValue());
QStringLiteral("%1%").arg(Settings::values.cpu_clock_percentage));
ui->toggle_new_3ds->setChecked(Settings::values.is_new_3ds);
}
void ConfigureSystem::ReadSystemSettings() {
// set username
username = cfg->GetUsername();
ui->edit_username->setText(QString::fromStdU16String(username));
// TODO(wwylele): Use this when we move to Qt 5.5
// ui->edit_username->setText(QString::fromStdU16String(username));
ui->edit_username->setText(
QString::fromUtf16(reinterpret_cast<const ushort*>(username.data())));
// set birthday
std::tie(birthmonth, birthday) = cfg->GetBirthday();
@ -352,29 +329,32 @@ void ConfigureSystem::ApplyConfiguration() {
bool modified = false;
// apply username
std::u16string new_username = ui->edit_username->text().toStdU16String();
// TODO(wwylele): Use this when we move to Qt 5.5
// std::u16string new_username = ui->edit_username->text().toStdU16String();
std::u16string new_username(
reinterpret_cast<const char16_t*>(ui->edit_username->text().utf16()));
if (new_username != username) {
cfg->SetUsername(new_username);
modified = true;
}
// apply birthday
s32 new_birthmonth = ui->combo_birthmonth->currentIndex() + 1;
s32 new_birthday = ui->combo_birthday->currentIndex() + 1;
int new_birthmonth = ui->combo_birthmonth->currentIndex() + 1;
int new_birthday = ui->combo_birthday->currentIndex() + 1;
if (birthmonth != new_birthmonth || birthday != new_birthday) {
cfg->SetBirthday(new_birthmonth, new_birthday);
modified = true;
}
// apply language
s32 new_language = ui->combo_language->currentIndex();
int new_language = ui->combo_language->currentIndex();
if (language_index != new_language) {
cfg->SetSystemLanguage(static_cast<Service::CFG::SystemLanguage>(new_language));
modified = true;
}
// apply sound
s32 new_sound = ui->combo_sound->currentIndex();
int new_sound = ui->combo_sound->currentIndex();
if (sound_index != new_sound) {
cfg->SetSoundOutputMode(static_cast<Service::CFG::SoundOutputMode>(new_sound));
modified = true;
@ -398,30 +378,15 @@ void ConfigureSystem::ApplyConfiguration() {
cfg->UpdateConfigNANDSavegame();
}
ConfigurationShared::ApplyPerGameSetting(&Settings::values.is_new_3ds, ui->toggle_new_3ds,
is_new_3ds);
Settings::values.init_clock =
static_cast<Settings::InitClock>(ui->combo_init_clock->currentIndex());
Settings::values.init_time = ui->edit_init_time->dateTime().toTime_t();
s64 time_offset_time = ui->edit_init_time_offset_time->time().msecsSinceStartOfDay() / 1000;
s64 time_offset_days = ui->edit_init_time_offset_days->value() * 86400;
if (time_offset_days < 0) {
time_offset_time = -time_offset_time;
}
Settings::values.init_time_offset = time_offset_days + time_offset_time;
Settings::values.is_new_3ds = ui->toggle_new_3ds->isChecked();
Settings::values.plugin_loader_enabled.SetValue(ui->plugin_loader->isChecked());
Settings::values.allow_plugin_loader.SetValue(ui->allow_plugin_loader->isChecked());
}
ConfigurationShared::ApplyPerGameSetting(
&Settings::values.cpu_clock_percentage, ui->clock_speed_combo,
[this](s32) { return SliderToSettings(ui->slider_clock_speed->value()); });
Settings::values.cpu_clock_percentage = SliderToSettings(ui->slider_clock_speed->value());
Settings::Apply();
}
void ConfigureSystem::UpdateBirthdayComboBox(int birthmonth_index) {
@ -429,10 +394,10 @@ void ConfigureSystem::UpdateBirthdayComboBox(int birthmonth_index) {
return;
// store current day selection
s32 birthday_index = ui->combo_birthday->currentIndex();
int birthday_index = ui->combo_birthday->currentIndex();
// get number of days in the new selected month
s32 days = days_in_month[birthmonth_index];
int days = days_in_month[birthmonth_index];
// if the selected day is out of range,
// reset it to 1st
@ -441,7 +406,7 @@ void ConfigureSystem::UpdateBirthdayComboBox(int birthmonth_index) {
// update the day combo box
ui->combo_birthday->clear();
for (s32 i = 1; i <= days; ++i) {
for (int i = 1; i <= days; ++i) {
ui->combo_birthday->addItem(QString::number(i));
}
@ -450,10 +415,10 @@ void ConfigureSystem::UpdateBirthdayComboBox(int birthmonth_index) {
}
void ConfigureSystem::ConfigureTime() {
ui->edit_init_time->setCalendarPopup(true);
QDateTime dt;
dt.fromString(QStringLiteral("2000-01-01 00:00:01"), QStringLiteral("yyyy-MM-dd hh:mm:ss"));
ui->edit_init_time->setMinimumDateTime(dt);
ui->edit_init_time->setCalendarPopup(true);
SetConfiguration();
@ -461,16 +426,10 @@ void ConfigureSystem::ConfigureTime() {
}
void ConfigureSystem::UpdateInitTime(int init_clock) {
const bool is_global = Settings::IsConfiguringGlobal();
const bool is_fixed_time =
static_cast<Settings::InitClock>(init_clock) == Settings::InitClock::FixedTime;
ui->label_init_time->setVisible(is_fixed_time && is_global);
ui->edit_init_time->setVisible(is_fixed_time && is_global);
ui->label_init_time_offset->setVisible(!is_fixed_time && is_global);
ui->edit_init_time_offset_days->setVisible(!is_fixed_time && is_global);
ui->edit_init_time_offset_time->setVisible(!is_fixed_time && is_global);
ui->label_init_time->setVisible(is_fixed_time);
ui->edit_init_time->setVisible(is_fixed_time);
}
void ConfigureSystem::RefreshConsoleID() {
@ -495,50 +454,3 @@ void ConfigureSystem::RefreshConsoleID() {
void ConfigureSystem::RetranslateUI() {
ui->retranslateUi(this);
}
void ConfigureSystem::SetupPerGameUI() {
// Block the global settings if a game is currently running that overrides them
if (Settings::IsConfiguringGlobal()) {
ui->toggle_new_3ds->setEnabled(Settings::values.is_new_3ds.UsingGlobal());
ui->slider_clock_speed->setEnabled(Settings::values.cpu_clock_percentage.UsingGlobal());
return;
}
// Hide most settings for now, we can implement them later
ui->label_username->setVisible(false);
ui->label_birthday->setVisible(false);
ui->label_init_clock->setVisible(false);
ui->label_init_time->setVisible(false);
ui->label_console_id->setVisible(false);
ui->label_sound->setVisible(false);
ui->label_language->setVisible(false);
ui->label_country->setVisible(false);
ui->label_play_coins->setVisible(false);
ui->edit_username->setVisible(false);
ui->spinBox_play_coins->setVisible(false);
ui->combo_birthday->setVisible(false);
ui->combo_birthmonth->setVisible(false);
ui->combo_init_clock->setVisible(false);
ui->combo_sound->setVisible(false);
ui->combo_language->setVisible(false);
ui->combo_country->setVisible(false);
ui->label_init_time_offset->setVisible(false);
ui->edit_init_time_offset_days->setVisible(false);
ui->edit_init_time_offset_time->setVisible(false);
ui->button_regenerate_console_id->setVisible(false);
// Apps can change the state of the plugin loader, so plugins load
// to a chainloaded app with specific parameters. Don't allow
// the plugin loader state to be configured per-game as it may
// mess things up.
ui->label_plugin_loader->setVisible(false);
ui->plugin_loader->setVisible(false);
ui->allow_plugin_loader->setVisible(false);
connect(ui->clock_speed_combo, qOverload<int>(&QComboBox::activated), this, [this](int index) {
ui->slider_clock_speed->setEnabled(index == 1);
ConfigurationShared::SetHighlight(ui->clock_speed_widget, index == 1);
});
ConfigurationShared::SetColoredTristate(ui->toggle_new_3ds, Settings::values.is_new_3ds,
is_new_3ds);
}

View File

@ -12,10 +12,6 @@ namespace Ui {
class ConfigureSystem;
}
namespace ConfigurationShared {
enum class CheckState;
}
namespace Service {
namespace CFG {
class Module;
@ -41,9 +37,6 @@ private:
void UpdateInitTime(int init_clock);
void RefreshConsoleID();
void SetupPerGameUI();
ConfigurationShared::CheckState is_new_3ds;
std::unique_ptr<Ui::ConfigureSystem> ui;
bool enabled = false;

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>525</width>
<height>619</height>
<width>520</width>
<height>564</height>
</rect>
</property>
<property name="windowTitle">
@ -258,44 +258,6 @@
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QDateTimeEdit" name="edit_init_time">
<property name="displayFormat">
<string>yyyy-MM-ddTHH:mm:ss</string>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="label_init_time_offset">
<property name="text">
<string>Offset time</string>
</property>
</widget>
</item>
<item row="8" column="1">
<layout class="QGridLayout" name="edit_init_time_offset_grid">
<item column="0">
<widget class="QSpinBox" name="edit_init_time_offset_days">
<property name="suffix">
<string> days</string>
</property>
<property name="minimum">
<number>-2147483648</number>
</property>
<property name="maximum">
<number>2147483647</number>
</property>
</widget>
</item>
<item column="1">
<widget class="QTimeEdit" name="edit_init_time_offset_time">
<property name="displayFormat">
<string>HH:mm:ss</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="9" column="1">
<widget class="QSpinBox" name="spinBox_play_coins">
<property name="maximum">
@ -333,6 +295,13 @@
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QDateTimeEdit" name="edit_init_time">
<property name="displayFormat">
<string>yyyy-MM-ddTHH:mm:ss</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="toggle_new_3ds">
<property name="text">
@ -340,102 +309,58 @@
</property>
</widget>
</item>
<item row="13" column="0">
<widget class="QLabel" name="label_plugin_loader">
<property name="text">
<string>3GX Plugin Loader:</string>
</property>
</widget>
</item>
<item row="13" column="1">
<widget class="QCheckBox" name="plugin_loader">
<property name="text">
<string>Enable 3GX plugin loader</string>
</property>
</widget>
</item>
<item row="14" column="1">
<widget class="QCheckBox" name="allow_plugin_loader">
<property name="text">
<string>Allow games to change plugin loader state</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="group_advanced">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Advanced</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QWidget" name="clock_speed_widget" native="true">
<layout class="QHBoxLayout" name="clock_speed_layout">
<property name="spacing">
<number>7</number>
</property>
<item>
<widget class="QComboBox" name="clock_speed_combo">
<item>
<property name="text">
<string>Use global clock speed</string>
</property>
</item>
<item>
<property name="text">
<string>Set clock speed:</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QLabel" name="clock_speed_label">
<property name="text">
<string>CPU Clock Speed</string>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="slider_clock_speed">
<property name="toolTip">
<string>&lt;html&gt;&lt;body&gt;Changes the emulated CPU clock frequency.&lt;br&gt;Underclocking can increase performance but may cause the game to freeze.&lt;br&gt;Overclocking may reduce in game lag but also might cause freezes&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>79</number>
</property>
<property name="singleStep">
<number>5</number>
</property>
<property name="pageStep">
<number>15</number>
</property>
<property name="value">
<number>25</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="tickPosition">
<enum>QSlider::TicksBelow</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="clock_display_label">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
<widget class="QLabel" name="label_3">
<property name="text">
<string>CPU Clock Speed</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QSlider" name="slider_clock_speed">
<property name="toolTip">
<string>&lt;html&gt;&lt;body&gt;Changes the emulated CPU clock frequency.&lt;br&gt;Underclocking can increase performance but may cause the game to freeze.&lt;br&gt;Overclocking may reduce in game lag but also might cause freezes&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>79</number>
</property>
<property name="singleStep">
<number>5</number>
</property>
<property name="pageStep">
<number>15</number>
</property>
<property name="value">
<number>25</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="tickPosition">
<enum>QSlider::TicksBelow</enum>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="clock_display_label">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
@ -493,6 +418,7 @@
<tabstop>edit_init_time</tabstop>
<tabstop>spinBox_play_coins</tabstop>
<tabstop>button_regenerate_console_id</tabstop>
<tabstop>slider_clock_speed</tabstop>
</tabstops>
<resources/>
<connections/>

View File

@ -73,11 +73,11 @@ ConfigureTouchFromButton::ConfigureTouchFromButton(
: QDialog(parent), ui(std::make_unique<Ui::ConfigureTouchFromButton>()), touch_maps(touch_maps),
selected_index(default_index), timeout_timer(std::make_unique<QTimer>()),
poll_timer(std::make_unique<QTimer>()) {
ui->setupUi(this);
binding_list_model = new QStandardItemModel(0, 3, this);
binding_list_model->setHorizontalHeaderLabels(
{tr("Button"), tr("X", "X axis"), tr("Y", "Y axis")});
ui->binding_list->setModel(binding_list_model);
binding_list_model = std::make_unique<QStandardItemModel>(0, 3, this);
binding_list_model->setHorizontalHeaderLabels({tr("Button"), tr("X"), tr("Y")});
ui->binding_list->setModel(binding_list_model.get());
ui->bottom_screen->SetCoordLabel(ui->coord_label);
SetConfiguration();
@ -93,12 +93,11 @@ void ConfigureTouchFromButton::showEvent(QShowEvent* ev) {
// width values are not valid in the constructor
const int w =
ui->binding_list->viewport()->contentsRect().width() / binding_list_model->columnCount();
if (w <= 0) {
return;
if (w > 0) {
ui->binding_list->setColumnWidth(0, w);
ui->binding_list->setColumnWidth(1, w);
ui->binding_list->setColumnWidth(2, w);
}
ui->binding_list->setColumnWidth(0, w);
ui->binding_list->setColumnWidth(1, w);
ui->binding_list->setColumnWidth(2, w);
}
void ConfigureTouchFromButton::SetConfiguration() {
@ -124,7 +123,7 @@ void ConfigureTouchFromButton::UpdateUiDisplay() {
QStandardItem* ycoord = new QStandardItem(QString::number(package.Get("y", 0)));
binding_list_model->appendRow({button, xcoord, ycoord});
const int dot = ui->bottom_screen->AddDot(package.Get("x", 0), package.Get("y", 0));
int dot = ui->bottom_screen->AddDot(package.Get("x", 0), package.Get("y", 0));
button->setData(dot, DataRoleDot);
}
}
@ -146,7 +145,7 @@ void ConfigureTouchFromButton::ConnectEvents() {
&ConfigureTouchFromButton::EditBinding);
connect(ui->binding_list->selectionModel(), &QItemSelectionModel::selectionChanged, this,
&ConfigureTouchFromButton::OnBindingSelection);
connect(binding_list_model, &QStandardItemModel::itemChanged, this,
connect(binding_list_model.get(), &QStandardItemModel::itemChanged, this,
&ConfigureTouchFromButton::OnBindingChanged);
connect(ui->binding_list->model(), &QStandardItemModel::rowsAboutToBeRemoved, this,
&ConfigureTouchFromButton::OnBindingDeleted);
@ -233,7 +232,7 @@ void ConfigureTouchFromButton::GetButtonInput(const int row_index, const bool is
input_setter = [this, row_index, is_new](const Common::ParamPackage& params,
const bool cancel) {
auto* cell = binding_list_model->item(row_index, 0);
auto cell = binding_list_model->item(row_index, 0);
if (cancel) {
if (is_new) {
binding_list_model->removeRow(row_index);
@ -261,15 +260,15 @@ void ConfigureTouchFromButton::GetButtonInput(const int row_index, const bool is
}
void ConfigureTouchFromButton::NewBinding(const QPoint& pos) {
auto* button = new QStandardItem();
QStandardItem* button = new QStandardItem();
button->setEditable(false);
auto* x_coord = new QStandardItem(QString::number(pos.x()));
auto* y_coord = new QStandardItem(QString::number(pos.y()));
QStandardItem* xcoord = new QStandardItem(QString::number(pos.x()));
QStandardItem* ycoord = new QStandardItem(QString::number(pos.y()));
const int dot_id = ui->bottom_screen->AddDot(pos.x(), pos.y());
button->setData(dot_id, DataRoleDot);
binding_list_model->appendRow({button, x_coord, y_coord});
binding_list_model->appendRow({button, xcoord, ycoord});
ui->binding_list->setFocus();
ui->binding_list->setCurrentIndex(button->index());
@ -284,11 +283,11 @@ void ConfigureTouchFromButton::EditBinding(const QModelIndex& qi) {
void ConfigureTouchFromButton::DeleteBinding() {
const int row_index = ui->binding_list->currentIndex().row();
if (row_index < 0) {
return;
if (row_index >= 0) {
ui->bottom_screen->RemoveDot(
binding_list_model->index(row_index, 0).data(DataRoleDot).toInt());
binding_list_model->removeRow(row_index);
}
ui->bottom_screen->RemoveDot(binding_list_model->index(row_index, 0).data(DataRoleDot).toInt());
binding_list_model->removeRow(row_index);
}
void ConfigureTouchFromButton::OnBindingSelection(const QItemSelection& selected,
@ -330,7 +329,7 @@ void ConfigureTouchFromButton::OnBindingChanged(QStandardItem* item) {
void ConfigureTouchFromButton::OnBindingDeleted([[maybe_unused]] const QModelIndex& parent,
int first, int last) {
for (int i = first; i <= last; ++i) {
const auto ix = binding_list_model->index(i, 0);
auto ix = binding_list_model->index(i, 0);
if (!ix.isValid()) {
return;
}
@ -423,7 +422,7 @@ int TouchScreenPreview::AddDot(const int device_x, const int device_y) {
dot_font.setStyleHint(QFont::Monospace);
dot_font.setPointSize(20);
auto* dot = new QLabel(this);
QLabel* dot = new QLabel(this);
dot->setAttribute(Qt::WA_TranslucentBackground);
dot->setFont(dot_font);
dot->setText(QChar(0xD7)); // U+00D7 Multiplication Sign
@ -441,14 +440,13 @@ int TouchScreenPreview::AddDot(const int device_x, const int device_y) {
}
void TouchScreenPreview::RemoveDot(const int id) {
const auto iter = std::find_if(dots.begin(), dots.end(),
[id](const auto& entry) { return entry.first == id; });
if (iter == dots.cend()) {
return;
for (auto dot_it = dots.begin(); dot_it != dots.end(); ++dot_it) {
if (dot_it->first == id) {
dot_it->second->deleteLater();
dots.erase(dot_it);
return;
}
}
iter->second->deleteLater();
dots.erase(iter);
}
void TouchScreenPreview::HighlightDot(const int id, const bool active) const {
@ -472,15 +470,14 @@ void TouchScreenPreview::HighlightDot(const int id, const bool active) const {
}
void TouchScreenPreview::MoveDot(const int id, const int device_x, const int device_y) const {
const auto iter = std::find_if(dots.begin(), dots.end(),
[id](const auto& entry) { return entry.first == id; });
if (iter == dots.cend()) {
return;
for (const auto& dot : dots) {
if (dot.first == id) {
dot.second->setProperty(PropX, device_x);
dot.second->setProperty(PropY, device_y);
PositionDot(dot.second, device_x, device_y);
return;
}
}
iter->second->setProperty(PropX, device_x);
iter->second->setProperty(PropY, device_y);
PositionDot(iter->second, device_x, device_y);
}
void TouchScreenPreview::resizeEvent(QResizeEvent* event) {
@ -524,12 +521,11 @@ void TouchScreenPreview::leaveEvent([[maybe_unused]] QEvent* event) {
}
void TouchScreenPreview::mousePressEvent(QMouseEvent* event) {
if (event->button() != Qt::MouseButton::LeftButton) {
return;
}
const auto pos = MapToDeviceCoords(event->x(), event->y());
if (pos) {
emit DotAdded(*pos);
if (event->button() == Qt::MouseButton::LeftButton) {
const auto pos = MapToDeviceCoords(event->x(), event->y());
if (pos) {
emit DotAdded(*pos);
}
}
}
@ -604,17 +600,12 @@ std::optional<QPoint> TouchScreenPreview::MapToDeviceCoords(const int screen_x,
void TouchScreenPreview::PositionDot(QLabel* const dot, const int device_x,
const int device_y) const {
const float device_coord_x =
static_cast<float>(device_x >= 0 ? device_x : dot->property(PropX).toInt());
const int x_coord = static_cast<int>(
device_coord_x * (contentsRect().width() - 1) / (Core::kScreenBottomWidth - 1) +
contentsMargins().left() - static_cast<float>(dot->width()) / 2 + 0.5f);
const float device_coord_y =
static_cast<float>(device_y >= 0 ? device_y : dot->property(PropY).toInt());
const int y_coord = static_cast<int>(
device_coord_y * (contentsRect().height() - 1) / (Core::kScreenBottomHeight - 1) +
contentsMargins().top() - static_cast<float>(dot->height()) / 2 + 0.5f);
dot->move(x_coord, y_coord);
dot->move(static_cast<int>(
static_cast<float>(device_x >= 0 ? device_x : dot->property(PropX).toInt()) *
(contentsRect().width() - 1) / (Core::kScreenBottomWidth - 1) +
contentsMargins().left() - static_cast<float>(dot->width()) / 2 + 0.5f),
static_cast<int>(
static_cast<float>(device_y >= 0 ? device_y : dot->property(PropY).toInt()) *
(contentsRect().height() - 1) / (Core::kScreenBottomHeight - 1) +
contentsMargins().top() - static_cast<float>(dot->height()) / 2 + 0.5f));
}

View File

@ -9,7 +9,7 @@
#include <optional>
#include <vector>
#include <QDialog>
#include "common/settings.h"
#include "core/settings.h"
class QItemSelection;
class QModelIndex;
@ -50,8 +50,8 @@ public slots:
void SetCoordinates(int dot_id, const QPoint& pos);
protected:
void showEvent(QShowEvent* ev) override;
void keyPressEvent(QKeyEvent* event) override;
virtual void showEvent(QShowEvent* ev) override;
virtual void keyPressEvent(QKeyEvent* event) override;
private slots:
void NewMapping();
@ -72,7 +72,7 @@ private:
void SaveCurrentMapping();
std::unique_ptr<Ui::ConfigureTouchFromButton> ui;
QStandardItemModel* binding_list_model;
std::unique_ptr<QStandardItemModel> binding_list_model;
std::vector<Settings::TouchFromButtonMap> touch_maps;
int selected_index;

View File

@ -33,11 +33,11 @@ signals:
void DotMoved(int dot_id, const QPoint& pos);
protected:
void resizeEvent(QResizeEvent*) override;
void mouseMoveEvent(QMouseEvent*) override;
void leaveEvent(QEvent*) override;
void mousePressEvent(QMouseEvent*) override;
bool eventFilter(QObject*, QEvent*) override;
virtual void resizeEvent(QResizeEvent*) override;
virtual void mouseMoveEvent(QMouseEvent*) override;
virtual void leaveEvent(QEvent*) override;
virtual void mousePressEvent(QMouseEvent*) override;
virtual bool eventFilter(QObject*, QEvent*) override;
private:
std::optional<QPoint> MapToDeviceCoords(int screen_x, int screen_y) const;
@ -53,10 +53,9 @@ private:
static constexpr char PropX[] = "device_x";
static constexpr char PropY[] = "device_y";
struct DragState {
struct {
bool active = false;
QPointer<QLabel> dot;
QPoint start_pos;
};
DragState drag_state;
} drag_state;
};

View File

@ -46,14 +46,12 @@ void ConfigureUi::SetConfiguration() {
ui->language_combobox->setCurrentIndex(
ui->language_combobox->findData(UISettings::values.language));
ui->icon_size_combobox->setCurrentIndex(
static_cast<int>(UISettings::values.game_list_icon_size.GetValue()));
ui->row_1_text_combobox->setCurrentIndex(
static_cast<int>(UISettings::values.game_list_row_1.GetValue()));
ui->row_2_text_combobox->setCurrentIndex(
static_cast<int>(UISettings::values.game_list_row_2.GetValue()) + 1);
ui->toggle_hide_no_icon->setChecked(UISettings::values.game_list_hide_no_icon.GetValue());
ui->toggle_single_line_mode->setChecked(
UISettings::values.game_list_single_line_mode.GetValue());
static_cast<int>(UISettings::values.game_list_icon_size));
ui->row_1_text_combobox->setCurrentIndex(static_cast<int>(UISettings::values.game_list_row_1));
ui->row_2_text_combobox->setCurrentIndex(static_cast<int>(UISettings::values.game_list_row_2) +
1);
ui->toggle_hide_no_icon->setChecked(UISettings::values.game_list_hide_no_icon);
ui->toggle_single_line_mode->setChecked(UISettings::values.game_list_single_line_mode);
}
void ConfigureUi::ApplyConfiguration() {

View File

@ -87,7 +87,7 @@ void ConfigureWeb::SetConfiguration() {
tr("Telemetry ID: 0x%1").arg(QString::number(Core::GetTelemetryId(), 16).toUpper()));
user_verified = true;
ui->toggle_discordrpc->setChecked(UISettings::values.enable_discord_presence.GetValue());
ui->toggle_discordrpc->setChecked(UISettings::values.enable_discord_presence);
}
void ConfigureWeb::ApplyConfiguration() {

View File

@ -15,10 +15,10 @@
namespace Debugger {
void ToggleConsole() {
static bool console_shown = false;
if (console_shown == UISettings::values.show_console.GetValue()) {
if (console_shown == UISettings::values.show_console) {
return;
} else {
console_shown = UISettings::values.show_console.GetValue();
console_shown = UISettings::values.show_console;
}
#ifdef _WIN32

View File

@ -314,31 +314,31 @@ void GraphicsSurfaceWidget::Pick(int x, int y) {
auto GetText = [offset](Format format, const u8* pixel) {
switch (format) {
case Format::RGBA8: {
auto value = Common::Color::DecodeRGBA8(pixel) / 255.0f;
auto value = Color::DecodeRGBA8(pixel) / 255.0f;
return QStringLiteral("Red: %1, Green: %2, Blue: %3, Alpha: %4")
.arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2),
QString::number(value.b(), 'f', 2), QString::number(value.a(), 'f', 2));
}
case Format::RGB8: {
auto value = Common::Color::DecodeRGB8(pixel) / 255.0f;
auto value = Color::DecodeRGB8(pixel) / 255.0f;
return QStringLiteral("Red: %1, Green: %2, Blue: %3")
.arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2),
QString::number(value.b(), 'f', 2));
}
case Format::RGB5A1: {
auto value = Common::Color::DecodeRGB5A1(pixel) / 255.0f;
auto value = Color::DecodeRGB5A1(pixel) / 255.0f;
return QStringLiteral("Red: %1, Green: %2, Blue: %3, Alpha: %4")
.arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2),
QString::number(value.b(), 'f', 2), QString::number(value.a(), 'f', 2));
}
case Format::RGB565: {
auto value = Common::Color::DecodeRGB565(pixel) / 255.0f;
auto value = Color::DecodeRGB565(pixel) / 255.0f;
return QStringLiteral("Red: %1, Green: %2, Blue: %3")
.arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2),
QString::number(value.b(), 'f', 2));
}
case Format::RGBA4: {
auto value = Common::Color::DecodeRGBA4(pixel) / 255.0f;
auto value = Color::DecodeRGBA4(pixel) / 255.0f;
return QStringLiteral("Red: %1, Green: %2, Blue: %3, Alpha: %4")
.arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2),
QString::number(value.b(), 'f', 2), QString::number(value.a(), 'f', 2));
@ -346,7 +346,7 @@ void GraphicsSurfaceWidget::Pick(int x, int y) {
case Format::IA8:
return QStringLiteral("Index: %1, Alpha: %2").arg(pixel[0], pixel[1]);
case Format::RG8: {
auto value = Common::Color::DecodeRG8(pixel) / 255.0f;
auto value = Color::DecodeRG8(pixel) / 255.0f;
return QStringLiteral("Red: %1, Green: %2")
.arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2));
}
@ -369,17 +369,17 @@ void GraphicsSurfaceWidget::Pick(int x, int y) {
// TODO: Display block information or channel values?
return QStringLiteral("Compressed data");
case Format::D16: {
auto value = Common::Color::DecodeD16(pixel);
auto value = Color::DecodeD16(pixel);
return QStringLiteral("Depth: %1").arg(QString::number(value / (float)0xFFFF, 'f', 4));
}
case Format::D24: {
auto value = Common::Color::DecodeD24(pixel);
auto value = Color::DecodeD24(pixel);
return QStringLiteral("Depth: %1")
.arg(QString::number(value / (float)0xFFFFFF, 'f', 4));
}
case Format::D24X8:
case Format::X24S8: {
auto values = Common::Color::DecodeD24S8(pixel);
auto values = Color::DecodeD24S8(pixel);
return QStringLiteral("Depth: %1, Stencil: %2")
.arg(QString::number(values[0] / (float)0xFFFFFF, 'f', 4), values[1]);
}
@ -603,27 +603,27 @@ void GraphicsSurfaceWidget::OnUpdate() {
switch (surface_format) {
case Format::D16: {
u32 data = Common::Color::DecodeD16(pixel);
u32 data = Color::DecodeD16(pixel);
color.r() = data & 0xFF;
color.g() = (data >> 8) & 0xFF;
break;
}
case Format::D24: {
u32 data = Common::Color::DecodeD24(pixel);
u32 data = Color::DecodeD24(pixel);
color.r() = data & 0xFF;
color.g() = (data >> 8) & 0xFF;
color.b() = (data >> 16) & 0xFF;
break;
}
case Format::D24X8: {
Common::Vec2<u32> data = Common::Color::DecodeD24S8(pixel);
Common::Vec2<u32> data = Color::DecodeD24S8(pixel);
color.r() = data.x & 0xFF;
color.g() = (data.x >> 8) & 0xFF;
color.b() = (data.x >> 16) & 0xFF;
break;
}
case Format::X24S8: {
Common::Vec2<u32> data = Common::Color::DecodeD24S8(pixel);
Common::Vec2<u32> data = Color::DecodeD24S8(pixel);
color.r() = color.g() = color.b() = data.y;
break;
}

View File

@ -7,7 +7,7 @@
#include <QLayout>
#include <QScrollArea>
#include "citra_qt/debugger/lle_service_modules.h"
#include "common/settings.h"
#include "core/settings.h"
LLEServiceModulesWidget::LLEServiceModulesWidget(QWidget* parent)
: QDockWidget(tr("Toggle LLE Service Modules"), parent) {

View File

@ -7,13 +7,13 @@
#include "citra_qt/uisettings.h"
#include "citra_qt/util/util.h"
#include "common/assert.h"
#include "common/settings.h"
#include "core/hle/kernel/event.h"
#include "core/hle/kernel/mutex.h"
#include "core/hle/kernel/semaphore.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/kernel/timer.h"
#include "core/hle/kernel/wait_object.h"
#include "core/settings.h"
namespace {

View File

@ -7,7 +7,7 @@
#include "citra_qt/dumping/dumping_dialog.h"
#include "citra_qt/dumping/options_dialog.h"
#include "citra_qt/uisettings.h"
#include "common/settings.h"
#include "core/settings.h"
#include "ui_dumping_dialog.h"
DumpingDialog::DumpingDialog(QWidget* parent)

View File

@ -29,10 +29,10 @@
#include "citra_qt/main.h"
#include "citra_qt/uisettings.h"
#include "common/logging/log.h"
#include "common/settings.h"
#include "core/file_sys/archive_extsavedata.h"
#include "core/file_sys/archive_source_sd_savedata.h"
#include "core/hle/service/fs/archive.h"
#include "core/settings.h"
#include "qcursor.h"
GameListSearchField::KeyReleaseEater::KeyReleaseEater(GameList* gamelist, QObject* parent)
@ -469,16 +469,6 @@ void GameList::PopupContextMenu(const QPoint& menu_location) {
context_menu.exec(tree_view->viewport()->mapToGlobal(menu_location));
}
void ForEachOpenGLCacheFile(u64 program_id, auto func) {
for (const std::string_view cache_type : {"separable", "conventional"}) {
const std::string path = fmt::format("{}opengl/precompiled/{}/{:016X}.bin",
FileUtil::GetUserPath(FileUtil::UserPath::ShaderDir),
cache_type, program_id);
QFile file{QString::fromStdString(path)};
func(file);
}
}
void GameList::AddGamePopup(QMenu& context_menu, const QString& path, u64 program_id,
u64 extdata_id) {
QAction* open_save_location = context_menu.addAction(tr("Open Save Data Location"));
@ -489,34 +479,29 @@ void GameList::AddGamePopup(QMenu& context_menu, const QString& path, u64 progra
QAction* open_texture_load_location =
context_menu.addAction(tr("Open Custom Texture Location"));
QAction* open_mods_location = context_menu.addAction(tr("Open Mods Location"));
QAction* open_dlc_location = context_menu.addAction(tr("Open DLC Data Location"));
QMenu* shader_menu = context_menu.addMenu(tr("Disk Shader Cache"));
QAction* dump_romfs = context_menu.addAction(tr("Dump RomFS"));
QAction* navigate_to_gamedb_entry = context_menu.addAction(tr("Navigate to GameDB entry"));
context_menu.addSeparator();
QAction* properties = context_menu.addAction(tr("Properties"));
QAction* open_shader_cache_location = shader_menu->addAction(tr("Open Shader Cache Location"));
shader_menu->addSeparator();
QAction* delete_opengl_disk_shader_cache =
shader_menu->addAction(tr("Delete OpenGL Shader Cache"));
QAction* delete_vulkan_disk_shader_cache =
shader_menu->addAction(tr("Delete Vulkan Shader Cache"));
const bool is_application =
0x0004000000000000 <= program_id && program_id <= 0x00040000FFFFFFFF;
bool opengl_cache_exists = false;
ForEachOpenGLCacheFile(
program_id, [&opengl_cache_exists](QFile& file) { opengl_cache_exists |= file.exists(); });
std::string sdmc_dir = FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir);
std::string sdmc_dir = Common::FS::GetUserPath(Common::FS::UserPath::SDMCDir);
open_save_location->setEnabled(
is_application && FileUtil::Exists(FileSys::ArchiveSource_SDSaveData::GetSaveDataPathFor(
is_application && Common::FS::Exists(FileSys::ArchiveSource_SDSaveData::GetSaveDataPathFor(
sdmc_dir, program_id)));
if (extdata_id) {
open_extdata_location->setEnabled(
is_application &&
FileUtil::Exists(FileSys::GetExtDataPathFromId(sdmc_dir, extdata_id)));
Common::FS::Exists(FileSys::GetExtDataPathFromId(sdmc_dir, extdata_id)));
} else {
open_extdata_location->setVisible(false);
}
@ -525,17 +510,15 @@ void GameList::AddGamePopup(QMenu& context_menu, const QString& path, u64 progra
open_application_location->setEnabled(path.toStdString() ==
Service::AM::GetTitleContentPath(media_type, program_id));
open_update_location->setEnabled(
is_application && FileUtil::Exists(Service::AM::GetTitlePath(Service::FS::MediaType::SDMC,
is_application && Common::FS::Exists(Service::AM::GetTitlePath(Service::FS::MediaType::SDMC,
program_id + 0xe00000000) +
"content/"));
auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id);
open_texture_dump_location->setEnabled(is_application);
open_texture_load_location->setEnabled(is_application);
open_mods_location->setEnabled(is_application);
open_dlc_location->setEnabled(is_application);
dump_romfs->setEnabled(is_application);
delete_opengl_disk_shader_cache->setEnabled(opengl_cache_exists);
open_texture_dump_location->setVisible(is_application);
open_texture_load_location->setVisible(is_application);
open_mods_location->setVisible(is_application);
dump_romfs->setVisible(is_application);
navigate_to_gamedb_entry->setVisible(it != compatibility_list.end());
@ -552,51 +535,57 @@ void GameList::AddGamePopup(QMenu& context_menu, const QString& path, u64 progra
emit OpenFolderRequested(program_id, GameListOpenTarget::UPDATE_DATA);
});
connect(open_texture_dump_location, &QAction::triggered, this, [this, program_id] {
if (FileUtil::CreateFullPath(fmt::format("{}textures/{:016X}/",
FileUtil::GetUserPath(FileUtil::UserPath::DumpDir),
if (Common::FS::CreateFullPath(fmt::format("{}textures/{:016X}/",
Common::FS::GetUserPath(Common::FS::UserPath::DumpDir),
program_id))) {
emit OpenFolderRequested(program_id, GameListOpenTarget::TEXTURE_DUMP);
}
});
connect(open_texture_load_location, &QAction::triggered, this, [this, program_id] {
if (FileUtil::CreateFullPath(fmt::format("{}textures/{:016X}/",
FileUtil::GetUserPath(FileUtil::UserPath::LoadDir),
if (Common::FS::CreateFullPath(fmt::format("{}textures/{:016X}/",
Common::FS::GetUserPath(Common::FS::UserPath::LoadDir),
program_id))) {
emit OpenFolderRequested(program_id, GameListOpenTarget::TEXTURE_LOAD);
}
});
connect(open_texture_load_location, &QAction::triggered, this, [this, program_id] {
if (Common::FS::CreateFullPath(fmt::format("{}textures/{:016X}/",
Common::FS::GetUserPath(Common::FS::UserPath::LoadDir),
program_id))) {
emit OpenFolderRequested(program_id, GameListOpenTarget::TEXTURE_LOAD);
}
});
connect(open_mods_location, &QAction::triggered, this, [this, program_id] {
if (FileUtil::CreateFullPath(fmt::format("{}mods/{:016X}/",
FileUtil::GetUserPath(FileUtil::UserPath::LoadDir),
if (Common::FS::CreateFullPath(fmt::format("{}mods/{:016X}/",
Common::FS::GetUserPath(Common::FS::UserPath::LoadDir),
program_id))) {
emit OpenFolderRequested(program_id, GameListOpenTarget::MODS);
}
});
connect(open_dlc_location, &QAction::triggered, this, [this, program_id] {
const u64 trimmed_id = program_id & 0xFFFFFFF;
const std::string dlc_path =
fmt::format("{}Nintendo 3DS/00000000000000000000000000000000/"
"00000000000000000000000000000000/title/0004008c/{:08x}/content/",
FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir), trimmed_id);
fmt::print("DLC path {}\n", dlc_path);
if (FileUtil::CreateFullPath(dlc_path)) {
emit OpenFolderRequested(trimmed_id, GameListOpenTarget::DLC_DATA);
}
});
connect(dump_romfs, &QAction::triggered, this,
[this, path, program_id] { emit DumpRomFSRequested(path, program_id); });
connect(navigate_to_gamedb_entry, &QAction::triggered, this, [this, program_id]() {
emit NavigateToGamedbEntryRequested(program_id, compatibility_list);
});
connect(properties, &QAction::triggered, this,
[this, path]() { emit OpenPerGameGeneralRequested(path); });
connect(open_shader_cache_location, &QAction::triggered, this, [this, program_id] {
if (FileUtil::CreateFullPath(FileUtil::GetUserPath(FileUtil::UserPath::ShaderDir))) {
if (Common::FS::CreateFullPath(Common::FS::GetUserPath(Common::FS::UserPath::ShaderDir))) {
emit OpenFolderRequested(program_id, GameListOpenTarget::SHADER_CACHE);
}
});
connect(delete_opengl_disk_shader_cache, &QAction::triggered, this, [program_id] {
ForEachOpenGLCacheFile(program_id, [](QFile& file) { file.remove(); });
const std::string_view cache_type =
Settings::values.separable_shader ? "separable" : "conventional";
const std::string path = fmt::format("{}opengl/precompiled/{}/{:016X}.bin",
Common::FS::GetUserPath(Common::FS::UserPath::ShaderDir),
cache_type, program_id);
QFile file{QString::fromStdString(path)};
file.remove();
});
connect(delete_vulkan_disk_shader_cache, &QAction::triggered, this, [] {
const std::string path =
fmt::format("{}vulkan", Common::FS::GetUserPath(Common::FS::UserPath::ShaderDir));
QDir dir{QString::fromStdString(path)};
dir.removeRecursively();
});
};

View File

@ -37,8 +37,7 @@ enum class GameListOpenTarget {
TEXTURE_DUMP = 4,
TEXTURE_LOAD = 5,
MODS = 6,
DLC_DATA = 7,
SHADER_CACHE = 8
SHADER_CACHE = 7
};
class GameList : public QWidget {
@ -84,7 +83,6 @@ signals:
void OpenFolderRequested(u64 program_id, GameListOpenTarget target);
void NavigateToGamedbEntryRequested(u64 program_id,
const CompatibilityList& compatibility_list);
void OpenPerGameGeneralRequested(const QString file);
void DumpRomFSRequested(QString game_path, u64 program_id);
void OpenDirectory(const QString& directory);
void AddDirectory();

View File

@ -160,19 +160,17 @@ public:
setData(qulonglong(program_id), ProgramIdRole);
setData(qulonglong(extdata_id), ExtdataIdRole);
if (UISettings::values.game_list_icon_size.GetValue() ==
UISettings::GameListIconSize::NoIcon) {
if (UISettings::values.game_list_icon_size == UISettings::GameListIconSize::NoIcon) {
// Do not display icons
setData(QPixmap(), Qt::DecorationRole);
}
bool large = UISettings::values.game_list_icon_size.GetValue() ==
UISettings::GameListIconSize::LargeIcon;
bool large =
UISettings::values.game_list_icon_size == UISettings::GameListIconSize::LargeIcon;
if (!Loader::IsValidSMDH(smdh_data)) {
// SMDH is not valid, set a default icon
if (UISettings::values.game_list_icon_size.GetValue() !=
UISettings::GameListIconSize::NoIcon)
if (UISettings::values.game_list_icon_size != UISettings::GameListIconSize::NoIcon)
setData(GetDefaultIcon(large), Qt::DecorationRole);
return;
}
@ -181,8 +179,7 @@ public:
memcpy(&smdh, smdh_data.data(), sizeof(Loader::SMDH));
// Get icon from SMDH
if (UISettings::values.game_list_icon_size.GetValue() !=
UISettings::GameListIconSize::NoIcon) {
if (UISettings::values.game_list_icon_size != UISettings::GameListIconSize::NoIcon) {
setData(GetQPixmapFromSMDH(smdh, large), Qt::DecorationRole);
}
@ -214,17 +211,16 @@ public:
QString::fromStdString(fmt::format("{:016X}", data(ProgramIdRole).toULongLong()))},
};
const QString& row1 =
display_texts.at(UISettings::values.game_list_row_1.GetValue()).simplified();
const QString& row1 = display_texts.at(UISettings::values.game_list_row_1).simplified();
if (role == SortRole)
return row1.toLower();
QString row2;
const auto row_2_id = UISettings::values.game_list_row_2.GetValue();
auto row_2_id = UISettings::values.game_list_row_2;
if (row_2_id != UISettings::GameListText::NoText) {
if (!row1.isEmpty()) {
row2 = UISettings::values.game_list_single_line_mode.GetValue()
row2 = UISettings::values.game_list_single_line_mode
? QStringLiteral(" ")
: QStringLiteral("\n ");
}
@ -320,12 +316,6 @@ public:
setData(type(), TypeRole);
setData(size_bytes, SizeRole);
}
explicit GameListItemSize(const QString& string) {
// This is required to avoid incorrect virtual function call in
// GameListItem's constructor
setText(string);
setData(string, SortRole);
}
void setData(const QVariant& value, int role) override {
// By specializing setData for SizeRole, we can ensure that the numerical and string
@ -365,7 +355,7 @@ public:
UISettings::GameDir* game_dir = &directory;
setData(QVariant(UISettings::values.game_dirs.indexOf(directory)), GameDirRole);
const int icon_size = IconSizes.at(UISettings::values.game_list_icon_size.GetValue());
const int icon_size = IconSizes.at(UISettings::values.game_list_icon_size);
switch (dir_type) {
case GameListItemType::InstalledDir:
setData(QIcon::fromTheme(QStringLiteral("sd_card")).pixmap(icon_size),
@ -408,7 +398,7 @@ public:
explicit GameListAddDir() {
setData(type(), TypeRole);
int icon_size = IconSizes.at(UISettings::values.game_list_icon_size.GetValue());
int icon_size = IconSizes.at(UISettings::values.game_list_icon_size);
setData(QIcon::fromTheme(QStringLiteral("plus")).pixmap(icon_size), Qt::DecorationRole);
setData(QObject::tr("Add New Game Directory"), Qt::DisplayRole);
}

View File

@ -43,7 +43,7 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign
}
const std::string physical_name = directory + DIR_SEP + virtual_name;
const bool is_dir = FileUtil::IsDirectory(physical_name);
const bool is_dir = Common::FS::IsDirectory(physical_name);
if (!is_dir && HasSupportedFileExtension(physical_name)) {
std::unique_ptr<Loader::AppLoader> loader = Loader::GetLoader(physical_name);
if (!loader) {
@ -67,7 +67,7 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign
if (!(program_id & ~0x00040000FFFFFFFF)) {
std::string update_path = Service::AM::GetTitleContentPath(
Service::FS::MediaType::SDMC, program_id | 0x0000000E00000000);
if (FileUtil::Exists(update_path)) {
if (Common::FS::Exists(update_path)) {
std::unique_ptr<Loader::AppLoader> update_loader =
Loader::GetLoader(update_path);
if (update_loader) {
@ -101,7 +101,7 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign
new GameListItemRegion(smdh),
new GameListItem(
QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType()))),
new GameListItemSize(FileUtil::GetSize(physical_name)),
new GameListItemSize(Common::FS::GetSize(physical_name)),
},
parent_dir);
@ -113,7 +113,7 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign
return true;
};
FileUtil::ForeachDirectoryEntry(nullptr, dir_path, callback);
Common::FS::ForeachDirectoryEntry(nullptr, dir_path, callback);
}
void GameListWorker::run() {
@ -121,12 +121,12 @@ void GameListWorker::run() {
for (UISettings::GameDir& game_dir : game_dirs) {
if (game_dir.path == QStringLiteral("INSTALLED")) {
QString games_path =
QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir)) +
QString::fromStdString(Common::FS::GetUserPath(Common::FS::UserPath::SDMCDir)) +
QStringLiteral("Nintendo "
"3DS/00000000000000000000000000000000/"
"00000000000000000000000000000000/title/00040000");
QString demos_path =
QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir)) +
QString::fromStdString(Common::FS::GetUserPath(Common::FS::UserPath::SDMCDir)) +
QStringLiteral(
"Nintendo "
"3DS/00000000000000000000000000000000/00000000000000000000000000000000/title/"
@ -139,7 +139,7 @@ void GameListWorker::run() {
AddFstEntriesToGameList(demos_path.toStdString(), 2, game_list_dir);
} else if (game_dir.path == QStringLiteral("SYSTEM")) {
QString path =
QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir)) +
QString::fromStdString(Common::FS::GetUserPath(Common::FS::UserPath::NANDDir)) +
QStringLiteral("00000000000000000000000000000000/title/00040010");
watch_list.append(path);
auto* const game_list_dir = new GameListDir(game_dir, GameListItemType::SystemDir);

View File

@ -9,19 +9,13 @@
namespace AppleAuthorization {
static bool authorized_camera = false;
static bool authorized_microphone = false;
static bool authorized = false;
enum class AuthMediaType { Camera, Microphone };
// Based on
// https://developer.apple.com/documentation/avfoundation/cameras_and_media_capture/requesting_authorization_for_media_capture_on_macos
// TODO: This could be rewritten to return the authorization state, having pure c++ code deal with
// it, log information and possibly wait for the camera access request.
void CheckAuthorization(AuthMediaType type) {
authorized = false;
if (@available(macOS 10.14, *)) {
NSString* media_type;
if (type == AuthMediaType::Camera) {
@ -75,19 +69,13 @@ void CheckAuthorization(AuthMediaType type) {
}
bool CheckAuthorizationForCamera() {
if (!authorized_camera) {
CheckAuthorization(AuthMediaType::Camera);
authorized_camera = authorized;
}
return authorized_camera;
CheckAuthorization(AuthMediaType::Camera);
return authorized;
}
bool CheckAuthorizationForMicrophone() {
if (!authorized_microphone) {
CheckAuthorization(AuthMediaType::Microphone);
authorized_microphone = authorized;
}
return authorized_microphone;
CheckAuthorization(AuthMediaType::Microphone);
return authorized;
}
} // AppleAuthorization

View File

@ -3,7 +3,6 @@
// Refer to the license.txt file included.
#include <clocale>
#include <filesystem>
#include <fstream>
#include <memory>
#include <thread>
@ -12,7 +11,6 @@
#include <QFutureWatcher>
#include <QLabel>
#include <QMessageBox>
#include <QOpenGLFunctions_4_3_Core>
#include <QSysInfo>
#include <QtConcurrent/QtConcurrentRun>
#include <QtGui>
@ -29,7 +27,6 @@
#include "citra_qt/compatibility_list.h"
#include "citra_qt/configuration/config.h"
#include "citra_qt/configuration/configure_dialog.h"
#include "citra_qt/configuration/configure_per_game.h"
#include "citra_qt/debugger/console.h"
#include "citra_qt/debugger/graphics/graphics.h"
#include "citra_qt/debugger/graphics/graphics_breakpoints.h"
@ -57,10 +54,8 @@
#include "common/common_paths.h"
#include "common/detached_tasks.h"
#include "common/file_util.h"
#include "common/literals.h"
#include "common/logging/backend.h"
#include "common/logging/log.h"
#include "common/memory_detect.h"
#include "common/microprofile.h"
#include "common/scm_rev.h"
#include "common/scope_exit.h"
@ -68,7 +63,6 @@
#ifdef ARCHITECTURE_x86_64
#include "common/x64/cpu_detect.h"
#endif
#include "common/settings.h"
#include "core/core.h"
#include "core/dumping/backend.h"
#include "core/file_sys/archive_extsavedata.h"
@ -79,8 +73,7 @@
#include "core/loader/loader.h"
#include "core/movie.h"
#include "core/savestate.h"
#include "game_list_p.h"
#include "input_common/main.h"
#include "core/settings.h"
#include "network/network_settings.h"
#include "ui_main.h"
#include "video_core/video_core.h"
@ -123,13 +116,11 @@ enum class CalloutFlag : uint32_t {
};
void GMainWindow::ShowTelemetryCallout() {
if (UISettings::values.callout_flags.GetValue() &
static_cast<uint32_t>(CalloutFlag::Telemetry)) {
if (UISettings::values.callout_flags & static_cast<uint32_t>(CalloutFlag::Telemetry)) {
return;
}
UISettings::values.callout_flags =
UISettings::values.callout_flags.GetValue() | static_cast<uint32_t>(CalloutFlag::Telemetry);
UISettings::values.callout_flags |= static_cast<uint32_t>(CalloutFlag::Telemetry);
const QString telemetry_message =
tr("<a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'>Anonymous "
"data is collected</a> to help improve Citra. "
@ -144,11 +135,11 @@ const int GMainWindow::max_recent_files_item;
static void InitializeLogging() {
Log::Filter log_filter;
log_filter.ParseFilterString(Settings::values.log_filter.GetValue());
log_filter.ParseFilterString(Settings::values.log_filter);
Log::SetGlobalFilter(log_filter);
const std::string& log_dir = FileUtil::GetUserPath(FileUtil::UserPath::LogDir);
FileUtil::CreateFullPath(log_dir);
const std::string& log_dir = Common::FS::GetUserPath(Common::FS::UserPath::LogDir);
Common::FS::CreateFullPath(log_dir);
Log::AddBackend(std::make_unique<Log::FileBackend>(log_dir + LOG_FILE));
#ifdef _WIN32
Log::AddBackend(std::make_unique<Log::DebuggerBackend>());
@ -176,7 +167,7 @@ GMainWindow::GMainWindow()
default_theme_paths = QIcon::themeSearchPaths();
UpdateUITheme();
SetDiscordEnabled(UISettings::values.enable_discord_presence.GetValue());
SetDiscordEnabled(UISettings::values.enable_discord_presence);
discord_rpc->Update();
Network::Init();
@ -217,10 +208,6 @@ GMainWindow::GMainWindow()
LOG_INFO(Frontend, "Host CPU: {}", cpu_string);
#endif
LOG_INFO(Frontend, "Host OS: {}", QSysInfo::prettyProductName().toStdString());
const auto& mem_info = Common::GetMemInfo();
using namespace Common::Literals;
LOG_INFO(Frontend, "Host RAM: {:.2f} GiB", mem_info.total_physical_memory / f64{1_GiB});
LOG_INFO(Frontend, "Host Swap: {:.2f} GiB", mem_info.total_swap_memory / f64{1_GiB});
UpdateWindowTitle();
show();
@ -258,11 +245,8 @@ void GMainWindow::InitializeWidgets() {
#ifdef CITRA_ENABLE_COMPATIBILITY_REPORTING
ui->action_Report_Compatibility->setVisible(true);
#endif
render_window = new GRenderWindow(this, emu_thread.get(), false);
secondary_window = new GRenderWindow(this, emu_thread.get(), true);
render_window = new GRenderWindow(this, emu_thread.get());
render_window->hide();
secondary_window->hide();
secondary_window->setParent(nullptr);
game_list = new GameList(this);
ui->horizontalLayout->addWidget(game_list);
@ -282,7 +266,6 @@ void GMainWindow::InitializeWidgets() {
}
});
InputCommon::Init();
multiplayer_state = new MultiplayerState(this, game_list->GetModel(), ui->action_Leave_Room,
ui->action_Show_Room);
multiplayer_state->setVisible(false);
@ -350,7 +333,6 @@ void GMainWindow::InitializeWidgets() {
actionGroup_ScreenLayouts->addAction(ui->action_Screen_Layout_Single_Screen);
actionGroup_ScreenLayouts->addAction(ui->action_Screen_Layout_Large_Screen);
actionGroup_ScreenLayouts->addAction(ui->action_Screen_Layout_Side_by_Side);
actionGroup_ScreenLayouts->addAction(ui->action_Screen_Layout_Separate_Windows);
}
void GMainWindow::InitializeDebugWidgets() {
@ -491,9 +473,6 @@ void GMainWindow::InitializeHotkeys() {
const QString toggle_filter_bar = QStringLiteral("Toggle Filter Bar");
const QString toggle_status_bar = QStringLiteral("Toggle Status Bar");
const QString fullscreen = QStringLiteral("Fullscreen");
const QString toggle_screen_layout = QStringLiteral("Toggle Screen Layout");
const QString swap_screens = QStringLiteral("Swap Screens");
const QString rotate_screens = QStringLiteral("Rotate Screens Upright");
ui->action_Show_Filter_Bar->setShortcut(
hotkey_registry.GetKeySequence(main_window, toggle_filter_bar));
@ -531,40 +510,18 @@ void GMainWindow::InitializeHotkeys() {
return;
BootGame(QString(game_path));
});
connect(hotkey_registry.GetHotkey(main_window, swap_screens, render_window),
connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Swap Screens"), render_window),
&QShortcut::activated, ui->action_Screen_Layout_Swap_Screens, &QAction::trigger);
connect(hotkey_registry.GetHotkey(main_window, rotate_screens, render_window),
connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Rotate Screens Upright"),
render_window),
&QShortcut::activated, ui->action_Screen_Layout_Upright_Screens, &QAction::trigger);
connect(hotkey_registry.GetHotkey(main_window, toggle_screen_layout, render_window),
connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Toggle Screen Layout"),
render_window),
&QShortcut::activated, this, &GMainWindow::ToggleScreenLayout);
connect(hotkey_registry.GetHotkey(main_window, fullscreen, render_window),
&QShortcut::activated, ui->action_Fullscreen, &QAction::trigger);
connect(hotkey_registry.GetHotkey(main_window, fullscreen, render_window),
&QShortcut::activatedAmbiguously, ui->action_Fullscreen, &QAction::trigger);
const auto add_secondary_window_hotkey = [this](QKeySequence hotkey, const char* slot) {
// This action will fire specifically when secondary_window is in focus
QAction* secondary_window_action = new QAction(secondary_window);
secondary_window_action->setShortcut(hotkey);
connect(secondary_window_action, SIGNAL(triggered()), this, slot);
secondary_window->addAction(secondary_window_action);
};
// Use the same fullscreen hotkey as the main window
const auto fullscreen_hotkey = hotkey_registry.GetKeySequence(main_window, fullscreen);
add_secondary_window_hotkey(fullscreen_hotkey, SLOT(ToggleSecondaryFullscreen()));
const auto toggle_screen_hotkey =
hotkey_registry.GetKeySequence(main_window, toggle_screen_layout);
add_secondary_window_hotkey(toggle_screen_hotkey, SLOT(ToggleScreenLayout()));
const auto swap_screen_hotkey = hotkey_registry.GetKeySequence(main_window, swap_screens);
add_secondary_window_hotkey(swap_screen_hotkey, SLOT(TriggerSwapScreens()));
const auto rotate_screen_hotkey = hotkey_registry.GetKeySequence(main_window, rotate_screens);
add_secondary_window_hotkey(rotate_screen_hotkey, SLOT(TriggerRotateScreens()));
connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Exit Fullscreen"), this),
&QShortcut::activated, this, [&] {
if (emulation_running) {
@ -574,7 +531,8 @@ void GMainWindow::InitializeHotkeys() {
});
connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Toggle Alternate Speed"), this),
&QShortcut::activated, this, [&] {
Settings::values.frame_limit.SetGlobal(!Settings::values.frame_limit.UsingGlobal());
Settings::values.use_frame_limit_alternate =
!Settings::values.use_frame_limit_alternate;
UpdateStatusBar();
});
connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Toggle Texture Dumping"), this),
@ -585,25 +543,42 @@ void GMainWindow::InitializeHotkeys() {
static constexpr u16 SPEED_LIMIT_STEP = 5;
connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Increase Speed Limit"), this),
&QShortcut::activated, this, [&] {
if (Settings::values.frame_limit.GetValue() == 0) {
return;
}
if (Settings::values.frame_limit.GetValue() < 995 - SPEED_LIMIT_STEP) {
Settings::values.frame_limit.SetValue(Settings::values.frame_limit.GetValue() +
SPEED_LIMIT_STEP);
if (Settings::values.use_frame_limit_alternate) {
if (Settings::values.frame_limit_alternate == 0) {
return;
}
if (Settings::values.frame_limit_alternate < 995 - SPEED_LIMIT_STEP) {
Settings::values.frame_limit_alternate += SPEED_LIMIT_STEP;
} else {
Settings::values.frame_limit_alternate = 0;
}
} else {
Settings::values.frame_limit = 0;
if (Settings::values.frame_limit == 0) {
return;
}
if (Settings::values.frame_limit < 995 - SPEED_LIMIT_STEP) {
Settings::values.frame_limit += SPEED_LIMIT_STEP;
} else {
Settings::values.frame_limit = 0;
}
}
UpdateStatusBar();
});
connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Decrease Speed Limit"), this),
&QShortcut::activated, this, [&] {
if (Settings::values.frame_limit.GetValue() == 0) {
Settings::values.frame_limit = 995;
} else if (Settings::values.frame_limit.GetValue() > SPEED_LIMIT_STEP) {
Settings::values.frame_limit.SetValue(Settings::values.frame_limit.GetValue() -
SPEED_LIMIT_STEP);
UpdateStatusBar();
if (Settings::values.use_frame_limit_alternate) {
if (Settings::values.frame_limit_alternate == 0) {
Settings::values.frame_limit_alternate = 995;
} else if (Settings::values.frame_limit_alternate > SPEED_LIMIT_STEP) {
Settings::values.frame_limit_alternate -= SPEED_LIMIT_STEP;
}
} else {
if (Settings::values.frame_limit == 0) {
Settings::values.frame_limit = 995;
} else if (Settings::values.frame_limit > SPEED_LIMIT_STEP) {
Settings::values.frame_limit -= SPEED_LIMIT_STEP;
UpdateStatusBar();
}
}
UpdateStatusBar();
});
@ -633,9 +608,6 @@ void GMainWindow::InitializeHotkeys() {
&QShortcut::activated, ui->action_Load_from_Newest_Slot, &QAction::trigger);
connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Save to Oldest Slot"), this),
&QShortcut::activated, ui->action_Save_to_Oldest_Slot, &QAction::trigger);
connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Mute Audio"), this),
&QShortcut::activated, this,
[] { Settings::values.audio_muted = !Settings::values.audio_muted; });
}
void GMainWindow::ShowUpdaterWidgets() {
@ -663,26 +635,25 @@ void GMainWindow::RestoreUIState() {
render_window->restoreGeometry(UISettings::values.renderwindow_geometry);
#if MICROPROFILE_ENABLED
microProfileDialog->restoreGeometry(UISettings::values.microprofile_geometry);
microProfileDialog->setVisible(UISettings::values.microprofile_visible.GetValue());
microProfileDialog->setVisible(UISettings::values.microprofile_visible);
#endif
ui->action_Cheats->setEnabled(false);
game_list->LoadInterfaceLayout();
ui->action_Single_Window_Mode->setChecked(UISettings::values.single_window_mode.GetValue());
ui->action_Single_Window_Mode->setChecked(UISettings::values.single_window_mode);
ToggleWindowMode();
ui->action_Fullscreen->setChecked(UISettings::values.fullscreen.GetValue());
ui->action_Fullscreen->setChecked(UISettings::values.fullscreen);
SyncMenuUISettings();
ui->action_Display_Dock_Widget_Headers->setChecked(
UISettings::values.display_titlebar.GetValue());
ui->action_Display_Dock_Widget_Headers->setChecked(UISettings::values.display_titlebar);
OnDisplayTitleBars(ui->action_Display_Dock_Widget_Headers->isChecked());
ui->action_Show_Filter_Bar->setChecked(UISettings::values.show_filter_bar.GetValue());
ui->action_Show_Filter_Bar->setChecked(UISettings::values.show_filter_bar);
game_list->SetFilterVisible(ui->action_Show_Filter_Bar->isChecked());
ui->action_Show_Status_Bar->setChecked(UISettings::values.show_status_bar.GetValue());
ui->action_Show_Status_Bar->setChecked(UISettings::values.show_status_bar);
statusBar()->setVisible(ui->action_Show_Status_Bar->isChecked());
}
@ -718,17 +689,10 @@ void GMainWindow::ConnectWidgetEvents() {
connect(game_list, &GameList::PopulatingCompleted, this,
[this] { multiplayer_state->UpdateGameList(game_list->GetModel()); });
connect(game_list, &GameList::OpenPerGameGeneralRequested, this,
&GMainWindow::OnGameListOpenPerGameProperties);
connect(this, &GMainWindow::EmulationStarting, render_window,
&GRenderWindow::OnEmulationStarting);
connect(this, &GMainWindow::EmulationStopping, render_window,
&GRenderWindow::OnEmulationStopping);
connect(this, &GMainWindow::EmulationStarting, secondary_window,
&GRenderWindow::OnEmulationStarting);
connect(this, &GMainWindow::EmulationStopping, secondary_window,
&GRenderWindow::OnEmulationStopping);
connect(&status_bar_update_timer, &QTimer::timeout, this, &GMainWindow::UpdateStatusBar);
@ -756,8 +720,6 @@ void GMainWindow::ConnectMenuEvents() {
connect(ui->action_Report_Compatibility, &QAction::triggered, this,
&GMainWindow::OnMenuReportCompatibility);
connect(ui->action_Configure, &QAction::triggered, this, &GMainWindow::OnConfigure);
connect(ui->action_Configure_Current_Game, &QAction::triggered, this,
&GMainWindow::OnConfigurePerGame);
connect(ui->action_Cheats, &QAction::triggered, this, &GMainWindow::OnCheats);
// View
@ -804,8 +766,6 @@ void GMainWindow::ConnectMenuEvents() {
&GMainWindow::ChangeScreenLayout);
connect(ui->action_Screen_Layout_Side_by_Side, &QAction::triggered, this,
&GMainWindow::ChangeScreenLayout);
connect(ui->action_Screen_Layout_Separate_Windows, &QAction::triggered, this,
&GMainWindow::ChangeScreenLayout);
connect(ui->action_Screen_Layout_Swap_Screens, &QAction::triggered, this,
&GMainWindow::OnSwapScreens);
connect(ui->action_Screen_Layout_Upright_Screens, &QAction::triggered, this,
@ -965,14 +925,11 @@ bool GMainWindow::LoadROM(const QString& filename) {
ShutdownGame();
render_window->InitRenderTarget();
secondary_window->InitRenderTarget();
const auto scope = render_window->Acquire();
Core::System& system{Core::System::GetInstance()};
const Core::System::ResultStatus result{
system.Load(*render_window, filename.toStdString(), secondary_window)};
Core::System& system = Core::System::GetInstance();
const Core::System::ResultStatus result = system.Load(*render_window, filename.toStdString());
if (result != Core::System::ResultStatus::Success) {
switch (result) {
@ -1079,22 +1036,6 @@ void GMainWindow::BootGame(const QString& filename) {
Core::Movie::GetInstance().PrepareForPlayback(movie_playback_path.toStdString());
}
u64 title_id{0};
const std::string path = filename.toStdString();
const auto loader = Loader::GetLoader(path);
if (loader != nullptr && loader->ReadProgramId(title_id) == Loader::ResultStatus::Success) {
// Load per game settings
const std::string name{FileUtil::GetFilename(filename.toStdString())};
const std::string config_file_name =
title_id == 0 ? name : fmt::format("{:016X}", title_id);
Config per_game_config(config_file_name, Config::ConfigType::PerGameConfig);
Settings::Apply();
LOG_INFO(Frontend, "Using per game config file for title id {}", config_file_name);
Settings::LogSettings();
}
// Save configurations
UpdateUISettings();
game_list->SaveInterfaceLayout();
@ -1146,8 +1087,6 @@ void GMainWindow::BootGame(const QString& filename) {
connect(render_window, &GRenderWindow::Closed, this, &GMainWindow::OnStopGame);
connect(render_window, &GRenderWindow::MouseActivity, this, &GMainWindow::OnMouseActivity);
connect(secondary_window, &GRenderWindow::Closed, this, &GMainWindow::OnStopGame);
connect(secondary_window, &GRenderWindow::MouseActivity, this, &GMainWindow::OnMouseActivity);
// BlockingQueuedConnection is important here, it makes sure we've finished refreshing our views
// before the CPU continues
@ -1239,7 +1178,6 @@ void GMainWindow::ShutdownGame() {
// The emulation is stopped, so closing the window or not does not matter anymore
disconnect(render_window, &GRenderWindow::Closed, this, &GMainWindow::OnStopGame);
disconnect(secondary_window, &GRenderWindow::Closed, this, &GMainWindow::OnStopGame);
// Update the GUI
ui->action_Start->setEnabled(false);
@ -1248,14 +1186,12 @@ void GMainWindow::ShutdownGame() {
ui->action_Stop->setEnabled(false);
ui->action_Restart->setEnabled(false);
ui->action_Cheats->setEnabled(false);
ui->action_Configure_Current_Game->setEnabled(false);
ui->action_Load_Amiibo->setEnabled(false);
ui->action_Remove_Amiibo->setEnabled(false);
ui->action_Report_Compatibility->setEnabled(false);
ui->action_Advance_Frame->setEnabled(false);
ui->action_Capture_Screenshot->setEnabled(false);
render_window->hide();
secondary_window->hide();
loading_screen->hide();
loading_screen->Clear();
if (game_list->IsEmpty())
@ -1288,7 +1224,6 @@ void GMainWindow::ShutdownGame() {
// When closing the game, destroy the GLWindow to clear the context after the game is closed
render_window->ReleaseRenderTarget();
secondary_window->ReleaseRenderTarget();
}
void GMainWindow::StoreRecentFile(const QString& filename) {
@ -1379,9 +1314,7 @@ void GMainWindow::UpdateSaveStates() {
}
void GMainWindow::OnGameListLoadFile(QString game_path) {
if (ConfirmChangeGame()) {
BootGame(game_path);
}
BootGame(game_path);
}
void GMainWindow::OnGameListOpenFolder(u64 data_id, GameListOpenTarget target) {
@ -1391,13 +1324,13 @@ void GMainWindow::OnGameListOpenFolder(u64 data_id, GameListOpenTarget target) {
switch (target) {
case GameListOpenTarget::SAVE_DATA: {
open_target = "Save Data";
std::string sdmc_dir = FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir);
std::string sdmc_dir = Common::FS::GetUserPath(Common::FS::UserPath::SDMCDir);
path = FileSys::ArchiveSource_SDSaveData::GetSaveDataPathFor(sdmc_dir, data_id);
break;
}
case GameListOpenTarget::EXT_DATA: {
open_target = "Extra Data";
std::string sdmc_dir = FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir);
std::string sdmc_dir = Common::FS::GetUserPath(Common::FS::UserPath::SDMCDir);
path = FileSys::GetExtDataPathFromId(sdmc_dir, data_id);
break;
}
@ -1416,31 +1349,24 @@ void GMainWindow::OnGameListOpenFolder(u64 data_id, GameListOpenTarget target) {
case GameListOpenTarget::TEXTURE_DUMP: {
open_target = "Dumped Textures";
path = fmt::format("{}textures/{:016X}/",
FileUtil::GetUserPath(FileUtil::UserPath::DumpDir), data_id);
Common::FS::GetUserPath(Common::FS::UserPath::DumpDir), data_id);
break;
}
case GameListOpenTarget::TEXTURE_LOAD: {
open_target = "Custom Textures";
path = fmt::format("{}textures/{:016X}/",
FileUtil::GetUserPath(FileUtil::UserPath::LoadDir), data_id);
Common::FS::GetUserPath(Common::FS::UserPath::LoadDir), data_id);
break;
}
case GameListOpenTarget::MODS: {
open_target = "Mods";
path = fmt::format("{}mods/{:016X}/", FileUtil::GetUserPath(FileUtil::UserPath::LoadDir),
path = fmt::format("{}mods/{:016X}/", Common::FS::GetUserPath(Common::FS::UserPath::LoadDir),
data_id);
break;
}
case GameListOpenTarget::DLC_DATA: {
open_target = "DLC Data";
path = fmt::format("{}Nintendo 3DS/00000000000000000000000000000000/"
"00000000000000000000000000000000/title/0004008c/{:08x}/content/",
FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir), data_id);
break;
}
case GameListOpenTarget::SHADER_CACHE: {
open_target = "Shader Cache";
path = FileUtil::GetUserPath(FileUtil::UserPath::ShaderDir);
path = Common::FS::GetUserPath(Common::FS::UserPath::ShaderDir);
break;
}
default:
@ -1484,9 +1410,9 @@ void GMainWindow::OnGameListDumpRomFS(QString game_path, u64 program_id) {
dialog->setValue(0);
const auto base_path = fmt::format(
"{}romfs/{:016X}", FileUtil::GetUserPath(FileUtil::UserPath::DumpDir), program_id);
"{}romfs/{:016X}", Common::FS::GetUserPath(Common::FS::UserPath::DumpDir), program_id);
const auto update_path =
fmt::format("{}romfs/{:016X}", FileUtil::GetUserPath(FileUtil::UserPath::DumpDir),
fmt::format("{}romfs/{:016X}", Common::FS::GetUserPath(Common::FS::UserPath::DumpDir),
program_id | 0x0004000e00000000);
using FutureWatcher = QFutureWatcher<std::pair<Loader::ResultStatus, Loader::ResultStatus>>;
auto* future_watcher = new FutureWatcher(this);
@ -1517,12 +1443,12 @@ void GMainWindow::OnGameListDumpRomFS(QString game_path, u64 program_id) {
void GMainWindow::OnGameListOpenDirectory(const QString& directory) {
QString path;
if (directory == QStringLiteral("INSTALLED")) {
path = QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir) +
path = QString::fromStdString(Common::FS::GetUserPath(Common::FS::UserPath::SDMCDir) +
"Nintendo "
"3DS/00000000000000000000000000000000/"
"00000000000000000000000000000000/title/00040000");
} else if (directory == QStringLiteral("SYSTEM")) {
path = QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) +
path = QString::fromStdString(Common::FS::GetUserPath(Common::FS::UserPath::NANDDir) +
"00000000000000000000000000000000/title/00040010");
} else {
path = directory;
@ -1554,19 +1480,6 @@ void GMainWindow::OnGameListShowList(bool show) {
game_list_placeholder->setVisible(!show);
};
void GMainWindow::OnGameListOpenPerGameProperties(const QString& file) {
const auto loader = Loader::GetLoader(file.toStdString());
u64 title_id{};
if (!loader || loader->ReadProgramId(title_id) != Loader::ResultStatus::Success) {
QMessageBox::information(this, tr("Properties"),
tr("The game properties could not be loaded."));
return;
}
OpenPerGameConfiguration(title_id, file);
}
void GMainWindow::OnMenuLoadFile() {
const QString extensions = QStringLiteral("*.").append(
GameList::supported_file_extensions.join(QStringLiteral(" *.")));
@ -1692,7 +1605,6 @@ void GMainWindow::OnStartGame() {
ui->action_Stop->setEnabled(true);
ui->action_Restart->setEnabled(true);
ui->action_Cheats->setEnabled(true);
ui->action_Configure_Current_Game->setEnabled(true);
ui->action_Load_Amiibo->setEnabled(true);
ui->action_Report_Compatibility->setEnabled(true);
ui->action_Capture_Screenshot->setEnabled(true);
@ -1715,12 +1627,10 @@ void GMainWindow::OnPauseGame() {
void GMainWindow::OnStopGame() {
ShutdownGame();
Settings::RestoreGlobalState(false);
}
void GMainWindow::OnLoadComplete() {
loading_screen->OnLoadComplete();
UpdateSecondaryWindowVisibility();
}
void GMainWindow::OnMenuReportCompatibility() {
@ -1745,17 +1655,6 @@ void GMainWindow::ToggleFullscreen() {
}
}
void GMainWindow::ToggleSecondaryFullscreen() {
if (!emulation_running) {
return;
}
if (secondary_window->isFullScreen()) {
secondary_window->showNormal();
} else {
secondary_window->showFullScreen();
}
}
void GMainWindow::ShowFullscreen() {
if (ui->action_Single_Window_Mode->isChecked()) {
UISettings::values.geometry = saveGeometry();
@ -1805,19 +1704,6 @@ void GMainWindow::ToggleWindowMode() {
}
}
void GMainWindow::UpdateSecondaryWindowVisibility() {
if (!emulation_running) {
return;
}
if (Settings::values.layout_option.GetValue() == Settings::LayoutOption::SeparateWindows) {
secondary_window->RestoreGeometry();
secondary_window->show();
} else {
secondary_window->BackupGeometry();
secondary_window->hide();
}
}
void GMainWindow::ChangeScreenLayout() {
Settings::LayoutOption new_layout = Settings::LayoutOption::Default;
@ -1829,39 +1715,35 @@ void GMainWindow::ChangeScreenLayout() {
new_layout = Settings::LayoutOption::LargeScreen;
} else if (ui->action_Screen_Layout_Side_by_Side->isChecked()) {
new_layout = Settings::LayoutOption::SideScreen;
} else if (ui->action_Screen_Layout_Separate_Windows->isChecked()) {
new_layout = Settings::LayoutOption::SeparateWindows;
}
Settings::values.layout_option = new_layout;
Settings::Apply();
UpdateSecondaryWindowVisibility();
}
void GMainWindow::ToggleScreenLayout() {
const Settings::LayoutOption new_layout = []() {
switch (Settings::values.layout_option.GetValue()) {
case Settings::LayoutOption::Default:
return Settings::LayoutOption::SingleScreen;
case Settings::LayoutOption::SingleScreen:
return Settings::LayoutOption::LargeScreen;
case Settings::LayoutOption::LargeScreen:
return Settings::LayoutOption::SideScreen;
case Settings::LayoutOption::SideScreen:
return Settings::LayoutOption::SeparateWindows;
case Settings::LayoutOption::SeparateWindows:
return Settings::LayoutOption::Default;
default:
LOG_ERROR(Frontend, "Unknown layout option {}",
Settings::values.layout_option.GetValue());
return Settings::LayoutOption::Default;
}
}();
Settings::LayoutOption new_layout = Settings::LayoutOption::Default;
switch (Settings::values.layout_option) {
case Settings::LayoutOption::Default:
new_layout = Settings::LayoutOption::SingleScreen;
break;
case Settings::LayoutOption::SingleScreen:
new_layout = Settings::LayoutOption::LargeScreen;
break;
case Settings::LayoutOption::LargeScreen:
new_layout = Settings::LayoutOption::SideScreen;
break;
case Settings::LayoutOption::SideScreen:
new_layout = Settings::LayoutOption::Default;
break;
default:
LOG_ERROR(Frontend, "Unknown layout option {}", Settings::values.layout_option);
}
Settings::values.layout_option = new_layout;
SyncMenuUISettings();
Settings::Apply();
UpdateSecondaryWindowVisibility();
}
void GMainWindow::OnSwapScreens() {
@ -1874,14 +1756,6 @@ void GMainWindow::OnRotateScreens() {
Settings::Apply();
}
void GMainWindow::TriggerSwapScreens() {
ui->action_Screen_Layout_Swap_Screens->trigger();
}
void GMainWindow::TriggerRotateScreens() {
ui->action_Screen_Layout_Upright_Screens->trigger();
}
void GMainWindow::OnCheats() {
CheatDialog cheat_dialog(this);
cheat_dialog.exec();
@ -1905,7 +1779,6 @@ void GMainWindow::OnLoadState() {
}
void GMainWindow::OnConfigure() {
Settings::SetConfiguringGlobal(true);
ConfigureDialog configureDialog(this, hotkey_registry,
!multiplayer_state->IsHostingPublicRoom());
connect(&configureDialog, &ConfigureDialog::LanguageChanged, this,
@ -1914,15 +1787,15 @@ void GMainWindow::OnConfigure() {
const int old_input_profile_index = Settings::values.current_input_profile_index;
const auto old_input_profiles = Settings::values.input_profiles;
const auto old_touch_from_button_maps = Settings::values.touch_from_button_maps;
const bool old_discord_presence = UISettings::values.enable_discord_presence.GetValue();
const bool old_discord_presence = UISettings::values.enable_discord_presence;
auto result = configureDialog.exec();
if (result == QDialog::Accepted) {
configureDialog.ApplyConfiguration();
InitializeHotkeys();
if (UISettings::values.theme != old_theme)
UpdateUITheme();
if (UISettings::values.enable_discord_presence.GetValue() != old_discord_presence)
SetDiscordEnabled(UISettings::values.enable_discord_presence.GetValue());
if (UISettings::values.enable_discord_presence != old_discord_presence)
SetDiscordEnabled(UISettings::values.enable_discord_presence);
if (!multiplayer_state->IsHostingPublicRoom())
multiplayer_state->UpdateCredentials();
emit UpdateThemedIcons();
@ -1935,7 +1808,6 @@ void GMainWindow::OnConfigure() {
} else {
setMouseTracking(false);
}
UpdateSecondaryWindowVisibility();
UpdateAPIIndicator(false);
} else {
Settings::values.input_profiles = old_input_profiles;
@ -2001,7 +1873,7 @@ void GMainWindow::OnRemoveAmiibo() {
void GMainWindow::OnOpenCitraFolder() {
QDesktopServices::openUrl(QUrl::fromLocalFile(
QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::UserDir))));
QString::fromStdString(Common::FS::GetUserPath(Common::FS::UserPath::UserDir))));
}
void GMainWindow::OnToggleFilterBar() {
@ -2100,26 +1972,22 @@ void GMainWindow::OnSaveMovie() {
void GMainWindow::OnCaptureScreenshot() {
OnPauseGame();
std::string path = UISettings::values.screenshot_path.GetValue();
if (!FileUtil::IsDirectory(path)) {
if (!FileUtil::CreateFullPath(path)) {
QString path = UISettings::values.screenshot_path;
if (!Common::FS::IsDirectory(path.toStdString())) {
if (!Common::FS::CreateFullPath(path.toStdString())) {
QMessageBox::information(this, tr("Invalid Screenshot Directory"),
tr("Cannot create specified screenshot directory. Screenshot "
"path is set back to its default value."));
path = FileUtil::GetUserPath(FileUtil::UserPath::UserDir);
path.append("screenshots/");
path = QString::fromStdString(Common::FS::GetUserPath(Common::FS::UserPath::UserDir));
path.append(QStringLiteral("screenshots/"));
UISettings::values.screenshot_path = path;
};
}
const std::string filename =
game_title.remove(QRegularExpression(QStringLiteral("[\\/:?\"<>|]"))).toStdString();
const std::string timestamp =
QDateTime::currentDateTime().toString(QStringLiteral("dd.MM.yy_hh.mm.ss.z")).toStdString();
path.append(fmt::format("/{}_{}.png", filename, timestamp));
auto* const screenshot_window = secondary_window->HasFocus() ? secondary_window : render_window;
screenshot_window->CaptureScreenshot(UISettings::values.screenshot_resolution_factor.GetValue(),
QString::fromStdString(path));
const QString filename = game_title.remove(QRegularExpression(QStringLiteral("[\\/:?\"<>|]")));
const QString timestamp =
QDateTime::currentDateTime().toString(QStringLiteral("dd.MM.yy_hh.mm.ss.z"));
path.append(QStringLiteral("/%1_%2.png").arg(filename, timestamp));
render_window->CaptureScreenshot(UISettings::values.screenshot_resolution_factor, path);
OnStartGame();
}
@ -2211,12 +2079,22 @@ void GMainWindow::UpdateStatusBar() {
auto results = Core::System::GetInstance().GetAndResetPerfStats();
if (Settings::values.frame_limit.GetValue() == 0) {
if (Settings::values.use_frame_limit_alternate) {
if (Settings::values.frame_limit_alternate == 0) {
emu_speed_label->setText(
tr("Speed: %1%").arg(results.emulation_speed * 100.0, 0, 'f', 0));
} else {
emu_speed_label->setText(tr("Speed: %1% / %2%")
.arg(results.emulation_speed * 100.0, 0, 'f', 0)
.arg(Settings::values.frame_limit_alternate));
}
} else if (Settings::values.frame_limit == 0) {
emu_speed_label->setText(tr("Speed: %1%").arg(results.emulation_speed * 100.0, 0, 'f', 0));
} else {
emu_speed_label->setText(tr("Speed: %1% / %2%")
.arg(results.emulation_speed * 100.0, 0, 'f', 0)
.arg(Settings::values.frame_limit.GetValue()));
.arg(Settings::values.frame_limit));
}
game_fps_label->setText(tr("Game: %1 FPS").arg(results.game_fps, 0, 'f', 0));
emu_frametime_label->setText(tr("Frame: %1 ms").arg(results.frametime * 1000.0, 0, 'f', 2));
@ -2227,22 +2105,16 @@ void GMainWindow::UpdateStatusBar() {
}
void GMainWindow::HideMouseCursor() {
if (emu_thread == nullptr || !UISettings::values.hide_mouse.GetValue()) {
if (emu_thread == nullptr || UISettings::values.hide_mouse == false) {
mouse_hide_timer.stop();
ShowMouseCursor();
return;
}
render_window->setCursor(QCursor(Qt::BlankCursor));
secondary_window->setCursor(QCursor(Qt::BlankCursor));
if (UISettings::values.single_window_mode.GetValue()) {
setCursor(QCursor(Qt::BlankCursor));
}
}
void GMainWindow::ShowMouseCursor() {
unsetCursor();
render_window->unsetCursor();
secondary_window->unsetCursor();
if (emu_thread != nullptr && UISettings::values.hide_mouse) {
mouse_hide_timer.start();
}
@ -2255,7 +2127,7 @@ void GMainWindow::UpdateAPIIndicator(bool override) {
static std::array graphics_api_colors = {QStringLiteral("#00ccdd"), QStringLiteral("#ba2a8d"),
QStringLiteral("#91242a")};
u32 api_index = static_cast<u32>(Settings::values.graphics_api.GetValue());
u32 api_index = static_cast<u32>(Settings::values.graphics_api);
if (override) {
api_index = (api_index + 1) % graphics_apis.size();
Settings::values.graphics_api = static_cast<Settings::GraphicsAPI>(api_index);
@ -2371,9 +2243,7 @@ void GMainWindow::closeEvent(QCloseEvent* event) {
ShutdownGame();
render_window->close();
secondary_window->close();
multiplayer_state->Close();
InputCommon::Shutdown();
QWidget::closeEvent(event);
}
@ -2524,35 +2394,6 @@ void GMainWindow::OnLanguageChanged(const QString& locale) {
ui->action_Start->setText(tr("Continue"));
}
void GMainWindow::OnConfigurePerGame() {
u64 title_id{};
Core::System::GetInstance().GetAppLoader().ReadProgramId(title_id);
OpenPerGameConfiguration(title_id, game_path);
}
void GMainWindow::OpenPerGameConfiguration(u64 title_id, const QString& file_name) {
Core::System& system = Core::System::GetInstance();
Settings::SetConfiguringGlobal(false);
ConfigurePerGame dialog(this, title_id, file_name, system);
const auto result = dialog.exec();
if (result != QDialog::Accepted) {
Settings::RestoreGlobalState(system.IsPoweredOn());
return;
} else if (result == QDialog::Accepted) {
dialog.ApplyConfiguration();
}
// Do not cause the global config to write local settings into the config file
const bool is_powered_on = system.IsPoweredOn();
Settings::RestoreGlobalState(system.IsPoweredOn());
if (!is_powered_on) {
config->Save();
}
}
void GMainWindow::OnMoviePlaybackCompleted() {
OnPauseGame();
QMessageBox::information(this, tr("Playback Completed"), tr("Movie playback completed."));
@ -2587,19 +2428,16 @@ void GMainWindow::UpdateUISettings() {
}
void GMainWindow::SyncMenuUISettings() {
ui->action_Screen_Layout_Default->setChecked(Settings::values.layout_option.GetValue() ==
ui->action_Screen_Layout_Default->setChecked(Settings::values.layout_option ==
Settings::LayoutOption::Default);
ui->action_Screen_Layout_Single_Screen->setChecked(Settings::values.layout_option.GetValue() ==
ui->action_Screen_Layout_Single_Screen->setChecked(Settings::values.layout_option ==
Settings::LayoutOption::SingleScreen);
ui->action_Screen_Layout_Large_Screen->setChecked(Settings::values.layout_option.GetValue() ==
ui->action_Screen_Layout_Large_Screen->setChecked(Settings::values.layout_option ==
Settings::LayoutOption::LargeScreen);
ui->action_Screen_Layout_Side_by_Side->setChecked(Settings::values.layout_option.GetValue() ==
ui->action_Screen_Layout_Side_by_Side->setChecked(Settings::values.layout_option ==
Settings::LayoutOption::SideScreen);
ui->action_Screen_Layout_Separate_Windows->setChecked(
Settings::values.layout_option.GetValue() == Settings::LayoutOption::SeparateWindows);
ui->action_Screen_Layout_Swap_Screens->setChecked(Settings::values.swap_screen.GetValue());
ui->action_Screen_Layout_Upright_Screens->setChecked(
Settings::values.upright_screen.GetValue());
ui->action_Screen_Layout_Swap_Screens->setChecked(Settings::values.swap_screen);
ui->action_Screen_Layout_Upright_Screens->setChecked(Settings::values.upright_screen);
}
void GMainWindow::RetranslateStatusBar() {
@ -2644,7 +2482,7 @@ int main(int argc, char* argv[]) {
QCoreApplication::setApplicationName(QStringLiteral("Citra"));
#ifdef __APPLE__
std::string bin_path = FileUtil::GetBundleDirectory() + DIR_SEP + "..";
std::string bin_path = Common::FS::GetBundleDirectory() + DIR_SEP + "..";
chdir(bin_path.c_str());
#endif
QCoreApplication::setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity);
@ -2664,13 +2502,11 @@ int main(int argc, char* argv[]) {
// Register frontend applets
Frontend::RegisterDefaultApplets();
Core::System& system = Core::System::GetInstance();
system.RegisterMiiSelector(std::make_shared<QtMiiSelector>(main_window));
system.RegisterSoftwareKeyboard(std::make_shared<QtKeyboard>(main_window));
Core::System::GetInstance().RegisterMiiSelector(std::make_shared<QtMiiSelector>(main_window));
Core::System::GetInstance().RegisterSoftwareKeyboard(std::make_shared<QtKeyboard>(main_window));
// Register Qt image interface
system.RegisterImageInterface(std::make_shared<QtImageInterface>());
Core::System::GetInstance().RegisterImageInterface(std::make_shared<QtImageInterface>());
main_window.show();

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