Compare commits

...

154 Commits

Author SHA1 Message Date
797d0e45ce blit screen temp 2022-11-16 21:54:09 +02:00
37ce0540ed vk_texture_runtime: HACK skip texture flushes 2022-11-15 13:59:03 +02:00
e978931574 renderer_vulkan: Fix LMDM crashes
* Cache vertex format lookups to avoid crashing the driver when the game does too many lookups

* Increase watcher count. For some reason the game uses way too many watchers

* Fix other misc SPIRV bugs and don't crash when shadow is requested
2022-11-13 15:29:16 +02:00
facddbfc8c vk_shader_gen_spv: Implement alpha testing
* Should fix all current graphical bugs
2022-11-13 10:38:54 +02:00
68a3217d1e vk_instance: Make DynamicLoader static
* That way we don't construct/destroy it all the time
2022-11-12 21:36:25 +02:00
ddfae0025c citra_qt: Add SPIR-V shader option 2022-11-07 22:33:53 +02:00
75b6c5b4c5 externals: Update sirit 2022-11-06 22:13:07 +02:00
32c6e76ab9 renderer_vulkan: Move fragment shader microprofile to a better place 2022-11-06 21:57:30 +02:00
479c7ed162 shader_cache: Fix type deduction 2022-11-06 21:41:57 +02:00
009dfa5265 cmake: Fork sirit
* Upstream is missing some required instructions
2022-11-06 21:30:57 +02:00
b225239e1f renderer_vulkan: Begin new fragment shader SPIR-V emitter 2022-11-06 20:34:40 +02:00
f887621921 renderer_vulkan: Drop requirement for VK_EXT_depth_clip_control 2022-11-03 15:32:15 +02:00
407ae3972a Revert "code: Use std::numbers::pi"
* Not available on Android

This reverts commit d6e545932a.
2022-11-03 14:01:24 +02:00
0f0ca03551 Revert "CI: dont upload macos artifacts (#6121)"
This reverts commit 30831e6367.
2022-11-03 07:12:54 +02:00
9ae84fb6e8 renderer_vulkan: Integrate MacOS wsi 2022-11-02 23:19:50 +02:00
215255d415 video_core: Fix build issues on macos 2022-11-02 23:10:31 +02:00
f5f88101e1 renderer_vulkan: Emulate 3-component vertex formats when unsupported
* This fixes the crashes on AMD
2022-11-02 21:46:58 +02:00
e511e51491 renderer_vulkan: Emulate logic op when unsupported
* Similar to GLES this is done to prepare for the android port
2022-11-01 14:24:45 +02:00
242047744e gl_rasterizer: Cleanup and fix bugs 2022-10-31 21:58:14 +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
209 changed files with 39031 additions and 6969 deletions

View File

@ -95,6 +95,13 @@ 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:

12
.gitmodules vendored
View File

@ -58,3 +58,15 @@
[submodule "sdl2"]
path = externals/sdl2/SDL
url = https://github.com/libsdl-org/SDL
[submodule "vulkan-headers"]
path = externals/vulkan-headers
url = https://github.com/KhronosGroup/Vulkan-Headers
[submodule "glslang"]
path = externals/glslang
url = https://github.com/KhronosGroup/glslang
[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,15 +1,15 @@
# CMake 3.12 required for 20 to be a valid value for CXX_STANDARD
cmake_minimum_required(VERSION 3.12)
if (${CMAKE_VERSION} VERSION_GREATER_EQUAL 3.15)
# Don't override the warning flags in MSVC:
cmake_policy(SET CMP0092 NEW)
# Enforce new LTO setting
cmake_policy(SET CMP0069 NEW)
endif()
cmake_minimum_required(VERSION 3.14)
# Don't override the warning flags in MSVC:
cmake_policy(SET CMP0092 NEW)
# Enforce new LTO setting
cmake_policy(SET CMP0069 NEW)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/externals/cmake-modules")
include(DownloadExternals)
include(GNUInstallDirs)
include(CMakeDependentOption)
project(citra LANGUAGES C CXX ASM)

View File

@ -13,6 +13,6 @@
<file alias="256x256/plus_folder.png">icons/256x256/plus_folder.png</file>
</qresource>
<qresource prefix="colorful">
<file>style.qss</file>
<file alias="style.qss">../default/style.qss</file>
</qresource>
</RCC>

View File

@ -1,4 +0,0 @@
/*
This file is intentionally left blank.
We do not want to apply any stylesheet for colorful, only icons.
*/

View File

@ -1,33 +1,22 @@
<RCC>
<qresource prefix="icons/default">
<file alias="index.theme">icons/index.theme</file>
<file alias="16x16/checked.png">icons/16x16/checked.png</file>
<file alias="16x16/failed.png">icons/16x16/failed.png</file>
<file alias="16x16/connected.png">icons/16x16/connected.png</file>
<file alias="16x16/disconnected.png">icons/16x16/disconnected.png</file>
<file alias="16x16/connected_notification.png">icons/16x16/connected_notification.png</file>
<file alias="16x16/lock.png">icons/16x16/lock.png</file>
<file alias="48x48/bad_folder.png">icons/48x48/bad_folder.png</file>
<file alias="48x48/chip.png">icons/48x48/chip.png</file>
<file alias="48x48/folder.png">icons/48x48/folder.png</file>
<file alias="48x48/no_avatar.png">icons/48x48/no_avatar.png</file>
<file alias="48x48/plus.png">icons/48x48/plus.png</file>
<file alias="48x48/sd_card.png">icons/48x48/sd_card.png</file>
<file alias="256x256/citra.png">icons/256x256/citra.png</file>
<file alias="256x256/plus_folder.png">icons/256x256/plus_folder.png</file>
</qresource>
<qresource prefix="default">
<file>style.qss</file>
</qresource>
</RCC>

13
dist/qt_themes/default/style.qss vendored Normal file
View File

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

View File

@ -522,13 +522,12 @@ QToolButton#qt_toolbar_ext_button {
QPushButton {
color: #eff0f1;
border-width: 1px;
border-color: #54575B;
border-style: solid;
padding: 6px 4px;
border: 1px solid #54575B;
border-radius: 2px;
padding: 5px 0px 5px 0px;
outline: none;
min-width: 100px;
min-height: 13px;
background-color: #232629;
}
@ -1237,3 +1236,17 @@ QPlainTextEdit:disabled {
TouchScreenPreview {
qproperty-dotHighlightColor: #3daee9;
}
QPushButton#GraphicsAPIStatusBarButton {
color: #656565;
border: 1px solid transparent;
background-color: transparent;
padding: 0px 3px 0px 3px;
text-align: center;
min-width: 60px;
min-height: 20px;
}
QPushButton#GraphicsAPIStatusBarButton:hover {
border: 1px solid #76797C;
}

View File

@ -60,6 +60,19 @@ endif()
# Glad
add_subdirectory(glad)
# glslang
set(SKIP_GLSLANG_INSTALL ON)
set(ENABLE_GLSLANG_BINARIES OFF)
set(ENABLE_SPVREMAPPER OFF)
set(ENABLE_CTEST OFF)
add_subdirectory(glslang)
# Sirit
add_subdirectory(sirit)
# glm
add_subdirectory(glm)
# inih
add_subdirectory(inih)
@ -154,3 +167,12 @@ if(ANDROID)
add_subdirectory(libyuv)
target_include_directories(yuv INTERFACE ./libyuv/include)
endif()
# VMA
add_library(vma INTERFACE)
target_include_directories(vma INTERFACE ./vma)
# vulkan-headers
add_library(vulkan-headers INTERFACE)
target_include_directories(vulkan-headers INTERFACE ./vulkan-headers/include)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1
externals/glm vendored Submodule

Submodule externals/glm added at cc98465e35

1
externals/glslang vendored Submodule

Submodule externals/glslang added at c0cf8ad876

View File

@ -847,7 +847,7 @@ inline MicroProfileLogEntry MicroProfileMakeLogIndex(uint64_t nBegin, MicroProfi
MicroProfileLogEntry Entry = (nBegin<<62) | ((0x3fff&nToken)<<48) | (MP_LOG_TICK_MASK&nTick);
int t = MicroProfileLogType(Entry);
uint64_t nTimerIndex = MicroProfileLogTimerIndex(Entry);
MP_ASSERT(t == nBegin);
MP_ASSERT(static_cast<uint64_t>(t) == nBegin);
MP_ASSERT(nTimerIndex == (nToken&0x3fff));
return Entry;
@ -1579,10 +1579,10 @@ void MicroProfileFlip()
pFramePut->nFrameStartCpu = MP_TICK();
pFramePut->nFrameStartGpu = (uint32_t)MicroProfileGpuInsertTimeStamp();
if(pFrameNext->nFrameStartGpu != (uint64_t)-1)
if(static_cast<uint64_t>(pFrameNext->nFrameStartGpu) != (uint64_t)-1)
pFrameNext->nFrameStartGpu = MicroProfileGpuGetTimeStamp((uint32_t)pFrameNext->nFrameStartGpu);
if(pFrameCurrent->nFrameStartGpu == (uint64_t)-1)
if(static_cast<uint64_t>(pFrameCurrent->nFrameStartGpu) == (uint64_t)-1)
pFrameCurrent->nFrameStartGpu = pFrameNext->nFrameStartGpu + 1;
uint64_t nFrameStartCpu = pFrameCurrent->nFrameStartCpu;

View File

@ -354,7 +354,7 @@ void MicroProfileInitUI()
if(!bInitialized)
{
bInitialized = true;
memset(&g_MicroProfileUI, 0, sizeof(g_MicroProfileUI));
g_MicroProfileUI = {};
UI.nActiveMenu = UINT32_MAX;
UI.fDetailedOffsetTarget = UI.fDetailedOffset = 0.f;
UI.fDetailedRangeTarget = UI.fDetailedRange = 50.f;
@ -845,8 +845,8 @@ void MicroProfileDrawDetailedBars(uint32_t nWidth, uint32_t nHeight, int nBaseY,
MicroProfile& S = *MicroProfileGet();
MP_DEBUG_DUMP_RANGE();
int nY = nBaseY - UI.nOffsetY;
int64_t nNumBoxes = 0;
int64_t nNumLines = 0;
[[maybe_unused]] int64_t nNumBoxes = 0;
[[maybe_unused]] int64_t nNumLines = 0;
uint32_t nFrameNext = (S.nFrameCurrent+1) % MICROPROFILE_MAX_FRAME_HISTORY;
MicroProfileFrameState* pFrameCurrent = &S.Frames[S.nFrameCurrent];
@ -1988,7 +1988,7 @@ const char* MicroProfileUIMenuGroups(int nIndex, bool* bSelected)
else
{
nIndex = nIndex-1;
if(nIndex < UI.GroupMenuCount)
if(static_cast<uint32_t>(nIndex) < UI.GroupMenuCount)
{
MicroProfileGroupMenuItem& Item = UI.GroupMenu[nIndex];
static char buffer[MICROPROFILE_NAME_MAX_LEN+32];
@ -2135,7 +2135,7 @@ const char* MicroProfileUIMenuCustom(int nIndex, bool* bSelected)
case 1: return "--";
default:
nIndex -= 2;
if(nIndex < UI.nCustomCount)
if(static_cast<uint32_t>(nIndex) < UI.nCustomCount)
{
return UI.Custom[nIndex].pName;
}
@ -2185,7 +2185,7 @@ void MicroProfileUIClickGroups(int nIndex)
else
{
nIndex -= 1;
if(nIndex < UI.GroupMenuCount)
if(static_cast<uint32_t>(nIndex) < UI.GroupMenuCount)
{
MicroProfileGroupMenuItem& Item = UI.GroupMenu[nIndex];
if(Item.nIsCategory)

View File

@ -39,9 +39,9 @@ set(SDL_JOYSTICK ON CACHE BOOL "")
set(SDL_HAPTIC OFF CACHE BOOL "")
set(SDL_HIDAPI ON CACHE BOOL "")
set(SDL_POWER OFF CACHE BOOL "")
set(SDL_THREADS ON CACHE BOOL "")
set(SDL_TIMERS ON CACHE BOOL "")
set(SDL_FILE ON CACHE BOOL "")
set(SDL_THREADS ON CACHE BOOL "")
set(SDL_LOADSO ON CACHE BOOL "")
set(SDL_CPUINFO OFF CACHE BOOL "")
set(SDL_FILESYSTEM OFF CACHE BOOL "")

1
externals/sirit vendored Submodule

Submodule externals/sirit added at 297d820eeb

19670
externals/vma/vk_mem_alloc.h vendored Normal file

File diff suppressed because it is too large Load Diff

1
externals/vulkan-headers vendored Submodule

View File

@ -103,6 +103,7 @@ else()
if (MINGW)
add_definitions(-DMINGW_HAS_SECURE_API)
add_compile_options("-Wa,-mbig-obj")
if (COMPILE_WITH_DWARF)
add_compile_options("-gdwarf")
endif()

View File

@ -22,7 +22,6 @@
#include "core/frontend/applets/default_applets.h"
#include "core/frontend/camera/factory.h"
#include "core/frontend/mic.h"
#include "core/frontend/scope_acquire_context.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/nfc/nfc.h"
#include "core/savestate.h"

View File

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

View File

@ -7,17 +7,7 @@
#include <regex>
#include <string>
#include <thread>
// This needs to be included before getopt.h because the latter #defines symbols used by it
#include "common/microprofile.h"
#ifdef _WIN32
// windows.h needs to be included before shellapi.h
#include <windows.h>
#include <shellapi.h>
#endif
#include "citra/config.h"
#include "citra/emu_window/emu_window_sdl2.h"
#include "citra/lodepng_image_interface.h"
@ -25,21 +15,17 @@
#include "common/detached_tasks.h"
#include "common/file_util.h"
#include "common/logging/backend.h"
#include "common/logging/filter.h"
#include "common/logging/log.h"
#include "common/microprofile.h"
#include "common/scm_rev.h"
#include "common/scope_exit.h"
#include "common/string_util.h"
#include "core/core.h"
#include "core/dumping/backend.h"
#include "core/file_sys/cia_container.h"
#include "core/frontend/applets/default_applets.h"
#include "core/frontend/framebuffer_layout.h"
#include "core/frontend/scope_acquire_context.h"
#include "core/gdbstub/gdbstub.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/cfg/cfg.h"
#include "core/loader/loader.h"
#include "core/movie.h"
#include "core/settings.h"
#include "network/network.h"
@ -52,6 +38,11 @@
#endif
#ifdef _WIN32
// windows.h needs to be included before shellapi.h
#include <windows.h>
#include <shellapi.h>
extern "C" {
// tells Nvidia drivers to use the dedicated GPU by default on laptops with switchable graphics
__declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001;
@ -104,35 +95,35 @@ static void OnNetworkError(const Network::RoomMember::Error& error) {
break;
case Network::RoomMember::Error::CouldNotConnect:
LOG_ERROR(Network, "Error: Could not connect");
exit(1);
std::exit(1);
break;
case Network::RoomMember::Error::NameCollision:
LOG_ERROR(
Network,
"You tried to use the same nickname as another user that is connected to the Room");
exit(1);
std::exit(1);
break;
case Network::RoomMember::Error::MacCollision:
LOG_ERROR(Network, "You tried to use the same MAC-Address as another user that is "
"connected to the Room");
exit(1);
std::exit(1);
break;
case Network::RoomMember::Error::ConsoleIdCollision:
LOG_ERROR(Network, "Your Console ID conflicted with someone else in the Room");
exit(1);
std::exit(1);
break;
case Network::RoomMember::Error::WrongPassword:
LOG_ERROR(Network, "Room replied with: Wrong password");
exit(1);
std::exit(1);
break;
case Network::RoomMember::Error::WrongVersion:
LOG_ERROR(Network,
"You are using a different version than the room you are trying to connect to");
exit(1);
std::exit(1);
break;
case Network::RoomMember::Error::RoomIsFull:
LOG_ERROR(Network, "The room is full");
exit(1);
std::exit(1);
break;
case Network::RoomMember::Error::HostKicked:
LOG_ERROR(Network, "You have been kicked by the host");
@ -140,6 +131,8 @@ static void OnNetworkError(const Network::RoomMember::Error& error) {
case Network::RoomMember::Error::HostBanned:
LOG_ERROR(Network, "You have been banned by the host");
break;
default:
LOG_ERROR(Network, "Unknown network error {}", error);
}
}
@ -359,7 +352,7 @@ int main(int argc, char** argv) {
Core::System::GetInstance().RegisterImageInterface(std::make_shared<LodePNGImageInterface>());
std::unique_ptr<EmuWindow_SDL2> emu_window{std::make_unique<EmuWindow_SDL2>(fullscreen)};
Frontend::ScopeAcquireContext scope(*emu_window);
const auto scope = emu_window->Acquire();
Core::System& system = Core::System::GetInstance();
const Core::System::ResultStatus load_result{system.Load(*emu_window, filepath)};

View File

@ -109,7 +109,8 @@ void Config::ReadValues() {
sdl2_config->GetInteger("Core", "cpu_clock_percentage", 100);
// Renderer
Settings::values.use_gles = sdl2_config->GetBoolean("Renderer", "use_gles", false);
Settings::values.graphics_api =
static_cast<Settings::GraphicsAPI>(sdl2_config->GetInteger("Renderer", "graphics_api", 0));
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);
#ifdef __APPLE__

View File

@ -147,7 +147,8 @@ EmuWindow_SDL2::EmuWindow_SDL2(bool fullscreen) {
SDL_SetMainReady();
if (Settings::values.use_gles) {
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);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
@ -201,7 +202,7 @@ EmuWindow_SDL2::EmuWindow_SDL2(bool fullscreen) {
exit(1);
}
auto gl_load_func = Settings::values.use_gles ? gladLoadGLES2Loader : gladLoadGLLoader;
auto gl_load_func = is_opengles ? gladLoadGLES2Loader : gladLoadGLLoader;
if (!gl_load_func(static_cast<GLADloadproc>(SDL_GL_GetProcAddress))) {
LOG_CRITICAL(Frontend, "Failed to initialize GL functions: {}", SDL_GetError());

View File

@ -260,9 +260,13 @@ endif()
create_target_directory_groups(citra-qt)
target_link_libraries(citra-qt PRIVATE audio_core common core input_common network video_core)
target_link_libraries(citra-qt PRIVATE Boost::boost glad nihstro-headers Qt5::Widgets Qt5::Multimedia)
target_link_libraries(citra-qt PRIVATE Boost::boost glad vma vulkan-headers nihstro-headers Qt5::Widgets Qt5::Multimedia)
target_link_libraries(citra-qt PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads)
if (NOT WIN32)
target_include_directories(citra-qt PRIVATE ${Qt5Gui_PRIVATE_INCLUDE_DIRS})
endif()
target_compile_definitions(citra-qt PRIVATE
# Use QStringBuilder for string concatenation to reduce
# the overall number of temporary strings created.

View File

@ -54,12 +54,12 @@ QtKeyboardDialog::QtKeyboardDialog(QWidget* parent, QtKeyboard* keyboard_)
case ButtonConfig::None:
break;
}
connect(buttons, &QDialogButtonBox::accepted, this, [=] { Submit(); });
connect(buttons, &QDialogButtonBox::rejected, this, [=] {
connect(buttons, &QDialogButtonBox::accepted, this, [this] { Submit(); });
connect(buttons, &QDialogButtonBox::rejected, this, [this] {
button = QtKeyboard::cancel_id;
accept();
});
connect(buttons, &QDialogButtonBox::helpRequested, this, [=] {
connect(buttons, &QDialogButtonBox::helpRequested, this, [this] {
button = QtKeyboard::forgot_id;
accept();
});

View File

@ -6,10 +6,10 @@
#include <QDragEnterEvent>
#include <QHBoxLayout>
#include <QKeyEvent>
#include <QMessageBox>
#include <QOffscreenSurface>
#include <QOpenGLContext>
#include <QOpenGLFunctions>
#include <QOpenGLFunctions_4_3_Core>
#include <QOpenGLExtraFunctions>
#include <fmt/format.h>
#include "citra_qt/bootmanager.h"
#include "citra_qt/main.h"
@ -17,56 +17,60 @@
#include "common/scm_rev.h"
#include "core/3ds.h"
#include "core/core.h"
#include "core/frontend/scope_acquire_context.h"
#include "core/perf_stats.h"
#include "core/settings.h"
#include "input_common/keyboard.h"
#include "input_common/main.h"
#include "input_common/motion_emu.h"
#include "network/network.h"
#include "video_core/renderer_base.h"
#include "video_core/video_core.h"
#if !defined(WIN32)
#include <qpa/qplatformnativeinterface.h>
#endif
EmuThread::EmuThread(Frontend::GraphicsContext& core_context) : core_context(core_context) {}
EmuThread::~EmuThread() = default;
static GMainWindow* GetMainWindow() {
for (QWidget* w : qApp->topLevelWidgets()) {
const auto widgets = qApp->topLevelWidgets();
for (QWidget* w : widgets) {
if (GMainWindow* main = qobject_cast<GMainWindow*>(w)) {
return main;
}
}
return nullptr;
}
void EmuThread::run() {
MicroProfileOnThreadCreate("EmuThread");
Frontend::ScopeAcquireContext scope(core_context);
const auto scope = core_context.Acquire();
emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0);
Core::System::GetInstance().Renderer().Rasterizer()->LoadDiskResources(
Core::System& system = Core::System::GetInstance();
system.Renderer().Rasterizer()->LoadDiskResources(
stop_run, [this](VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total) {
emit LoadProgress(stage, value, total);
});
emit LoadProgress(VideoCore::LoadCallbackStage::Complete, 0, 0);
emit HideLoadingScreen();
core_context.MakeCurrent();
if (Core::System::GetInstance().frame_limiter.IsFrameAdvancing()) {
if (system.frame_limiter.IsFrameAdvancing()) {
// Usually the loading screen is hidden after the first frame is drawn. In this case
// we hide it immediately as we need to wait for user input to start the emulation.
emit HideLoadingScreen();
Core::System::GetInstance().frame_limiter.WaitOnce();
system.frame_limiter.WaitOnce();
}
// Holds whether the cpu was running during the last iteration,
// so that the DebugModeLeft signal can be emitted before the
// next execution step.
bool was_active = false;
Core::System& system = Core::System::GetInstance();
while (!stop_run) {
if (running) {
if (!was_active)
@ -111,87 +115,236 @@ void EmuThread::run() {
#endif
}
OpenGLWindow::OpenGLWindow(QWindow* parent, QWidget* event_handler, QOpenGLContext* shared_context)
: QWindow(parent), context(std::make_unique<QOpenGLContext>(shared_context->parent())),
event_handler(event_handler) {
class OpenGLSharedContext : public Frontend::GraphicsContext {
public:
/// Create the original context that should be shared from
explicit OpenGLSharedContext(QSurface* surface) : surface(surface) {
QSurfaceFormat format;
// disable vsync for any shared contexts
auto format = shared_context->format();
format.setSwapInterval(Settings::values.use_vsync_new ? 1 : 0);
this->setFormat(format);
format.setVersion(4, 4);
format.setProfile(QSurfaceFormat::CoreProfile);
context->setShareContext(shared_context);
context->setScreen(this->screen());
context->setFormat(format);
context->create();
if (Settings::values.renderer_debug) {
format.setOption(QSurfaceFormat::FormatOption::DebugContext);
}
setSurfaceType(QWindow::OpenGLSurface);
// TODO: expose a setting for buffer value (ie default/single/double/triple)
format.setSwapBehavior(QSurfaceFormat::DefaultSwapBehavior);
format.setSwapInterval(0);
// TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground,
// WA_DontShowOnScreen, WA_DeleteOnClose
}
OpenGLWindow::~OpenGLWindow() {
context->doneCurrent();
}
void OpenGLWindow::Present() {
if (!isExposed())
return;
context->makeCurrent(this);
if (VideoCore::g_renderer) {
VideoCore::g_renderer->TryPresent(100);
context = std::make_unique<QOpenGLContext>();
context->setFormat(format);
if (!context->create()) {
LOG_ERROR(Frontend, "Unable to create main openGL context");
}
}
context->swapBuffers(this);
auto f = context->versionFunctions<QOpenGLFunctions_4_3_Core>();
f->glFinish();
QWindow::requestUpdate();
}
bool OpenGLWindow::event(QEvent* event) {
switch (event->type()) {
case QEvent::UpdateRequest:
/// Create the shared contexts for rendering and presentation
explicit OpenGLSharedContext(QOpenGLContext* share_context, QSurface* main_surface = nullptr) {
// disable vsync for any shared contexts
auto format = share_context->format();
format.setSwapInterval(main_surface ? Settings::values.use_vsync_new : 0);
context = std::make_unique<QOpenGLContext>();
context->setShareContext(share_context);
context->setFormat(format);
if (!context->create()) {
LOG_ERROR(Frontend, "Unable to create shared openGL context");
}
if (!main_surface) {
offscreen_surface = std::make_unique<QOffscreenSurface>(nullptr);
offscreen_surface->setFormat(format);
offscreen_surface->create();
surface = offscreen_surface.get();
} else {
surface = main_surface;
}
}
~OpenGLSharedContext() {
context->doneCurrent();
}
void SwapBuffers() override {
context->swapBuffers(surface);
}
void MakeCurrent() override {
// We can't track the current state of the underlying context in this wrapper class because
// Qt may make the underlying context not current for one reason or another. In particular,
// the WebBrowser uses GL, so it seems to conflict if we aren't careful.
// Instead of always just making the context current (which does not have any caching to
// check if the underlying context is already current) we can check for the current context
// in the thread local data by calling `currentContext()` and checking if its ours.
if (QOpenGLContext::currentContext() != context.get()) {
context->makeCurrent(surface);
}
}
void DoneCurrent() override {
context->doneCurrent();
}
QOpenGLContext* GetShareContext() const {
return context.get();
}
private:
// Avoid using Qt parent system here since we might move the QObjects to new threads
// As a note, this means we should avoid using slots/signals with the objects too
std::unique_ptr<QOpenGLContext> context;
std::unique_ptr<QOffscreenSurface> offscreen_surface{};
QSurface* surface;
};
class DummyContext : public Frontend::GraphicsContext {};
class RenderWidget : public QWidget {
public:
RenderWidget(GRenderWindow* parent) : QWidget(parent), render_window(parent) {
setAttribute(Qt::WA_NativeWindow);
setAttribute(Qt::WA_PaintOnScreen);
}
virtual ~RenderWidget() = default;
virtual void Present() {}
void paintEvent(QPaintEvent* event) override {
Present();
return true;
case QEvent::MouseButtonPress:
case QEvent::MouseButtonRelease:
case QEvent::MouseButtonDblClick:
case QEvent::MouseMove:
case QEvent::KeyPress:
case QEvent::KeyRelease:
case QEvent::FocusIn:
case QEvent::FocusOut:
case QEvent::FocusAboutToChange:
case QEvent::Enter:
case QEvent::Leave:
case QEvent::Wheel:
case QEvent::TabletMove:
case QEvent::TabletPress:
case QEvent::TabletRelease:
case QEvent::TabletEnterProximity:
case QEvent::TabletLeaveProximity:
case QEvent::TouchBegin:
case QEvent::TouchUpdate:
case QEvent::TouchEnd:
case QEvent::InputMethodQuery:
case QEvent::TouchCancel:
return QCoreApplication::sendEvent(event_handler, event);
case QEvent::Drop:
GetMainWindow()->DropAction(static_cast<QDropEvent*>(event));
return true;
case QEvent::DragEnter:
case QEvent::DragMove:
GetMainWindow()->AcceptDropEvent(static_cast<QDropEvent*>(event));
return true;
default:
return QWindow::event(event);
update();
}
void resizeEvent(QResizeEvent* ev) override {
render_window->resize(ev->size());
render_window->OnFramebufferSizeChanged();
}
void keyPressEvent(QKeyEvent* event) override {
InputCommon::GetKeyboard()->PressKey(event->key());
}
void keyReleaseEvent(QKeyEvent* event) override {
InputCommon::GetKeyboard()->ReleaseKey(event->key());
}
void mousePressEvent(QMouseEvent* event) override {
if (event->source() == Qt::MouseEventSynthesizedBySystem)
return; // touch input is handled in TouchBeginEvent
const auto pos{event->pos()};
if (event->button() == Qt::LeftButton) {
const auto [x, y] = render_window->ScaleTouch(pos);
render_window->TouchPressed(x, y);
} else if (event->button() == Qt::RightButton) {
InputCommon::GetMotionEmu()->BeginTilt(pos.x(), pos.y());
}
}
void mouseMoveEvent(QMouseEvent* event) override {
if (event->source() == Qt::MouseEventSynthesizedBySystem)
return; // touch input is handled in TouchUpdateEvent
const auto pos{event->pos()};
const auto [x, y] = render_window->ScaleTouch(pos);
render_window->TouchMoved(x, y);
InputCommon::GetMotionEmu()->Tilt(pos.x(), pos.y());
}
void mouseReleaseEvent(QMouseEvent* event) override {
if (event->source() == Qt::MouseEventSynthesizedBySystem)
return; // touch input is handled in TouchEndEvent
if (event->button() == Qt::LeftButton)
render_window->TouchReleased();
else if (event->button() == Qt::RightButton)
InputCommon::GetMotionEmu()->EndTilt();
}
std::pair<unsigned, unsigned> GetSize() const {
return std::make_pair(width(), height());
}
QPaintEngine* paintEngine() const override {
return nullptr;
}
private:
GRenderWindow* render_window;
};
class OpenGLRenderWidget : public RenderWidget {
public:
explicit OpenGLRenderWidget(GRenderWindow* parent) : RenderWidget(parent) {
windowHandle()->setSurfaceType(QWindow::OpenGLSurface);
}
void SetContext(std::unique_ptr<OpenGLSharedContext>&& context_) {
context = std::move(context_);
}
void Present() override {
if (!isVisible()) {
return;
}
if (!Core::System::GetInstance().IsPoweredOn()) {
return;
}
context->MakeCurrent();
const auto f = context->GetShareContext()->extraFunctions();
f->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
VideoCore::g_renderer->TryPresent(100);
context->SwapBuffers();
f->glFinish();
}
private:
std::unique_ptr<OpenGLSharedContext> context{};
};
class VulkanRenderWidget : public RenderWidget {
public:
explicit VulkanRenderWidget(GRenderWindow* parent) : RenderWidget(parent) {
windowHandle()->setSurfaceType(QWindow::VulkanSurface);
}
};
static Frontend::WindowSystemType GetWindowSystemType() {
// Determine WSI type based on Qt platform.
QString platform_name = QGuiApplication::platformName();
if (platform_name == QStringLiteral("windows"))
return Frontend::WindowSystemType::Windows;
else if (platform_name == QStringLiteral("xcb"))
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;
}
void OpenGLWindow::exposeEvent(QExposeEvent* event) {
QWindow::requestUpdate();
QWindow::exposeEvent(event);
static Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window) {
Frontend::EmuWindow::WindowSystemInfo wsi;
wsi.type = GetWindowSystemType();
// Our Win32 Qt external doesn't have the private API.
#if defined(WIN32) || defined(__APPLE__)
wsi.render_surface = window ? reinterpret_cast<void*>(window->winId()) : nullptr;
#else
QPlatformNativeInterface* pni = QGuiApplication::platformNativeInterface();
wsi.display_connection = pni->nativeResourceForWindow("display", window);
if (wsi.type == Frontend::WindowSystemType::Wayland)
wsi.render_surface = window ? pni->nativeResourceForWindow("surface", window) : nullptr;
else
wsi.render_surface = window ? reinterpret_cast<void*>(window->winId()) : nullptr;
#endif
wsi.render_surface_scale = window ? static_cast<float>(window->devicePixelRatio()) : 1.0f;
return wsi;
}
GRenderWindow::GRenderWindow(QWidget* parent_, EmuThread* emu_thread)
@ -218,11 +371,11 @@ GRenderWindow::~GRenderWindow() {
}
void GRenderWindow::MakeCurrent() {
core_context->MakeCurrent();
main_context->MakeCurrent();
}
void GRenderWindow::DoneCurrent() {
core_context->DoneCurrent();
main_context->DoneCurrent();
}
void GRenderWindow::PollEvents() {
@ -387,33 +540,70 @@ void GRenderWindow::resizeEvent(QResizeEvent* event) {
OnFramebufferSizeChanged();
}
void GRenderWindow::InitRenderTarget() {
std::unique_ptr<Frontend::GraphicsContext> GRenderWindow::CreateSharedContext() const {
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());
// Bind the shared contexts to the main surface in case the backend wants to take over
// presentation
return std::make_unique<OpenGLSharedContext>(c->GetShareContext(),
child_widget->windowHandle());
}
return std::make_unique<DummyContext>();
}
bool GRenderWindow::InitRenderTarget() {
ReleaseRenderTarget();
{
// Create a dummy render widget so that Qt
// places the render window at the correct position.
const RenderWidget dummy_widget{this};
}
first_frame = false;
GMainWindow* parent = GetMainWindow();
QWindow* parent_win_handle = parent ? parent->windowHandle() : nullptr;
child_window = new OpenGLWindow(parent_win_handle, this, QOpenGLContext::globalShareContext());
child_window->create();
child_widget = createWindowContainer(child_window, this);
const Settings::GraphicsAPI graphics_api = Settings::values.graphics_api;
switch (graphics_api) {
case Settings::GraphicsAPI::OpenGL:
case Settings::GraphicsAPI::OpenGLES:
if (!InitializeOpenGL()) {
return false;
}
break;
case Settings::GraphicsAPI::Vulkan:
if (!InitializeVulkan()) {
return false;
}
break;
}
// Update the Window System information with the new render target
window_info = GetWindowSystemInfo(child_widget->windowHandle());
child_widget->resize(Core::kScreenTopWidth, Core::kScreenTopHeight + Core::kScreenBottomHeight);
layout()->addWidget(child_widget);
// Reset minimum required size to avoid resizing issues on the main window after restarting.
setMinimumSize(1, 1);
core_context = CreateSharedContext();
resize(Core::kScreenTopWidth, Core::kScreenTopHeight + Core::kScreenBottomHeight);
OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size);
OnFramebufferSizeChanged();
BackupGeometry();
return true;
}
void GRenderWindow::ReleaseRenderTarget() {
if (child_widget) {
layout()->removeWidget(child_widget);
delete child_widget;
child_widget->deleteLater();
child_widget = nullptr;
}
main_context.reset();
}
void GRenderWindow::CaptureScreenshot(u32 res_scale, const QString& screenshot_path) {
@ -423,7 +613,7 @@ void GRenderWindow::CaptureScreenshot(u32 res_scale, const QString& screenshot_p
screenshot_image = QImage(QSize(layout.width, layout.height), QImage::Format_RGB32);
VideoCore::RequestScreenshot(
screenshot_image.bits(),
[=] {
[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);
@ -438,6 +628,29 @@ void GRenderWindow::OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal
setMinimumSize(minimal_size.first, minimal_size.second);
}
bool GRenderWindow::InitializeOpenGL() {
// TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground,
// WA_DontShowOnScreen, WA_DeleteOnClose
auto child = new OpenGLRenderWidget(this);
child_widget = child;
child_widget->windowHandle()->create();
auto context = std::make_shared<OpenGLSharedContext>(child->windowHandle());
main_context = context;
child->SetContext(
std::make_unique<OpenGLSharedContext>(context->GetShareContext(), child->windowHandle()));
return true;
}
bool GRenderWindow::InitializeVulkan() {
auto child = new VulkanRenderWidget(this);
child_widget = child;
child_widget->windowHandle()->create();
main_context = std::make_unique<DummyContext>();
return true;
}
void GRenderWindow::OnEmulationStarting(EmuThread* emu_thread) {
this->emu_thread = emu_thread;
}
@ -449,31 +662,3 @@ void GRenderWindow::OnEmulationStopping() {
void GRenderWindow::showEvent(QShowEvent* event) {
QWidget::showEvent(event);
}
std::unique_ptr<Frontend::GraphicsContext> GRenderWindow::CreateSharedContext() const {
return std::make_unique<GLContext>(QOpenGLContext::globalShareContext());
}
GLContext::GLContext(QOpenGLContext* shared_context)
: context(std::make_unique<QOpenGLContext>(shared_context->parent())),
surface(std::make_unique<QOffscreenSurface>(nullptr)) {
// disable vsync for any shared contexts
auto format = shared_context->format();
format.setSwapInterval(0);
context->setShareContext(shared_context);
context->setFormat(format);
context->create();
surface->setParent(shared_context->parent());
surface->setFormat(format);
surface->create();
}
void GLContext::MakeCurrent() {
context->makeCurrent(surface.get());
}
void GLContext::DoneCurrent() {
context->doneCurrent();
}

View File

@ -27,19 +27,6 @@ namespace VideoCore {
enum class LoadCallbackStage;
}
class GLContext : public Frontend::GraphicsContext {
public:
explicit GLContext(QOpenGLContext* shared_context);
void MakeCurrent() override;
void DoneCurrent() override;
private:
std::unique_ptr<QOpenGLContext> context;
std::unique_ptr<QOffscreenSurface> surface;
};
class EmuThread final : public QThread {
Q_OBJECT
@ -126,24 +113,6 @@ signals:
void HideLoadingScreen();
};
class OpenGLWindow : public QWindow {
Q_OBJECT
public:
explicit OpenGLWindow(QWindow* parent, QWidget* event_handler, QOpenGLContext* shared_context);
~OpenGLWindow();
void Present();
protected:
bool event(QEvent* event) override;
void exposeEvent(QExposeEvent* event) override;
private:
std::unique_ptr<QOpenGLContext> context;
QWidget* event_handler;
};
class GRenderWindow : public QWidget, public Frontend::EmuWindow {
Q_OBJECT
@ -179,13 +148,15 @@ public:
void focusOutEvent(QFocusEvent* event) override;
void InitRenderTarget();
bool InitRenderTarget();
/// Destroy the previous run's child_widget which should also destroy the child_window
void ReleaseRenderTarget();
void CaptureScreenshot(u32 res_scale, const QString& screenshot_path);
std::pair<u32, u32> ScaleTouch(const QPointF pos) const;
public slots:
void OnEmulationStarting(EmuThread* emu_thread);
@ -205,29 +176,29 @@ signals:
void MouseActivity();
private:
std::pair<u32, u32> ScaleTouch(QPointF pos) const;
void TouchBeginEvent(const QTouchEvent* event);
void TouchUpdateEvent(const QTouchEvent* event);
void TouchEndEvent();
void OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) override;
std::unique_ptr<GraphicsContext> core_context;
QByteArray geometry;
/// Native window handle that backs this presentation widget
QWindow* child_window = nullptr;
/// In order to embed the window into GRenderWindow, you need to use createWindowContainer to
/// put the child_window into a widget then add it to the layout. This child_widget can be
/// parented to GRenderWindow and use Qt's lifetime system
QWidget* child_widget = nullptr;
bool InitializeOpenGL();
bool InitializeVulkan();
EmuThread* emu_thread;
// Main context that will be shared with all other contexts that are requested.
// If this is used in a shared context setting, then this should not be used directly, but
// should instead be shared from
std::shared_ptr<Frontend::GraphicsContext> main_context;
/// Temporary storage of the screenshot taken
QImage screenshot_image;
QByteArray geometry;
QWidget* child_widget = nullptr;
bool first_frame = false;
protected:

View File

@ -37,7 +37,7 @@ CheatDialog::CheatDialog(QWidget* parent)
connect(ui->textNotes, &QPlainTextEdit::textChanged, this, &CheatDialog::OnTextEdited);
connect(ui->textCode, &QPlainTextEdit::textChanged, this, &CheatDialog::OnTextEdited);
connect(ui->buttonSave, &QPushButton::clicked,
connect(ui->buttonSave, &QPushButton::clicked, this,
[this] { SaveCheat(ui->tableCheats->currentRow()); });
connect(ui->buttonDelete, &QPushButton::clicked, this, &CheatDialog::OnDeleteCheat);
@ -91,7 +91,7 @@ bool CheatDialog::SaveCheat(int row) {
}
// Check if the cheat lines are valid
auto code_lines = ui->textCode->toPlainText().split(QLatin1Char{'\n'}, QString::SkipEmptyParts);
auto code_lines = ui->textCode->toPlainText().split(QLatin1Char{'\n'}, Qt::SkipEmptyParts);
for (int i = 0; i < code_lines.size(); ++i) {
Cheats::GatewayCheat::CheatLine cheat_line(code_lines[i].toStdString());
if (cheat_line.valid)
@ -190,8 +190,9 @@ void CheatDialog::OnDeleteCheat() {
if (newly_created) {
newly_created = false;
} else {
Core::System::GetInstance().CheatEngine().RemoveCheat(ui->tableCheats->currentRow());
Core::System::GetInstance().CheatEngine().SaveCheatFile();
auto& cheat_engine = Core::System::GetInstance().CheatEngine();
cheat_engine.RemoveCheat(ui->tableCheats->currentRow());
cheat_engine.SaveCheatFile();
}
LoadCheats();

View File

@ -327,6 +327,9 @@ void Config::ReadDebuggingValues() {
qt_config->value(QStringLiteral("record_frame_times"), false).toBool();
Settings::values.use_gdbstub = ReadSetting(QStringLiteral("use_gdbstub"), false).toBool();
Settings::values.gdbstub_port = ReadSetting(QStringLiteral("gdbstub_port"), 24689).toInt();
Settings::values.renderer_debug = ReadSetting(QStringLiteral("renderer_debug"), false).toBool();
Settings::values.dump_command_buffers =
ReadSetting(QStringLiteral("dump_command_buffers"), false).toBool();
qt_config->beginGroup(QStringLiteral("LLE"));
for (const auto& service_module : Service::service_module_map) {
@ -478,6 +481,12 @@ void Config::ReadPathValues() {
void Config::ReadRendererValues() {
qt_config->beginGroup(QStringLiteral("Renderer"));
Settings::values.graphics_api = static_cast<Settings::GraphicsAPI>(
ReadSetting(QStringLiteral("graphics_api"), static_cast<u32>(Settings::GraphicsAPI::OpenGL))
.toUInt());
Settings::values.physical_device = ReadSetting(QStringLiteral("physical_device"), 0).toUInt();
Settings::values.async_command_recording = ReadSetting(QStringLiteral("async_command_recording"), true).toBool();
Settings::values.spirv_shader_gen = ReadSetting(QStringLiteral("spirv_shader_gen"), false).toBool();
Settings::values.use_hw_renderer =
ReadSetting(QStringLiteral("use_hw_renderer"), true).toBool();
Settings::values.use_hw_shader = ReadSetting(QStringLiteral("use_hw_shader"), true).toBool();
@ -517,7 +526,7 @@ void Config::ReadRendererValues() {
void Config::ReadShortcutValues() {
qt_config->beginGroup(QStringLiteral("Shortcuts"));
for (auto [name, group, shortcut] : default_hotkeys) {
for (const auto& [name, group, shortcut] : default_hotkeys) {
auto [keyseq, context] = shortcut;
qt_config->beginGroup(group);
qt_config->beginGroup(name);
@ -552,7 +561,7 @@ void Config::ReadSystemValues() {
// https://developers.google.com/media/vp9/live-encoding
const QString DEFAULT_VIDEO_ENCODER_OPTIONS =
QStringLiteral("quality:realtime,speed:6,tile-columns:4,frame-parallel:1,threads:8,row-mt:1");
const QString DEFAULT_AUDIO_ENCODER_OPTIONS = QString{};
const QString DEFAULT_AUDIO_ENCODER_OPTIONS = QStringLiteral("");
void Config::ReadVideoDumpingValues() {
qt_config->beginGroup(QStringLiteral("VideoDumping"));
@ -883,6 +892,9 @@ void Config::SaveDebuggingValues() {
qt_config->setValue(QStringLiteral("record_frame_times"), Settings::values.record_frame_times);
WriteSetting(QStringLiteral("use_gdbstub"), Settings::values.use_gdbstub, false);
WriteSetting(QStringLiteral("gdbstub_port"), Settings::values.gdbstub_port, 24689);
WriteSetting(QStringLiteral("renderer_debug"), Settings::values.renderer_debug, false);
WriteSetting(QStringLiteral("dump_command_buffers"), Settings::values.dump_command_buffers,
false);
qt_config->beginGroup(QStringLiteral("LLE"));
for (const auto& service_module : Settings::values.lle_modules) {
@ -991,6 +1003,11 @@ void Config::SavePathValues() {
void Config::SaveRendererValues() {
qt_config->beginGroup(QStringLiteral("Renderer"));
WriteSetting(QStringLiteral("graphics_api"), static_cast<u32>(Settings::values.graphics_api),
static_cast<u32>(Settings::GraphicsAPI::OpenGL));
WriteSetting(QStringLiteral("physical_device"), Settings::values.physical_device, 0);
WriteSetting(QStringLiteral("async_command_recording"), Settings::values.async_command_recording, true);
WriteSetting(QStringLiteral("spirv_shader_gen"), Settings::values.spirv_shader_gen, false);
WriteSetting(QStringLiteral("use_hw_renderer"), Settings::values.use_hw_renderer, true);
WriteSetting(QStringLiteral("use_hw_shader"), Settings::values.use_hw_shader, true);
#ifdef __APPLE__
@ -1012,9 +1029,9 @@ void Config::SaveRendererValues() {
200);
// Cast to double because Qt's written float values are not human-readable
WriteSetting(QStringLiteral("bg_red"), (double)Settings::values.bg_red, 0.0);
WriteSetting(QStringLiteral("bg_green"), (double)Settings::values.bg_green, 0.0);
WriteSetting(QStringLiteral("bg_blue"), (double)Settings::values.bg_blue, 0.0);
WriteSetting(QStringLiteral("bg_red"), static_cast<double>(Settings::values.bg_red), 0.0);
WriteSetting(QStringLiteral("bg_green"), static_cast<double>(Settings::values.bg_green), 0.0);
WriteSetting(QStringLiteral("bg_blue"), static_cast<double>(Settings::values.bg_blue), 0.0);
WriteSetting(QStringLiteral("texture_filter_name"),
QString::fromStdString(Settings::values.texture_filter_name),

View File

@ -9,8 +9,6 @@
#include <QMessageBox>
#include <QWidget>
#include "citra_qt/configuration/configure_camera.h"
#include "citra_qt/uisettings.h"
#include "core/core.h"
#include "core/frontend/camera/factory.h"
#include "core/frontend/camera/interface.h"
#include "core/hle/service/cam/cam.h"
@ -91,7 +89,7 @@ void ConfigureCamera::ConnectEvents() {
SetConfiguration();
});
connect(ui->toolButton, &QToolButton::clicked, this, &ConfigureCamera::OnToolButtonClicked);
connect(ui->preview_button, &QPushButton::clicked, this, [=] { StartPreviewing(); });
connect(ui->preview_button, &QPushButton::clicked, this, [this] { StartPreviewing(); });
connect(ui->prompt_before_load, &QCheckBox::stateChanged, this, [this](int state) {
ui->camera_file->setDisabled(state == Qt::Checked);
ui->toolButton->setDisabled(state == Qt::Checked);
@ -99,12 +97,11 @@ void ConfigureCamera::ConnectEvents() {
ui->camera_file->setText(QString{});
}
});
connect(ui->camera_file, &QLineEdit::textChanged, this, [=] { StopPreviewing(); });
connect(ui->system_camera,
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
[=] { StopPreviewing(); });
connect(ui->camera_flip, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
this, [=] { StopPreviewing(); });
connect(ui->camera_file, &QLineEdit::textChanged, this, [this] { StopPreviewing(); });
connect(ui->system_camera, qOverload<int>(&QComboBox::currentIndexChanged), this,
[this] { StopPreviewing(); });
connect(ui->camera_flip, qOverload<int>(&QComboBox::currentIndexChanged), this,
[this] { StopPreviewing(); });
}
void ConfigureCamera::UpdateCameraMode() {

View File

@ -4,16 +4,17 @@
#include <QDesktopServices>
#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/backend.h"
#include "common/logging/filter.h"
#include "common/logging/log.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"
ConfigureDebug::ConfigureDebug(QWidget* parent)
: QWidget(parent), ui(std::make_unique<Ui::ConfigureDebug>()) {
@ -24,7 +25,41 @@ ConfigureDebug::ConfigureDebug(QWidget* parent)
QString path = QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::LogDir));
QDesktopServices::openUrl(QUrl::fromLocalFile(path));
});
ui->toggle_cpu_jit->setEnabled(!Core::System::GetInstance().IsPoweredOn());
connect(ui->toggle_renderer_debug, &QCheckBox::clicked, this, [this](bool checked) {
if (checked && Settings::values.graphics_api == Settings::GraphicsAPI::Vulkan) {
try {
Vulkan::Instance debug_inst{true};
} 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"));
}
}
});
connect(ui->toggle_dump_command_buffers, &QCheckBox::clicked, this, [this](bool checked) {
if (checked && Settings::values.graphics_api == Settings::GraphicsAPI::Vulkan) {
try {
Vulkan::Instance debug_inst{false, true};
} 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"));
}
}
});
const bool is_powered_on = Core::System::GetInstance().IsPoweredOn();
ui->toggle_cpu_jit->setEnabled(!is_powered_on);
ui->toggle_renderer_debug->setEnabled(!is_powered_on);
ui->toggle_dump_command_buffers->setEnabled(!is_powered_on);
}
ConfigureDebug::~ConfigureDebug() = default;
@ -37,6 +72,8 @@ void ConfigureDebug::SetConfiguration() {
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() {
@ -49,6 +86,8 @@ void ConfigureDebug::ApplyConfiguration() {
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();
Settings::values.dump_command_buffers = ui->toggle_dump_command_buffers->isChecked();
}
void ConfigureDebug::RetranslateUI() {

View File

@ -22,5 +22,6 @@ public:
void RetranslateUI();
void SetConfiguration();
private:
std::unique_ptr<Ui::ConfigureDebug> ui;
};

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>443</width>
<height>300</height>
<width>454</width>
<height>356</height>
</rect>
</property>
<property name="windowTitle">
@ -114,11 +114,31 @@
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QCheckBox" name="toggle_cpu_jit">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enables the use of the ARM JIT compiler for emulating the 3DS CPUs. Don't disable unless for debugging purposes&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Enable CPU JIT</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="toggle_renderer_debug">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enables debug reporting in the currently selected graphics API. Causes measurable performance loss, don't enable unless for debugging purposes&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Enable debug renderer</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="toggle_dump_command_buffers">
<property name="text">
<string>Dump command buffers</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>

View File

@ -10,15 +10,28 @@
#include "core/core.h"
#include "core/settings.h"
#include "ui_configure_graphics.h"
#include "video_core/renderer_opengl/post_processing_opengl.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();
SetConfiguration();
ui->hw_renderer_group->setEnabled(ui->toggle_hw_renderer->isChecked());
ui->toggle_vsync_new->setEnabled(!Core::System::GetInstance().IsPoweredOn());
const bool not_running = !Core::System::GetInstance().IsPoweredOn();
const bool hw_renderer_enabled = ui->toggle_hw_renderer->isChecked();
ui->toggle_hw_renderer->setEnabled(not_running);
ui->hw_renderer_group->setEnabled(hw_renderer_enabled && not_running);
ui->toggle_vsync_new->setEnabled(not_running);
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());
connect(ui->graphics_api_combo, qOverload<int>(&QComboBox::currentIndexChanged), this,
&ConfigureGraphics::SetPhysicalDeviceComboVisibility);
connect(ui->toggle_hw_renderer, &QCheckBox::toggled, this, [this] {
auto checked = ui->toggle_hw_renderer->isChecked();
@ -31,7 +44,7 @@ ConfigureGraphics::ConfigureGraphics(QWidget* parent)
ui->toggle_hw_shader->isChecked());
connect(ui->toggle_hw_shader, &QCheckBox::toggled, this, [this] {
auto checked = ui->toggle_hw_shader->isChecked();
const bool checked = ui->toggle_hw_shader->isChecked();
ui->hw_shader_group->setEnabled(checked);
ui->toggle_disk_shader_cache->setEnabled(checked);
});
@ -69,6 +82,10 @@ void ConfigureGraphics::SetConfiguration() {
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);
ui->spirv_shader_gen->setChecked(Settings::values.spirv_shader_gen);
}
void ConfigureGraphics::ApplyConfiguration() {
@ -79,8 +96,32 @@ void ConfigureGraphics::ApplyConfiguration() {
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();
Settings::values.spirv_shader_gen = ui->spirv_shader_gen->isChecked();
}
void ConfigureGraphics::RetranslateUI() {
ui->retranslateUi(this);
}
void ConfigureGraphics::DiscoverPhysicalDevices() {
Vulkan::Instance instance{};
const auto physical_devices = instance.GetPhysicalDevices();
ui->physical_device_combo->clear();
for (const vk::PhysicalDevice& physical_device : physical_devices) {
const QString name = QString::fromLocal8Bit(physical_device.getProperties().deviceName);
ui->physical_device_combo->addItem(name);
}
}
void ConfigureGraphics::SetPhysicalDeviceComboVisibility(int index) {
const auto graphics_api = static_cast<Settings::GraphicsAPI>(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

@ -24,6 +24,11 @@ public:
void UpdateBackgroundColorButton(const QColor& color);
private:
void DiscoverPhysicalDevices();
void SetPhysicalDeviceComboVisibility(int index);
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>430</height>
<height>513</height>
</rect>
</property>
<property name="minimumSize">
@ -20,6 +20,66 @@
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="apiBox">
<property name="title">
<string>API Settings</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="graphics_api_label">
<property name="text">
<string>Graphics API</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="graphics_api_combo">
<item>
<property name="text">
<string>OpenGL</string>
</property>
</item>
<item>
<property name="text">
<string>OpenGLES</string>
</property>
</item>
<item>
<property name="text">
<string>Vulkan</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="physical_device_label">
<property name="text">
<string>Physical device</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="physical_device_combo"/>
</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>
<item>
<widget class="QGroupBox" name="rendererBox">
<property name="title">
@ -118,6 +178,16 @@
<string>Advanced</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QCheckBox" name="toggle_async_recording">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Offloads command buffer recording and fragment shader generation to a worker thread. Can improve performance especially on weaker systems. Disable if you notice better performance. If unsure leave it enabled,&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Async Command Recording</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="toggle_disk_shader_cache">
<property name="toolTip">

View File

@ -192,10 +192,10 @@ ConfigureInput::ConfigureInput(QWidget* parent)
if (!button_map[button_id])
continue;
button_map[button_id]->setContextMenuPolicy(Qt::CustomContextMenu);
connect(button_map[button_id], &QPushButton::clicked, [=]() {
connect(button_map[button_id], &QPushButton::clicked, [this, button_id]() {
HandleClick(
button_map[button_id],
[=](const Common::ParamPackage& 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()`
@ -204,16 +204,16 @@ ConfigureInput::ConfigureInput(QWidget* parent)
},
InputCommon::Polling::DeviceType::Button);
});
connect(button_map[button_id], &QPushButton::customContextMenuRequested,
[=](const QPoint& menu_location) {
connect(button_map[button_id], &QPushButton::customContextMenuRequested, this,
[this, button_id](const QPoint& menu_location) {
QMenu context_menu;
context_menu.addAction(tr("Clear"), [&] {
context_menu.addAction(tr("Clear"), this, [&] {
buttons_param[button_id].Clear();
button_map[button_id]->setText(tr("[not set]"));
ApplyConfiguration();
Settings::SaveProfile(ui->profile->currentIndex());
});
context_menu.addAction(tr("Restore Default"), [&] {
context_menu.addAction(tr("Restore Default"), this, [&] {
buttons_param[button_id] = Common::ParamPackage{
InputCommon::GenerateKeyboardParam(Config::default_buttons[button_id])};
button_map[button_id]->setText(ButtonToText(buttons_param[button_id]));
@ -230,27 +230,29 @@ ConfigureInput::ConfigureInput(QWidget* parent)
continue;
analog_map_buttons[analog_id][sub_button_id]->setContextMenuPolicy(
Qt::CustomContextMenu);
connect(analog_map_buttons[analog_id][sub_button_id], &QPushButton::clicked, [=]() {
HandleClick(
analog_map_buttons[analog_id][sub_button_id],
[=](const Common::ParamPackage& params) {
SetAnalogButton(params, analogs_param[analog_id],
analog_sub_buttons[sub_button_id]);
ApplyConfiguration();
Settings::SaveProfile(ui->profile->currentIndex());
},
InputCommon::Polling::DeviceType::Button);
});
connect(analog_map_buttons[analog_id][sub_button_id], &QPushButton::clicked, this,
[this, analog_id, sub_button_id]() {
HandleClick(
analog_map_buttons[analog_id][sub_button_id],
[this, analog_id, sub_button_id](const Common::ParamPackage& params) {
SetAnalogButton(params, analogs_param[analog_id],
analog_sub_buttons[sub_button_id]);
ApplyConfiguration();
Settings::SaveProfile(ui->profile->currentIndex());
},
InputCommon::Polling::DeviceType::Button);
});
connect(analog_map_buttons[analog_id][sub_button_id],
&QPushButton::customContextMenuRequested, [=](const QPoint& menu_location) {
&QPushButton::customContextMenuRequested, this,
[this, analog_id, sub_button_id](const QPoint& menu_location) {
QMenu context_menu;
context_menu.addAction(tr("Clear"), [&] {
context_menu.addAction(tr("Clear"), this, [&] {
analogs_param[analog_id].Erase(analog_sub_buttons[sub_button_id]);
analog_map_buttons[analog_id][sub_button_id]->setText(tr("[not set]"));
ApplyConfiguration();
Settings::SaveProfile(ui->profile->currentIndex());
});
context_menu.addAction(tr("Restore Default"), [&] {
context_menu.addAction(tr("Restore Default"), this, [&] {
Common::ParamPackage params{InputCommon::GenerateKeyboardParam(
Config::default_analogs[analog_id][sub_button_id])};
SetAnalogButton(params, analogs_param[analog_id],
@ -264,7 +266,7 @@ ConfigureInput::ConfigureInput(QWidget* parent)
menu_location));
});
}
connect(analog_map_stick[analog_id], &QPushButton::clicked, [=]() {
connect(analog_map_stick[analog_id], &QPushButton::clicked, this, [this, analog_id]() {
if (QMessageBox::information(
this, tr("Information"),
tr("After pressing OK, first move your joystick horizontally, "
@ -272,7 +274,7 @@ ConfigureInput::ConfigureInput(QWidget* parent)
QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok) {
HandleClick(
analog_map_stick[analog_id],
[=](const Common::ParamPackage& params) {
[this, analog_id](const Common::ParamPackage& params) {
analogs_param[analog_id] = params;
ApplyConfiguration();
Settings::SaveProfile(ui->profile->currentIndex());
@ -280,29 +282,31 @@ ConfigureInput::ConfigureInput(QWidget* parent)
InputCommon::Polling::DeviceType::Analog);
}
});
connect(analog_map_deadzone_and_modifier_slider[analog_id], &QSlider::valueChanged, [=] {
const int slider_value = analog_map_deadzone_and_modifier_slider[analog_id]->value();
const auto engine = analogs_param[analog_id].Get("engine", "");
if (engine == "sdl" || engine == "gcpad") {
analog_map_deadzone_and_modifier_slider_label[analog_id]->setText(
tr("Deadzone: %1%").arg(slider_value));
analogs_param[analog_id].Set("deadzone", slider_value / 100.0f);
} else {
analog_map_deadzone_and_modifier_slider_label[analog_id]->setText(
tr("Modifier Scale: %1%").arg(slider_value));
analogs_param[analog_id].Set("modifier_scale", slider_value / 100.0f);
}
ApplyConfiguration();
Settings::SaveProfile(ui->profile->currentIndex());
});
connect(analog_map_deadzone_and_modifier_slider[analog_id], &QSlider::valueChanged, this,
[this, analog_id] {
const int slider_value =
analog_map_deadzone_and_modifier_slider[analog_id]->value();
const auto engine = analogs_param[analog_id].Get("engine", "");
if (engine == "sdl" || engine == "gcpad") {
analog_map_deadzone_and_modifier_slider_label[analog_id]->setText(
tr("Deadzone: %1%").arg(slider_value));
analogs_param[analog_id].Set("deadzone", slider_value / 100.0f);
} else {
analog_map_deadzone_and_modifier_slider_label[analog_id]->setText(
tr("Modifier Scale: %1%").arg(slider_value));
analogs_param[analog_id].Set("modifier_scale", slider_value / 100.0f);
}
ApplyConfiguration();
Settings::SaveProfile(ui->profile->currentIndex());
});
}
// The Circle Mod button is common for both the sticks, so update the modifier settings
// for both the sticks.
connect(ui->buttonCircleMod, &QPushButton::clicked, [=]() {
connect(ui->buttonCircleMod, &QPushButton::clicked, this, [this]() {
HandleClick(
ui->buttonCircleMod,
[=](const Common::ParamPackage& params) {
[this](const Common::ParamPackage& params) {
for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs;
analog_id++) {
SetAnalogButton(params, analogs_param[analog_id], "modifier");
@ -312,10 +316,10 @@ ConfigureInput::ConfigureInput(QWidget* parent)
},
InputCommon::Polling::DeviceType::Button);
});
connect(ui->buttonCircleMod, &QPushButton::customContextMenuRequested,
connect(ui->buttonCircleMod, &QPushButton::customContextMenuRequested, this,
[&](const QPoint& menu_location) {
QMenu context_menu;
context_menu.addAction(tr("Clear"), [&] {
context_menu.addAction(tr("Clear"), this, [&] {
for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs;
analog_id++) {
analogs_param[analog_id].Erase("modifier");
@ -325,7 +329,7 @@ ConfigureInput::ConfigureInput(QWidget* parent)
Settings::SaveProfile(ui->profile->currentIndex());
});
context_menu.addAction(tr("Restore Default"), [&] {
context_menu.addAction(tr("Restore Default"), this, [&] {
for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs;
analog_id++) {
Common::ParamPackage params{InputCommon::GenerateKeyboardParam(
@ -341,7 +345,7 @@ ConfigureInput::ConfigureInput(QWidget* parent)
context_menu.exec(ui->buttonCircleMod->mapToGlobal(menu_location));
});
connect(ui->buttonMotionTouch, &QPushButton::clicked, [this] {
connect(ui->buttonMotionTouch, &QPushButton::clicked, this, [this] {
QDialog* motion_touch_dialog = new ConfigureMotionTouch(this);
return motion_touch_dialog->exec();
});
@ -356,18 +360,17 @@ ConfigureInput::ConfigureInput(QWidget* parent)
connect(ui->buttonDelete, &QPushButton::clicked, this, &ConfigureInput::DeleteProfile);
connect(ui->buttonRename, &QPushButton::clicked, this, &ConfigureInput::RenameProfile);
connect(ui->profile, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
[this](int i) {
ApplyConfiguration();
Settings::SaveProfile(Settings::values.current_input_profile_index);
Settings::LoadProfile(i);
LoadConfiguration();
});
connect(ui->profile, qOverload<int>(&QComboBox::currentIndexChanged), this, [this](int i) {
ApplyConfiguration();
Settings::SaveProfile(Settings::values.current_input_profile_index);
Settings::LoadProfile(i);
LoadConfiguration();
});
timeout_timer->setSingleShot(true);
connect(timeout_timer.get(), &QTimer::timeout, [this]() { SetPollingResult({}, true); });
connect(timeout_timer.get(), &QTimer::timeout, this, [this]() { SetPollingResult({}, true); });
connect(poll_timer.get(), &QTimer::timeout, [this]() {
connect(poll_timer.get(), &QTimer::timeout, this, [this]() {
Common::ParamPackage params;
for (auto& poller : device_pollers) {
params = poller->GetNextInput();
@ -554,7 +557,7 @@ void ConfigureInput::AutoMap() {
QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Cancel) {
return;
}
input_setter = [=](const Common::ParamPackage& params) {
input_setter = [this](const Common::ParamPackage& params) {
MapFromButton(params);
ApplyConfiguration();
Settings::SaveProfile(ui->profile->currentIndex());

View File

@ -46,6 +46,9 @@ CalibrationConfigurationDialog::CalibrationConfigurationDialog(QWidget* parent,
case CalibrationConfigurationJob::Status::Completed:
text = tr("Configuration completed!");
break;
default:
LOG_ERROR(Frontend, "Unknown calibration status {}", status);
break;
}
QMetaObject::invokeMethod(this, "UpdateLabelText", Q_ARG(QString, text));
if (status == CalibrationConfigurationJob::Status::Completed) {
@ -99,9 +102,9 @@ ConfigureMotionTouch::ConfigureMotionTouch(QWidget* parent)
"style=\"text-decoration: underline; color:#039be5;\">Learn More</span></a>"));
timeout_timer->setSingleShot(true);
connect(timeout_timer.get(), &QTimer::timeout, [this]() { SetPollingResult({}, true); });
connect(timeout_timer.get(), &QTimer::timeout, this, [this]() { SetPollingResult({}, true); });
connect(poll_timer.get(), &QTimer::timeout, [this]() {
connect(poll_timer.get(), &QTimer::timeout, this, [this]() {
Common::ParamPackage params;
for (auto& poller : device_pollers) {
params = poller->GetNextInput();
@ -202,7 +205,7 @@ void ConfigureMotionTouch::ConnectEvents() {
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, [=]() {
connect(ui->motion_controller_button, &QPushButton::clicked, this, [this]() {
if (QMessageBox::information(this, tr("Information"),
tr("After pressing OK, press a button on the controller whose "
"motion you want to track."),
@ -210,7 +213,7 @@ void ConfigureMotionTouch::ConnectEvents() {
ui->motion_controller_button->setText(tr("[press button]"));
ui->motion_controller_button->setFocus();
input_setter = [=](const Common::ParamPackage& params) {
input_setter = [this](const Common::ParamPackage& params) {
guid = params.Get("guid", "0");
port = params.Get("port", 0);
};

View File

@ -508,7 +508,7 @@ void TouchScreenPreview::mouseMoveEvent(QMouseEvent* event) {
}
const auto pos = MapToDeviceCoords(event->x(), event->y());
if (pos) {
coord_label->setText(QStringLiteral("X: %1, Y: %2").arg(pos->x()).arg(pos->y()));
coord_label->setText(QStringLiteral("X: %1, Y: %2").arg(pos->x(), pos->y()));
} else {
coord_label->clear();
}
@ -568,7 +568,7 @@ bool TouchScreenPreview::eventFilter(QObject* obj, QEvent* event) {
emit DotMoved(drag_state.dot->property(PropId).toInt(), *device_coord);
if (coord_label) {
coord_label->setText(
QStringLiteral("X: %1, Y: %2").arg(device_coord->x()).arg(device_coord->y()));
QStringLiteral("X: %1, Y: %2").arg(device_coord->x(), device_coord->y()));
}
}
return true;

View File

@ -9,7 +9,6 @@
#include <QVBoxLayout>
#include "citra_qt/debugger/graphics/graphics_breakpoints.h"
#include "citra_qt/debugger/graphics/graphics_breakpoints_p.h"
#include "common/assert.h"
BreakPointModel::BreakPointModel(std::shared_ptr<Pica::DebugContext> debug_context, QObject* parent)
: QAbstractListModel(parent), context_weak(debug_context),
@ -60,12 +59,15 @@ QVariant BreakPointModel::data(const QModelIndex& index, int role) const {
}
Qt::ItemFlags BreakPointModel::flags(const QModelIndex& index) const {
if (!index.isValid())
return 0;
if (!index.isValid()) {
return {};
}
Qt::ItemFlags flags = Qt::ItemIsEnabled;
if (index.column() == 0)
if (index.column() == 0) {
flags |= Qt::ItemIsUserCheckable;
}
return flags;
}

View File

@ -14,7 +14,6 @@
#include <QTreeView>
#include <QVBoxLayout>
#include "citra_qt/debugger/graphics/graphics_cmdlists.h"
#include "citra_qt/util/spinbox.h"
#include "citra_qt/util/util.h"
#include "common/vector_math.h"
#include "core/core.h"
@ -130,7 +129,7 @@ void GPUCommandListWidget::OnCommandDoubleClicked(const QModelIndex& index) {
COMMAND_IN_RANGE(command_id, texturing.texture1) ||
COMMAND_IN_RANGE(command_id, texturing.texture2)) {
unsigned texture_index;
[[maybe_unused]] u32 texture_index;
if (COMMAND_IN_RANGE(command_id, texturing.texture0)) {
texture_index = 0;
} else if (COMMAND_IN_RANGE(command_id, texturing.texture1)) {

View File

@ -16,7 +16,6 @@
#include "citra_qt/util/spinbox.h"
#include "common/color.h"
#include "core/core.h"
#include "core/hw/gpu.h"
#include "core/memory.h"
#include "video_core/pica_state.h"
#include "video_core/regs_framebuffer.h"
@ -34,12 +33,15 @@ void SurfacePicture::mousePressEvent(QMouseEvent* event) {
if (!(event->buttons() & Qt::LeftButton))
return;
if (pixmap() == nullptr)
const QPixmap pixmap = this->pixmap(Qt::ReturnByValue);
if (pixmap.isNull()) {
return;
}
if (surface_widget)
surface_widget->Pick(event->x() * pixmap()->width() / width(),
event->y() * pixmap()->height() / height());
if (surface_widget) {
surface_widget->Pick(event->x() * pixmap.width() / width(),
event->y() * pixmap.height() / height());
}
}
void SurfacePicture::mouseMoveEvent(QMouseEvent* event) {
@ -314,57 +316,46 @@ void GraphicsSurfaceWidget::Pick(int x, int y) {
case Format::RGBA8: {
auto value = Color::DecodeRGBA8(pixel) / 255.0f;
return QStringLiteral("Red: %1, Green: %2, Blue: %3, Alpha: %4")
.arg(QString::number(value.r(), 'f', 2))
.arg(QString::number(value.g(), 'f', 2))
.arg(QString::number(value.b(), 'f', 2))
.arg(QString::number(value.a(), 'f', 2));
.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 = Color::DecodeRGB8(pixel) / 255.0f;
return QStringLiteral("Red: %1, Green: %2, Blue: %3")
.arg(QString::number(value.r(), 'f', 2))
.arg(QString::number(value.g(), 'f', 2))
.arg(QString::number(value.b(), 'f', 2));
.arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2),
QString::number(value.b(), 'f', 2));
}
case Format::RGB5A1: {
auto value = Color::DecodeRGB5A1(pixel) / 255.0f;
return QStringLiteral("Red: %1, Green: %2, Blue: %3, Alpha: %4")
.arg(QString::number(value.r(), 'f', 2))
.arg(QString::number(value.g(), 'f', 2))
.arg(QString::number(value.b(), 'f', 2))
.arg(QString::number(value.a(), 'f', 2));
.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 = Color::DecodeRGB565(pixel) / 255.0f;
return QStringLiteral("Red: %1, Green: %2, Blue: %3")
.arg(QString::number(value.r(), 'f', 2))
.arg(QString::number(value.g(), 'f', 2))
.arg(QString::number(value.b(), 'f', 2));
.arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2),
QString::number(value.b(), 'f', 2));
}
case Format::RGBA4: {
auto value = Color::DecodeRGBA4(pixel) / 255.0f;
return QStringLiteral("Red: %1, Green: %2, Blue: %3, Alpha: %4")
.arg(QString::number(value.r(), 'f', 2))
.arg(QString::number(value.g(), 'f', 2))
.arg(QString::number(value.b(), 'f', 2))
.arg(QString::number(value.a(), 'f', 2));
.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::IA8:
return QStringLiteral("Index: %1, Alpha: %2").arg(pixel[0]).arg(pixel[1]);
return QStringLiteral("Index: %1, Alpha: %2").arg(pixel[0], pixel[1]);
case Format::RG8: {
auto value = Color::DecodeRG8(pixel) / 255.0f;
return QStringLiteral("Red: %1, Green: %2")
.arg(QString::number(value.r(), 'f', 2))
.arg(QString::number(value.g(), 'f', 2));
.arg(QString::number(value.r(), 'f', 2), QString::number(value.g(), 'f', 2));
}
case Format::I8:
return QStringLiteral("Index: %1").arg(*pixel);
case Format::A8:
return QStringLiteral("Alpha: %1").arg(QString::number(*pixel / 255.0f, 'f', 2));
case Format::IA4:
return QStringLiteral("Index: %1, Alpha: %2")
.arg(*pixel & 0xF)
.arg((*pixel & 0xF0) >> 4);
return QStringLiteral("Index: %1, Alpha: %2").arg(*pixel & 0xF, (*pixel & 0xF0) >> 4);
case Format::I4: {
u8 i = (*pixel >> ((offset % 2) ? 4 : 0)) & 0xF;
return QStringLiteral("Index: %1").arg(i);
@ -390,8 +381,7 @@ void GraphicsSurfaceWidget::Pick(int x, int y) {
case Format::X24S8: {
auto values = Color::DecodeD24S8(pixel);
return QStringLiteral("Depth: %1, Stencil: %2")
.arg(QString::number(values[0] / (float)0xFFFFFF, 'f', 4))
.arg(values[1]);
.arg(QString::number(values[0] / (float)0xFFFFFF, 'f', 4), values[1]);
}
case Format::Unknown:
return QStringLiteral("Unknown format");
@ -401,8 +391,8 @@ void GraphicsSurfaceWidget::Pick(int x, int y) {
};
QString nibbles;
for (unsigned i = 0; i < nibbles_per_pixel; i++) {
unsigned nibble_index = i;
for (u32 i = 0; i < nibbles_per_pixel; i++) {
u32 nibble_index = i;
if (nibble_mode) {
nibble_index += (offset % 2) ? 0 : 1;
}
@ -412,7 +402,7 @@ void GraphicsSurfaceWidget::Pick(int x, int y) {
}
surface_info_label->setText(
QStringLiteral("Raw: 0x%3\n(%4)").arg(nibbles).arg(GetText(surface_format, pixel)));
QStringLiteral("Raw: 0x%3\n(%4)").arg(nibbles, GetText(surface_format, pixel)));
surface_info_label->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
}
@ -676,8 +666,8 @@ void GraphicsSurfaceWidget::SaveSurface() {
}
if (selected_filter == png_filter) {
const QPixmap* const pixmap = surface_picture_label->pixmap();
ASSERT_MSG(pixmap != nullptr, "No pixmap set");
const QPixmap pixmap = surface_picture_label->pixmap(Qt::ReturnByValue);
ASSERT_MSG(!pixmap.isNull(), "No pixmap set");
QFile file{filename};
if (!file.open(QIODevice::WriteOnly)) {
@ -685,7 +675,7 @@ void GraphicsSurfaceWidget::SaveSurface() {
return;
}
if (!pixmap->save(&file, "PNG")) {
if (!pixmap.save(&file, "PNG")) {
QMessageBox::warning(this, tr("Error"),
tr("Failed to save surface data to file '%1'").arg(filename));
}

View File

@ -111,13 +111,13 @@ QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) con
}
};
const Instruction instr = par->info.code[index.row()];
const Instruction& instr = par->info.code[index.row()];
const OpCode opcode = instr.opcode;
const OpCode::Info opcode_info = opcode.GetInfo();
const u32 operand_desc_id = opcode_info.type == OpCode::Type::MultiplyAdd
? instr.mad.operand_desc_id.Value()
: instr.common.operand_desc_id.Value();
const SwizzlePattern swizzle = par->info.swizzle_info[operand_desc_id].pattern;
const SwizzlePattern& swizzle = par->info.swizzle_info[operand_desc_id].pattern;
// longest known instruction name: "setemit "
int kOpcodeColumnWidth = 8;
@ -407,8 +407,8 @@ GraphicsVertexShaderWidget::GraphicsVertexShaderWidget(
static_cast<void (QSignalMapper::*)()>(&QSignalMapper::map));
input_data_mapper->setMapping(input_data[i], i);
}
connect(input_data_mapper, static_cast<void (QSignalMapper::*)(int)>(&QSignalMapper::mapped),
this, &GraphicsVertexShaderWidget::OnInputAttributeChanged);
connect(input_data_mapper, &QSignalMapper::mappedInt, this,
&GraphicsVertexShaderWidget::OnInputAttributeChanged);
auto main_widget = new QWidget;
auto main_layout = new QVBoxLayout;
@ -514,8 +514,10 @@ void GraphicsVertexShaderWidget::Reload(bool replace_vertex_data, void* vertex_d
info.code.push_back({instr});
int num_attributes = shader_config.max_input_attribute_index + 1;
for (auto pattern : shader_setup.swizzle_data)
info.swizzle_info.push_back({pattern});
for (auto pattern : shader_setup.swizzle_data) {
const nihstro::SwizzleInfo swizzle_info = {.pattern = nihstro::SwizzlePattern{pattern}};
info.swizzle_info.push_back(swizzle_info);
}
u32 entry_point = Pica::g_state.regs.vs.main_offset;
info.labels.insert({entry_point, "main"});

View File

@ -57,6 +57,7 @@ QString IPCRecorderWidget::GetStatusStr(const IPCDebugger::RequestRecord& record
return tr("HLE Unimplemented");
default:
UNREACHABLE();
return QLatin1String{};
}
}

View File

@ -160,7 +160,8 @@ void MicroProfileWidget::mouseReleaseEvent(QMouseEvent* event) {
}
void MicroProfileWidget::wheelEvent(QWheelEvent* event) {
MicroProfileMousePosition(event->x() / x_scale, event->y() / y_scale, event->delta() / 120);
MicroProfileMousePosition(event->position().x() / x_scale, event->position().y() / y_scale,
event->angleDelta().y() / 120);
event->accept();
}

View File

@ -114,7 +114,7 @@ void OptionSetDialog::InitializeUI(const std::string& initial_value) {
ui->formatLabel->text().append(QStringLiteral("\n"));
}
ui->formatLabel->setText(
ui->formatLabel->text().append(tr("Range: %1 - %2").arg(option.min).arg(option.max)));
ui->formatLabel->text().append(tr("Range: %1 - %2").arg(option.min, option.max)));
}
// Decide and initialize layout

View File

@ -3,6 +3,7 @@
// Refer to the license.txt file included.
#include <QApplication>
#include <QDir>
#include <QFileInfo>
#include <QFileSystemWatcher>
#include <QHBoxLayout>
@ -31,6 +32,8 @@
#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)
: QObject(parent), gamelist{gamelist} {}
@ -169,8 +172,7 @@ GameListSearchField::GameListSearchField(GameList* parent) : QWidget{parent} {
* @return true if the haystack contains all words of userinput
*/
static bool ContainsAllWords(const QString& haystack, const QString& userinput) {
const QStringList userinput_split =
userinput.split(QLatin1Char{' '}, QString::SplitBehavior::SkipEmptyParts);
const QStringList userinput_split = userinput.split(QLatin1Char{' '}, Qt::SkipEmptyParts);
return std::all_of(userinput_split.begin(), userinput_split.end(),
[&haystack](const QString& s) { return haystack.contains(s); });
@ -463,6 +465,7 @@ void GameList::PopupContextMenu(const QPoint& menu_location) {
default:
break;
}
context_menu.exec(tree_view->viewport()->mapToGlobal(menu_location));
}
@ -476,19 +479,27 @@ 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"));
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"));
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;
std::string sdmc_dir = FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir);
open_save_location->setVisible(
open_save_location->setEnabled(
is_application && FileUtil::Exists(FileSys::ArchiveSource_SDSaveData::GetSaveDataPathFor(
sdmc_dir, program_id)));
if (extdata_id) {
open_extdata_location->setVisible(
open_extdata_location->setEnabled(
is_application &&
FileUtil::Exists(FileSys::GetExtDataPathFromId(sdmc_dir, extdata_id)));
} else {
@ -496,9 +507,9 @@ void GameList::AddGamePopup(QMenu& context_menu, const QString& path, u64 progra
}
auto media_type = Service::AM::GetTitleMediaType(program_id);
open_application_location->setVisible(path.toStdString() ==
open_application_location->setEnabled(path.toStdString() ==
Service::AM::GetTitleContentPath(media_type, program_id));
open_update_location->setVisible(
open_update_location->setEnabled(
is_application && FileUtil::Exists(Service::AM::GetTitlePath(Service::FS::MediaType::SDMC,
program_id + 0xe00000000) +
"content/"));
@ -511,44 +522,71 @@ void GameList::AddGamePopup(QMenu& context_menu, const QString& path, u64 progra
navigate_to_gamedb_entry->setVisible(it != compatibility_list.end());
connect(open_save_location, &QAction::triggered, [this, program_id] {
connect(open_save_location, &QAction::triggered, this, [this, program_id] {
emit OpenFolderRequested(program_id, GameListOpenTarget::SAVE_DATA);
});
connect(open_extdata_location, &QAction::triggered, [this, extdata_id] {
connect(open_extdata_location, &QAction::triggered, this, [this, extdata_id] {
emit OpenFolderRequested(extdata_id, GameListOpenTarget::EXT_DATA);
});
connect(open_application_location, &QAction::triggered, [this, program_id] {
connect(open_application_location, &QAction::triggered, this, [this, program_id] {
emit OpenFolderRequested(program_id, GameListOpenTarget::APPLICATION);
});
connect(open_update_location, &QAction::triggered, [this, program_id] {
connect(open_update_location, &QAction::triggered, this, [this, program_id] {
emit OpenFolderRequested(program_id, GameListOpenTarget::UPDATE_DATA);
});
connect(open_texture_dump_location, &QAction::triggered, [this, program_id] {
connect(open_texture_dump_location, &QAction::triggered, this, [this, program_id] {
if (FileUtil::CreateFullPath(fmt::format("{}textures/{:016X}/",
FileUtil::GetUserPath(FileUtil::UserPath::DumpDir),
program_id))) {
emit OpenFolderRequested(program_id, GameListOpenTarget::TEXTURE_DUMP);
}
});
connect(open_texture_load_location, &QAction::triggered, [this, program_id] {
connect(open_texture_load_location, &QAction::triggered, this, [this, program_id] {
if (FileUtil::CreateFullPath(fmt::format("{}textures/{:016X}/",
FileUtil::GetUserPath(FileUtil::UserPath::LoadDir),
program_id))) {
emit OpenFolderRequested(program_id, GameListOpenTarget::TEXTURE_LOAD);
}
});
connect(open_mods_location, &QAction::triggered, [this, program_id] {
connect(open_texture_load_location, &QAction::triggered, this, [this, program_id] {
if (FileUtil::CreateFullPath(fmt::format("{}textures/{:016X}/",
FileUtil::GetUserPath(FileUtil::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),
program_id))) {
emit OpenFolderRequested(program_id, GameListOpenTarget::MODS);
}
});
connect(dump_romfs, &QAction::triggered,
connect(dump_romfs, &QAction::triggered, this,
[this, path, program_id] { emit DumpRomFSRequested(path, program_id); });
connect(navigate_to_gamedb_entry, &QAction::triggered, [this, program_id]() {
connect(navigate_to_gamedb_entry, &QAction::triggered, this, [this, program_id]() {
emit NavigateToGamedbEntryRequested(program_id, compatibility_list);
});
connect(open_shader_cache_location, &QAction::triggered, this, [this, program_id] {
if (FileUtil::CreateFullPath(FileUtil::GetUserPath(FileUtil::UserPath::ShaderDir))) {
emit OpenFolderRequested(program_id, GameListOpenTarget::SHADER_CACHE);
}
});
connect(delete_opengl_disk_shader_cache, &QAction::triggered, this, [program_id] {
const std::string_view cache_type =
Settings::values.separable_shader ? "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)};
file.remove();
});
connect(delete_vulkan_disk_shader_cache, &QAction::triggered, this, [] {
const std::string path =
fmt::format("{}vulkan", FileUtil::GetUserPath(FileUtil::UserPath::ShaderDir));
QDir dir{QString::fromStdString(path)};
dir.removeRecursively();
});
};
void GameList::AddCustomDirPopup(QMenu& context_menu, QModelIndex selected) {
@ -561,11 +599,11 @@ void GameList::AddCustomDirPopup(QMenu& context_menu, QModelIndex selected) {
deep_scan->setCheckable(true);
deep_scan->setChecked(game_dir.deep_scan);
connect(deep_scan, &QAction::triggered, [this, &game_dir] {
connect(deep_scan, &QAction::triggered, this, [this, &game_dir] {
game_dir.deep_scan = !game_dir.deep_scan;
PopulateAsync(UISettings::values.game_dirs);
});
connect(delete_dir, &QAction::triggered, [this, &game_dir, selected] {
connect(delete_dir, &QAction::triggered, this, [this, &game_dir, selected] {
UISettings::values.game_dirs.removeOne(game_dir);
item_model->invisibleRootItem()->removeRow(selected.row());
});
@ -583,7 +621,7 @@ void GameList::AddPermDirPopup(QMenu& context_menu, QModelIndex selected) {
move_up->setEnabled(row > 0);
move_down->setEnabled(row < item_model->rowCount() - 2);
connect(move_up, &QAction::triggered, [this, selected, row, game_dir_index] {
connect(move_up, &QAction::triggered, this, [this, selected, row, game_dir_index] {
const int other_index = selected.sibling(row - 1, 0).data(GameListDir::GameDirRole).toInt();
// swap the items in the settings
std::swap(UISettings::values.game_dirs[game_dir_index],
@ -598,7 +636,7 @@ void GameList::AddPermDirPopup(QMenu& context_menu, QModelIndex selected) {
tree_view->setExpanded(selected, UISettings::values.game_dirs[game_dir_index].expanded);
});
connect(move_down, &QAction::triggered, [this, selected, row, game_dir_index] {
connect(move_down, &QAction::triggered, this, [this, selected, row, game_dir_index] {
const int other_index = selected.sibling(row + 1, 0).data(GameListDir::GameDirRole).toInt();
// swap the items in the settings
std::swap(UISettings::values.game_dirs[game_dir_index],
@ -613,7 +651,7 @@ void GameList::AddPermDirPopup(QMenu& context_menu, QModelIndex selected) {
tree_view->setExpanded(selected, UISettings::values.game_dirs[game_dir_index].expanded);
});
connect(open_directory_location, &QAction::triggered, [this, game_dir_index] {
connect(open_directory_location, &QAction::triggered, this, [this, game_dir_index] {
emit OpenDirectory(UISettings::values.game_dirs[game_dir_index].path);
});
}
@ -640,7 +678,7 @@ void GameList::LoadCompatibilityList() {
const QJsonDocument json = QJsonDocument::fromJson(content);
const QJsonArray arr = json.array();
for (const QJsonValue value : arr) {
for (const QJsonValue& value : arr) {
const QJsonObject game = value.toObject();
const QString compatibility_key = QStringLiteral("compatibility");
@ -652,7 +690,7 @@ void GameList::LoadCompatibilityList() {
const QString directory = game[QStringLiteral("directory")].toString();
const QJsonArray ids = game[QStringLiteral("releases")].toArray();
for (const QJsonValue id_ref : ids) {
for (const QJsonValue& id_ref : ids) {
const QJsonObject id_object = id_ref.toObject();
const QString id = id_object[QStringLiteral("id")].toString();

View File

@ -37,6 +37,7 @@ enum class GameListOpenTarget {
TEXTURE_DUMP = 4,
TEXTURE_LOAD = 5,
MODS = 6,
SHADER_CACHE = 7
};
class GameList : public QWidget {

View File

@ -11,18 +11,11 @@
#include <QFutureWatcher>
#include <QLabel>
#include <QMessageBox>
#include <QOpenGLFunctions_4_3_Core>
#include <QSysInfo>
#include <QtConcurrent/QtConcurrentRun>
#include <QtGui>
#include <QtWidgets>
#include <fmt/format.h>
#ifdef __APPLE__
#include <unistd.h> // for chdir
#endif
#ifdef _WIN32
#include <windows.h>
#endif
#include "citra_qt/aboutdialog.h"
#include "citra_qt/applets/mii_selector.h"
#include "citra_qt/applets/swkbd.h"
@ -62,12 +55,11 @@
#include "common/detached_tasks.h"
#include "common/file_util.h"
#include "common/logging/backend.h"
#include "common/logging/filter.h"
#include "common/logging/log.h"
#include "common/logging/text_formatter.h"
#include "common/microprofile.h"
#include "common/scm_rev.h"
#include "common/scope_exit.h"
#include "common/string_util.h"
#ifdef ARCHITECTURE_x86_64
#include "common/x64/cpu_detect.h"
#endif
@ -76,20 +68,23 @@
#include "core/file_sys/archive_extsavedata.h"
#include "core/file_sys/archive_source_sd_savedata.h"
#include "core/frontend/applets/default_applets.h"
#include "core/frontend/scope_acquire_context.h"
#include "core/gdbstub/gdbstub.h"
#include "core/hle/service/fs/archive.h"
#include "core/hle/service/nfc/nfc.h"
#include "core/loader/loader.h"
#include "core/movie.h"
#include "core/savestate.h"
#include "core/settings.h"
#include "game_list_p.h"
#include "network/network_settings.h"
#include "ui_main.h"
#include "video_core/renderer_base.h"
#include "video_core/video_core.h"
#ifdef __APPLE__
#include <unistd.h> // for chdir
#endif
#ifdef _WIN32
#include <windows.h>
#endif
#ifdef USE_DISCORD_PRESENCE
#include "citra_qt/discord_impl.h"
#endif
@ -152,8 +147,8 @@ static void InitializeLogging() {
}
GMainWindow::GMainWindow()
: config(std::make_unique<Config>()), emu_thread(nullptr),
ui(std::make_unique<Ui::MainWindow>()) {
: ui{std::make_unique<Ui::MainWindow>()}, config{std::make_unique<Config>()}, emu_thread{
nullptr} {
InitializeLogging();
Debugger::ToggleConsole();
Settings::LogSettings();
@ -263,7 +258,7 @@ void GMainWindow::InitializeWidgets() {
loading_screen = new LoadingScreen(this);
loading_screen->hide();
ui->horizontalLayout->addWidget(loading_screen);
connect(loading_screen, &LoadingScreen::Hidden, [&] {
connect(loading_screen, &LoadingScreen::Hidden, this, [&] {
loading_screen->Clear();
if (emulation_running) {
render_window->show();
@ -282,7 +277,6 @@ void GMainWindow::InitializeWidgets() {
// Create status bar
message_label = new QLabel();
// Configured separately for left alignment
message_label->setVisible(false);
message_label->setFrameStyle(QFrame::NoFrame);
message_label->setContentsMargins(4, 0, 4, 0);
message_label->setAlignment(Qt::AlignLeft);
@ -307,10 +301,28 @@ void GMainWindow::InitializeWidgets() {
label->setVisible(false);
label->setFrameStyle(QFrame::NoFrame);
label->setContentsMargins(4, 0, 4, 0);
statusBar()->addPermanentWidget(label, 0);
statusBar()->addPermanentWidget(label);
}
statusBar()->addPermanentWidget(multiplayer_state->GetStatusText(), 0);
statusBar()->addPermanentWidget(multiplayer_state->GetStatusIcon(), 0);
// Setup Graphics API button
graphics_api_button = new QPushButton();
graphics_api_button->setObjectName(QStringLiteral("GraphicsAPIStatusBarButton"));
graphics_api_button->setFocusPolicy(Qt::NoFocus);
UpdateAPIIndicator(false);
connect(graphics_api_button, &QPushButton::clicked, this, [this] {
if (emulation_running) {
return;
}
UpdateAPIIndicator(true);
});
statusBar()->insertPermanentWidget(0, graphics_api_button);
statusBar()->addPermanentWidget(multiplayer_state->GetStatusText());
statusBar()->addPermanentWidget(multiplayer_state->GetStatusIcon());
statusBar()->setVisible(true);
// Removes an ugly inner border from the status bar widgets under Linux
@ -432,13 +444,13 @@ void GMainWindow::InitializeSaveStateMenuActions() {
ui->menu_Save_State->addAction(actions_save_state[i]);
}
connect(ui->action_Load_from_Newest_Slot, &QAction::triggered, [this] {
connect(ui->action_Load_from_Newest_Slot, &QAction::triggered, this, [this] {
UpdateSaveStates();
if (newest_slot != 0) {
actions_load_state[newest_slot - 1]->trigger();
}
});
connect(ui->action_Save_to_Oldest_Slot, &QAction::triggered, [this] {
connect(ui->action_Save_to_Oldest_Slot, &QAction::triggered, this, [this] {
UpdateSaveStates();
actions_save_state[oldest_slot - 1]->trigger();
});
@ -674,7 +686,7 @@ void GMainWindow::ConnectWidgetEvents() {
connect(game_list_placeholder, &GameListPlaceholder::AddDirectory, this,
&GMainWindow::OnGameListAddDirectory);
connect(game_list, &GameList::ShowList, this, &GMainWindow::OnGameListShowList);
connect(game_list, &GameList::PopulatingCompleted,
connect(game_list, &GameList::PopulatingCompleted, this,
[this] { multiplayer_state->UpdateGameList(game_list->GetModel()); });
connect(this, &GMainWindow::EmulationStarting, render_window,
@ -765,7 +777,7 @@ void GMainWindow::ConnectMenuEvents() {
connect(ui->action_Close_Movie, &QAction::triggered, this, &GMainWindow::OnCloseMovie);
connect(ui->action_Save_Movie, &QAction::triggered, this, &GMainWindow::OnSaveMovie);
connect(ui->action_Movie_Read_Only_Mode, &QAction::toggled, this,
[this](bool checked) { Core::Movie::GetInstance().SetReadOnly(checked); });
[](bool checked) { Core::Movie::GetInstance().SetReadOnly(checked); });
connect(ui->action_Enable_Frame_Advancing, &QAction::triggered, this, [this] {
if (emulation_running) {
Core::System::GetInstance().frame_limiter.SetFrameAdvancing(
@ -914,20 +926,10 @@ bool GMainWindow::LoadROM(const QString& filename) {
render_window->InitRenderTarget();
Frontend::ScopeAcquireContext scope(*render_window);
const auto scope = render_window->Acquire();
const QString below_gl43_title = tr("OpenGL 4.3 Unsupported");
const QString below_gl43_message = tr("Your GPU may not support OpenGL 4.3, or you do not "
"have the latest graphics driver.");
if (!QOpenGLContext::globalShareContext()->versionFunctions<QOpenGLFunctions_4_3_Core>()) {
QMessageBox::critical(this, below_gl43_title, below_gl43_message);
return false;
}
Core::System& system{Core::System::GetInstance()};
const Core::System::ResultStatus result{system.Load(*render_window, filename.toStdString())};
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) {
@ -976,7 +978,7 @@ bool GMainWindow::LoadROM(const QString& filename) {
case Core::System::ResultStatus::ErrorVideoCore:
QMessageBox::critical(
this, tr("Video Core Error"),
tr("An error has occurred. Please <a "
tr("An error has occurred during intialization of the video backend. Please <a "
"href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>see "
"the "
"log</a> for more details. "
@ -991,10 +993,6 @@ bool GMainWindow::LoadROM(const QString& filename) {
"proper drivers for your graphics card from the manufacturer's website."));
break;
case Core::System::ResultStatus::ErrorVideoCore_ErrorBelowGL43:
QMessageBox::critical(this, below_gl43_title, below_gl43_message);
break;
default:
QMessageBox::critical(
this, tr("Error while loading ROM!"),
@ -1206,7 +1204,6 @@ void GMainWindow::ShutdownGame() {
// Disable status bar updates
status_bar_update_timer.stop();
message_label->setVisible(false);
message_label_used_for_movie = false;
emu_speed_label->setVisible(false);
game_fps_label->setVisible(false);
@ -1343,26 +1340,35 @@ void GMainWindow::OnGameListOpenFolder(u64 data_id, GameListOpenTarget target) {
path = Service::AM::GetTitlePath(media_type, data_id) + "content/";
break;
}
case GameListOpenTarget::UPDATE_DATA:
case GameListOpenTarget::UPDATE_DATA: {
open_target = "Update Data";
path = Service::AM::GetTitlePath(Service::FS::MediaType::SDMC, data_id + 0xe00000000) +
"content/";
break;
case GameListOpenTarget::TEXTURE_DUMP:
}
case GameListOpenTarget::TEXTURE_DUMP: {
open_target = "Dumped Textures";
path = fmt::format("{}textures/{:016X}/",
FileUtil::GetUserPath(FileUtil::UserPath::DumpDir), data_id);
break;
case GameListOpenTarget::TEXTURE_LOAD:
}
case GameListOpenTarget::TEXTURE_LOAD: {
open_target = "Custom Textures";
path = fmt::format("{}textures/{:016X}/",
FileUtil::GetUserPath(FileUtil::UserPath::LoadDir), data_id);
break;
case GameListOpenTarget::MODS:
}
case GameListOpenTarget::MODS: {
open_target = "Mods";
path = fmt::format("{}mods/{:016X}/", FileUtil::GetUserPath(FileUtil::UserPath::LoadDir),
data_id);
break;
}
case GameListOpenTarget::SHADER_CACHE: {
open_target = "Shader Cache";
path = FileUtil::GetUserPath(FileUtil::UserPath::ShaderDir);
break;
}
default:
LOG_ERROR(Frontend, "Unexpected target {}", static_cast<int>(target));
return;
@ -1410,7 +1416,7 @@ void GMainWindow::OnGameListDumpRomFS(QString game_path, u64 program_id) {
program_id | 0x0004000e00000000);
using FutureWatcher = QFutureWatcher<std::pair<Loader::ResultStatus, Loader::ResultStatus>>;
auto* future_watcher = new FutureWatcher(this);
connect(future_watcher, &FutureWatcher::finished,
connect(future_watcher, &FutureWatcher::finished, this,
[this, dialog, base_path, update_path, future_watcher] {
dialog->hide();
const auto& [base, update] = future_watcher->result();
@ -1512,7 +1518,7 @@ void GMainWindow::InstallCIA(QStringList filepaths) {
const auto cia_progress = [&](std::size_t written, std::size_t total) {
emit UpdateProgress(written, total);
};
for (const auto current_path : filepaths) {
for (const auto& current_path : filepaths) {
status = Service::AM::InstallCIA(current_path.toStdString(), cia_progress);
emit CIAInstallReport(status, current_path);
}
@ -1550,6 +1556,10 @@ void GMainWindow::OnCIAInstallReport(Service::AM::InstallStatus status, QString
"before being used with Citra. A real 3DS is required.")
.arg(filename));
break;
case Service::AM::InstallStatus::ErrorFileNotFound:
QMessageBox::critical(this, tr("Unable to find File"),
tr("Could not find %1").arg(filename));
break;
}
}
@ -1727,6 +1737,8 @@ void GMainWindow::ToggleScreenLayout() {
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;
@ -1796,6 +1808,7 @@ void GMainWindow::OnConfigure() {
} else {
setMouseTracking(false);
}
UpdateAPIIndicator(false);
} else {
Settings::values.input_profiles = old_input_profiles;
Settings::values.touch_from_button_maps = old_touch_from_button_maps;
@ -1973,7 +1986,7 @@ void GMainWindow::OnCaptureScreenshot() {
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).arg(timestamp));
path.append(QStringLiteral("/%1_%2.png").arg(filename, timestamp));
render_window->CaptureScreenshot(UISettings::values.screenshot_resolution_factor, path);
OnStartGame();
}
@ -2048,7 +2061,7 @@ void GMainWindow::UpdateStatusBar() {
message_label_used_for_movie = true;
ui->action_Save_Movie->setEnabled(true);
} else if (play_mode == Core::Movie::PlayMode::Playing) {
message_label->setText(tr("Playing %1 / %2").arg(current).arg(total));
message_label->setText(tr("Playing %1 / %2").arg(current, total));
message_label->setVisible(true);
message_label_used_for_movie = true;
ui->action_Save_Movie->setEnabled(false);
@ -2107,6 +2120,26 @@ void GMainWindow::ShowMouseCursor() {
}
}
void GMainWindow::UpdateAPIIndicator(bool override) {
static std::array graphics_apis = {QStringLiteral("OPENGL"), QStringLiteral("OPENGLES"),
QStringLiteral("VULKAN")};
static std::array graphics_api_colors = {QStringLiteral("#00ccdd"), QStringLiteral("#ba2a8d"),
QStringLiteral("#91242a")};
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);
}
const QString style_sheet = QStringLiteral("QPushButton { font-weight: bold; color: %0; }")
.arg(graphics_api_colors[api_index]);
graphics_api_button->setText(graphics_apis[api_index]);
graphics_api_button->setStyleSheet(style_sheet);
}
void GMainWindow::OnMouseActivity() {
ShowMouseCursor();
}
@ -2292,8 +2325,16 @@ void GMainWindow::UpdateUITheme() {
QStringList theme_paths(default_theme_paths);
if (is_default_theme || current_theme.isEmpty()) {
qApp->setStyleSheet({});
setStyleSheet({});
const QString theme_uri(QStringLiteral(":default/style.qss"));
QFile f(theme_uri);
if (f.open(QFile::ReadOnly | QFile::Text)) {
QTextStream ts(&f);
qApp->setStyleSheet(ts.readAll());
setStyleSheet(ts.readAll());
} else {
qApp->setStyleSheet({});
setStyleSheet({});
}
theme_paths.append(default_icons);
QIcon::setThemeName(default_icons);
} else {
@ -2440,14 +2481,6 @@ int main(int argc, char* argv[]) {
QCoreApplication::setOrganizationName(QStringLiteral("Citra team"));
QCoreApplication::setApplicationName(QStringLiteral("Citra"));
QSurfaceFormat format;
format.setVersion(4, 3);
format.setProfile(QSurfaceFormat::CoreProfile);
format.setSwapInterval(0);
// TODO: expose a setting for buffer value (ie default/single/double/triple)
format.setSwapBehavior(QSurfaceFormat::DefaultSwapBehavior);
QSurfaceFormat::setDefaultFormat(format);
#ifdef __APPLE__
std::string bin_path = FileUtil::GetBundleDirectory() + DIR_SEP + "..";
chdir(bin_path.c_str());

View File

@ -7,6 +7,7 @@
#include <array>
#include <memory>
#include <QMainWindow>
#include <QPushButton>
#include <QTimer>
#include <QTranslator>
#include "citra_qt/compatibility_list.h"
@ -234,6 +235,7 @@ private:
void InstallCIA(QStringList filepaths);
void HideMouseCursor();
void ShowMouseCursor();
void UpdateAPIIndicator(bool override);
std::unique_ptr<Ui::MainWindow> ui;
@ -248,6 +250,7 @@ private:
QLabel* emu_speed_label = nullptr;
QLabel* game_fps_label = nullptr;
QLabel* emu_frametime_label = nullptr;
QPushButton* graphics_api_button = nullptr;
QTimer status_bar_update_timer;
bool message_label_used_for_movie = false;

View File

@ -5,6 +5,7 @@
#pragma once
#include <memory>
#include <unordered_map>
#include <unordered_set>
#include <QDialog>
#include <QSortFilterProxyModel>

View File

@ -7,7 +7,6 @@
#include <QIcon>
#include <QMessageBox>
#include <QStandardItemModel>
#include "citra_qt/game_list.h"
#include "citra_qt/multiplayer/client_room.h"
#include "citra_qt/multiplayer/direct_connect.h"
#include "citra_qt/multiplayer/host_room.h"
@ -16,7 +15,6 @@
#include "citra_qt/multiplayer/state.h"
#include "citra_qt/uisettings.h"
#include "citra_qt/util/clickable_label.h"
#include "common/announce_multiplayer_room.h"
#include "common/logging/log.h"
MultiplayerState::MultiplayerState(QWidget* parent, QStandardItemModel* game_list_model,
@ -231,8 +229,9 @@ bool MultiplayerState::OnCloseRoom() {
if (room->GetState() != Network::Room::State::Open) {
return true;
}
// Save ban list
UISettings::values.ban_list = std::move(room->GetBanList());
UISettings::values.ban_list = room->GetBanList();
room->Destroy();
announce_multiplayer_session->Stop();

View File

@ -78,6 +78,7 @@ add_library(common STATIC
logging/backend.h
logging/filter.cpp
logging/filter.h
logging/formatter.h
logging/log.h
logging/text_formatter.cpp
logging/text_formatter.h

View File

@ -59,6 +59,60 @@ __declspec(dllimport) void __stdcall DebugBreak(void);
#endif // _MSC_VER ndef
#define DECLARE_ENUM_FLAG_OPERATORS(type) \
[[nodiscard]] constexpr type operator|(type a, type b) noexcept { \
using T = std::underlying_type_t<type>; \
return static_cast<type>(static_cast<T>(a) | static_cast<T>(b)); \
} \
[[nodiscard]] constexpr type operator&(type a, type b) noexcept { \
using T = std::underlying_type_t<type>; \
return static_cast<type>(static_cast<T>(a) & static_cast<T>(b)); \
} \
[[nodiscard]] constexpr type operator^(type a, type b) noexcept { \
using T = std::underlying_type_t<type>; \
return static_cast<type>(static_cast<T>(a) ^ static_cast<T>(b)); \
} \
[[nodiscard]] constexpr type operator<<(type a, type b) noexcept { \
using T = std::underlying_type_t<type>; \
return static_cast<type>(static_cast<T>(a) << static_cast<T>(b)); \
} \
[[nodiscard]] constexpr type operator>>(type a, type b) noexcept { \
using T = std::underlying_type_t<type>; \
return static_cast<type>(static_cast<T>(a) >> static_cast<T>(b)); \
} \
constexpr type& operator|=(type& a, type b) noexcept { \
a = a | b; \
return a; \
} \
constexpr type& operator&=(type& a, type b) noexcept { \
a = a & b; \
return a; \
} \
constexpr type& operator^=(type& a, type b) noexcept { \
a = a ^ b; \
return a; \
} \
constexpr type& operator<<=(type& a, type b) noexcept { \
a = a << b; \
return a; \
} \
constexpr type& operator>>=(type& a, type b) noexcept { \
a = a >> b; \
return a; \
} \
[[nodiscard]] constexpr type operator~(type key) noexcept { \
using T = std::underlying_type_t<type>; \
return static_cast<type>(~static_cast<T>(key)); \
} \
[[nodiscard]] constexpr bool True(type key) noexcept { \
using T = std::underlying_type_t<type>; \
return static_cast<T>(key) != 0; \
} \
[[nodiscard]] constexpr bool False(type key) noexcept { \
using T = std::underlying_type_t<type>; \
return static_cast<T>(key) == 0; \
}
// Generic function to get last error message.
// Call directly after the command or use the error num.
// This function might change the error code.

View File

@ -31,8 +31,10 @@
#endif
// 64 bit offsets for MSVC and MinGW. MinGW also needs this for using _wstat64
#ifndef __MINGW64__
#define stat _stat64
#define fstat _fstat64
#endif
#else
#ifdef __APPLE__

View File

@ -4,6 +4,7 @@
#pragma once
#include <concepts>
#include <cstddef>
#include <cstring>
#include "common/cityhash.h"
@ -41,6 +42,13 @@ inline u64 HashCombine(std::size_t& seed, const u64 hash) {
return seed ^= hash + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
template <typename T>
struct IdentityHash {
T operator()(const T& value) const {
return value;
}
};
/// A helper template that ensures the padding in a struct is initialized by memsetting to 0.
template <typename T>
struct HashableStruct {

View File

@ -235,6 +235,7 @@ void DebuggerBackend::Write(const Entry& entry) {
CLS(Render) \
SUB(Render, Software) \
SUB(Render, OpenGL) \
SUB(Render, Vulkan) \
CLS(Audio) \
SUB(Audio, DSP) \
SUB(Audio, Sink) \

View File

@ -8,6 +8,7 @@
#include <array>
#include "common/common_types.h"
#include "common/logging/formatter.h"
namespace Log {
// trims up to and including the last of ../, ..\, src/, src\ in a string
@ -102,6 +103,7 @@ enum class Class : ClassType {
Render, ///< Emulator video output and hardware acceleration
Render_Software, ///< Software renderer backend
Render_OpenGL, ///< OpenGL backend
Render_Vulkan, ///< Vulkan backend
Audio, ///< Audio emulation
Audio_DSP, ///< The HLE and LLE implementations of the DSP
Audio_Sink, ///< Emulator audio output backend

View File

@ -4,6 +4,7 @@
#pragma once
#include <compare>
#include <cstdlib>
#include <type_traits>
@ -23,19 +24,31 @@ struct Rectangle {
constexpr Rectangle(T left, T top, T right, T bottom)
: left(left), top(top), right(right), bottom(bottom) {}
[[nodiscard]] T GetWidth() const {
constexpr auto operator<=>(const Rectangle&) const = default;
constexpr void operator*=(const T value) {
left *= value;
top *= value;
right *= value;
bottom *= value;
}
[[nodiscard]] constexpr Rectangle operator*(const T value) const {
return Rectangle{left * value, top * value, right * value, bottom * value};
}
[[nodiscard]] constexpr T GetWidth() const {
return std::abs(static_cast<std::make_signed_t<T>>(right - left));
}
[[nodiscard]] T GetHeight() const {
[[nodiscard]] constexpr T GetHeight() const {
return std::abs(static_cast<std::make_signed_t<T>>(bottom - top));
}
[[nodiscard]] Rectangle<T> TranslateX(const T x) const {
[[nodiscard]] constexpr Rectangle<T> TranslateX(const T x) const {
return Rectangle{left + x, top, right + x, bottom};
}
[[nodiscard]] Rectangle<T> TranslateY(const T y) const {
[[nodiscard]] constexpr Rectangle<T> TranslateY(const T y) const {
return Rectangle{left, top + y, right, bottom + y};
}
[[nodiscard]] Rectangle<T> Scale(const float s) const {
[[nodiscard]] constexpr Rectangle<T> Scale(const float s) const {
return Rectangle{left, top, static_cast<T>(left + GetWidth() * s),
static_cast<T>(top + GetHeight() * s)};
}

View File

@ -3,8 +3,8 @@
// Refer to the license.txt file included.
#pragma once
#include <memory>
#include <span>
#include <vector>
#include <boost/serialization/export.hpp>
#include <boost/serialization/shared_ptr.hpp>
@ -65,8 +65,11 @@ private:
BOOST_CLASS_EXPORT_KEY(BufferMem);
/// A managed reference to host-side memory. Fast enough to be used everywhere instead of u8*
/// Supports serialization.
/**
* A managed reference to host-side memory.
* Fast enough to be used everywhere instead of u8*
* Supports serialization.
*/
class MemoryRef {
public:
MemoryRef() = default;
@ -75,35 +78,52 @@ public:
: backing_mem(std::move(backing_mem_)), offset(0) {
Init();
}
MemoryRef(std::shared_ptr<BackingMem> backing_mem_, u64 offset_)
: backing_mem(std::move(backing_mem_)), offset(offset_) {
ASSERT(offset <= backing_mem->GetSize());
Init();
}
explicit operator bool() const {
return cptr != nullptr;
}
operator u8*() {
return cptr;
}
u8* GetPtr() {
return cptr;
}
operator const u8*() const {
return cptr;
}
u8* GetPtr() {
return cptr;
}
const u8* GetPtr() const {
return cptr;
}
auto GetWriteBytes(std::size_t size) {
return std::span{reinterpret_cast<std::byte*>(cptr), size > csize ? csize : size};
}
auto GetReadBytes(std::size_t size) const {
return std::span{reinterpret_cast<const std::byte*>(cptr), size > csize ? csize : size};
}
std::size_t GetSize() const {
return csize;
}
MemoryRef& operator+=(u32 offset_by) {
ASSERT(offset_by < csize);
offset += offset_by;
Init();
return *this;
}
MemoryRef operator+(u32 offset_by) const {
ASSERT(offset_by < csize);
return MemoryRef(backing_mem, offset + offset_by);

View File

@ -23,12 +23,3 @@ typedef void* HANDLE;
#include <microprofile.h>
#define MP_RGB(r, g, b) ((r) << 16 | (g) << 8 | (b) << 0)
// On OS X, some Mach header included by MicroProfile defines these as macros, conflicting with
// identifiers we use.
#ifdef PAGE_SIZE
#undef PAGE_SIZE
#endif
#ifdef PAGE_MASK
#undef PAGE_MASK
#endif

View File

@ -110,8 +110,6 @@ add_library(core STATIC
frontend/input.h
frontend/mic.cpp
frontend/mic.h
frontend/scope_acquire_context.cpp
frontend/scope_acquire_context.h
gdbstub/gdbstub.cpp
gdbstub/gdbstub.h
hle/applets/applet.cpp

View File

@ -261,6 +261,8 @@ u32 ARM_Dynarmic::GetCP15Register(CP15Register reg) const {
default:
UNREACHABLE_MSG("Unknown CP15 register: {}", reg);
}
return 0;
}
void ARM_Dynarmic::SetCP15Register(CP15Register reg, u32 value) {

View File

@ -849,17 +849,13 @@ static int InterpreterTranslateBlock(ARMul_State* cpu, std::size_t& bb_start, u3
// Save start addr of basicblock in CreamCache
ARM_INST_PTR inst_base = nullptr;
TransExtData ret = TransExtData::NON_BRANCH;
int size = 0; // instruction size of basic block
bb_start = trans_cache_buf_top;
u32 phys_addr = addr;
u32 pc_start = cpu->Reg[15];
while (ret == TransExtData::NON_BRANCH) {
unsigned int inst_size = InterpreterTranslateInstruction(cpu, phys_addr, inst_base);
size++;
u32 inst_size = InterpreterTranslateInstruction(cpu, phys_addr, inst_base);
phys_addr += inst_size;
if ((phys_addr & 0xfff) == 0) {
@ -972,7 +968,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
// GCC and Clang have a C++ extension to support a lookup table of labels. Otherwise, fallback to a
// clunky switch statement.
#if defined __GNUC__ || defined __clang__
#if defined __GNUC__ || (defined __clang__ && !defined _MSC_VER)
#define GOTO_NEXT_INST \
GDB_BP_CHECK; \
if (num_instrs >= cpu->NumInstrsToExecute) \

View File

@ -1218,7 +1218,7 @@ u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr) {
for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) {
u32 except;
char type;
[[maybe_unused]] char type;
type = (fop->flags & OP_SD) ? 's' : 'd';
if (op == FOP_EXT)

View File

@ -1242,7 +1242,7 @@ u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr) {
for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) {
s32 m = vfp_get_float(state, sm);
u32 except;
char type;
[[maybe_unused]] char type;
type = (fop->flags & OP_DD) ? 'd' : 's';
if (op == FOP_EXT)

View File

@ -47,7 +47,7 @@ void CheatEngine::AddCheat(const std::shared_ptr<CheatBase>& cheat) {
void CheatEngine::RemoveCheat(int index) {
std::unique_lock<std::shared_mutex> lock(cheats_list_mutex);
if (index < 0 || index >= cheats_list.size()) {
if (index < 0 || index >= static_cast<int>(cheats_list.size())) {
LOG_ERROR(Core_Cheats, "Invalid index {}", index);
return;
}
@ -56,7 +56,7 @@ void CheatEngine::RemoveCheat(int index) {
void CheatEngine::UpdateCheat(int index, const std::shared_ptr<CheatBase>& new_cheat) {
std::unique_lock<std::shared_mutex> lock(cheats_list_mutex);
if (index < 0 || index >= cheats_list.size()) {
if (index < 0 || index >= static_cast<int>(cheats_list.size())) {
LOG_ERROR(Core_Cheats, "Invalid index {}", index);
return;
}

View File

@ -424,8 +424,6 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, u32 system_mo
switch (result) {
case VideoCore::ResultStatus::ErrorGenericDrivers:
return ResultStatus::ErrorVideoCore_ErrorGenericDrivers;
case VideoCore::ResultStatus::ErrorBelowGL43:
return ResultStatus::ErrorVideoCore_ErrorBelowGL43;
default:
return ResultStatus::ErrorVideoCore;
}

View File

@ -88,8 +88,6 @@ public:
ErrorVideoCore, ///< Error in the video core
ErrorVideoCore_ErrorGenericDrivers, ///< Error in the video core due to the user having
/// generic drivers installed
ErrorVideoCore_ErrorBelowGL43, ///< Error in the video core due to the user not having
/// OpenGL 4.3 or higher
ErrorSavestate, ///< Error saving or loading
ShutdownRequested, ///< Emulated program requested a system shutdown
ErrorUnknown ///< Any other error

View File

@ -301,10 +301,6 @@ private:
std::vector<std::shared_ptr<Timer>> timers;
Timer* current_timer = nullptr;
// Stores a scaling for the internal clockspeed. Changing this number results in
// under/overclocking the guest cpu
double cpu_clock_scale = 1.0;
// When true, the event queue can't be modified. Used while deserializing to workaround
// destructor side effects.
bool event_queue_locked = false;

View File

@ -12,6 +12,17 @@
namespace Frontend {
/// Information for the Graphics Backends signifying what type of screen pointer is in
/// WindowInformation
enum class WindowSystemType : u8 {
Headless,
Android,
Windows,
MacOS,
X11,
Wayland,
};
struct Frame;
/**
* For smooth Vsync rendering, we want to always present the latest frame that the core generates,
@ -60,11 +71,33 @@ class GraphicsContext {
public:
virtual ~GraphicsContext();
/// Inform the driver to swap the front/back buffers and present the current image
virtual void SwapBuffers(){};
/// Makes the graphics context current for the caller thread
virtual void MakeCurrent() = 0;
virtual void MakeCurrent(){};
/// Releases (dunno if this is the "right" word) the context from the caller thread
virtual void DoneCurrent() = 0;
virtual void DoneCurrent(){};
class Scoped {
public:
explicit Scoped(GraphicsContext& context_) : context(context_) {
context.MakeCurrent();
}
~Scoped() {
context.DoneCurrent();
}
private:
GraphicsContext& context;
};
/// Calls MakeCurrent on the context and calls DoneCurrent when the scope for the returned value
/// ends
[[nodiscard]] Scoped Acquire() {
return Scoped{*this};
}
};
/**
@ -95,6 +128,23 @@ public:
std::pair<unsigned, unsigned> min_client_area_size;
};
/// Data describing host window system information
struct WindowSystemInfo {
// Window system type. Determines which GL context or Vulkan WSI is used.
WindowSystemType type = WindowSystemType::Headless;
// Connection to a display server. This is used on X11 and Wayland platforms.
void* display_connection = nullptr;
// Render surface. This is a pointer to the native window handle, which depends
// on the platform. e.g. HWND for Windows, Window for X11. If the surface is
// set to nullptr, the video backend will run in headless mode.
void* render_surface = nullptr;
// Scale of the render surface. For hidpi systems, this will be >1.
float render_surface_scale = 1.0f;
};
/// Polls window events
virtual void PollEvents() = 0;
@ -158,6 +208,13 @@ public:
config = val;
}
/**
* Returns system information about the drawing area.
*/
const WindowSystemInfo& GetWindowInfo() const {
return window_info;
}
/**
* Gets the framebuffer layout (width, height, and screen regions)
* @note This method is thread-safe
@ -204,6 +261,8 @@ protected:
framebuffer_layout = layout;
}
WindowSystemInfo window_info;
private:
/**
* Handler called when the minimal client area was requested to be changed via SetConfig.

View File

@ -1,17 +0,0 @@
// Copyright 2019 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "core/frontend/emu_window.h"
#include "core/frontend/scope_acquire_context.h"
namespace Frontend {
ScopeAcquireContext::ScopeAcquireContext(Frontend::GraphicsContext& context) : context{context} {
context.MakeCurrent();
}
ScopeAcquireContext::~ScopeAcquireContext() {
context.DoneCurrent();
}
} // namespace Frontend

View File

@ -1,23 +0,0 @@
// Copyright 2019 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "common/common_types.h"
namespace Frontend {
class GraphicsContext;
/// Helper class to acquire/release window context within a given scope
class ScopeAcquireContext : NonCopyable {
public:
explicit ScopeAcquireContext(Frontend::GraphicsContext& context);
~ScopeAcquireContext();
private:
Frontend::GraphicsContext& context;
};
} // namespace Frontend

View File

@ -80,7 +80,7 @@ private:
std::shared_ptr<Callback> timeout_callback;
void WakeUp(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
std::shared_ptr<WaitObject> object);
std::shared_ptr<WaitObject> object) override;
class DummyCallback : public WakeupCallback {
public:

View File

@ -138,10 +138,10 @@ ResultCode TranslateCommandBuffer(Kernel::KernelSystem& kernel, Memory::MemorySy
u32 size = static_cast<u32>(descInfo.size);
IPC::MappedBufferPermissions permissions = descInfo.perms;
VAddr page_start = Common::AlignDown(source_address, Memory::PAGE_SIZE);
VAddr page_start = Common::AlignDown(source_address, Memory::CITRA_PAGE_SIZE);
u32 page_offset = source_address - page_start;
u32 num_pages =
Common::AlignUp(page_offset + size, Memory::PAGE_SIZE) >> Memory::PAGE_BITS;
u32 num_pages = Common::AlignUp(page_offset + size, Memory::CITRA_PAGE_SIZE) >>
Memory::CITRA_PAGE_BITS;
// Skip when the size is zero and num_pages == 0
if (size == 0) {
@ -171,8 +171,8 @@ ResultCode TranslateCommandBuffer(Kernel::KernelSystem& kernel, Memory::MemorySy
found->target_address, size);
}
VAddr prev_reserve = page_start - Memory::PAGE_SIZE;
VAddr next_reserve = page_start + num_pages * Memory::PAGE_SIZE;
VAddr prev_reserve = page_start - Memory::CITRA_PAGE_SIZE;
VAddr next_reserve = page_start + num_pages * Memory::CITRA_PAGE_SIZE;
auto& prev_vma = src_process->vm_manager.FindVMA(prev_reserve)->second;
auto& next_vma = src_process->vm_manager.FindVMA(next_reserve)->second;
@ -180,8 +180,9 @@ ResultCode TranslateCommandBuffer(Kernel::KernelSystem& kernel, Memory::MemorySy
next_vma.meminfo_state == MemoryState::Reserved);
// Unmap the buffer and guard pages from the source process
ResultCode result = src_process->vm_manager.UnmapRange(
page_start - Memory::PAGE_SIZE, (num_pages + 2) * Memory::PAGE_SIZE);
ResultCode result =
src_process->vm_manager.UnmapRange(page_start - Memory::CITRA_PAGE_SIZE,
(num_pages + 2) * Memory::CITRA_PAGE_SIZE);
ASSERT(result == RESULT_SUCCESS);
mapped_buffer_context.erase(found);
@ -196,13 +197,13 @@ ResultCode TranslateCommandBuffer(Kernel::KernelSystem& kernel, Memory::MemorySy
// Reserve a page of memory before the mapped buffer
std::shared_ptr<BackingMem> reserve_buffer =
std::make_shared<BufferMem>(Memory::PAGE_SIZE);
std::make_shared<BufferMem>(Memory::CITRA_PAGE_SIZE);
dst_process->vm_manager.MapBackingMemoryToBase(
Memory::IPC_MAPPING_VADDR, Memory::IPC_MAPPING_SIZE, reserve_buffer,
Memory::PAGE_SIZE, Kernel::MemoryState::Reserved);
Memory::CITRA_PAGE_SIZE, Kernel::MemoryState::Reserved);
std::shared_ptr<BackingMem> buffer =
std::make_shared<BufferMem>(num_pages * Memory::PAGE_SIZE);
std::make_shared<BufferMem>(num_pages * Memory::CITRA_PAGE_SIZE);
memory.ReadBlock(*src_process, source_address, buffer->GetPtr() + page_offset, size);
// Map the page(s) into the target process' address space.

View File

@ -127,7 +127,7 @@ void Process::ParseKernelCaps(const u32* kernel_caps, std::size_t len) {
// Mapped memory page
AddressMapping mapping;
mapping.address = descriptor << 12;
mapping.size = Memory::PAGE_SIZE;
mapping.size = Memory::CITRA_PAGE_SIZE;
mapping.read_only = false;
mapping.unk_flag = false;
@ -265,7 +265,7 @@ ResultCode Process::HeapFree(VAddr target, u32 size) {
// Free heaps block by block
CASCADE_RESULT(auto backing_blocks, vm_manager.GetBackingBlocksForRange(target, size));
for (const auto [backing_memory, block_size] : backing_blocks) {
for (const auto& [backing_memory, block_size] : backing_blocks) {
memory_region->Free(kernel.memory.GetFCRAMOffset(backing_memory.GetPtr()), block_size);
}
@ -396,7 +396,7 @@ ResultCode Process::Map(VAddr target, VAddr source, u32 size, VMAPermission perm
CASCADE_RESULT(auto backing_blocks, vm_manager.GetBackingBlocksForRange(source, size));
VAddr interval_target = target;
for (const auto [backing_memory, block_size] : backing_blocks) {
for (const auto& [backing_memory, block_size] : backing_blocks) {
auto target_vma =
vm_manager.MapBackingMemory(interval_target, backing_memory, block_size, target_state);
ASSERT(target_vma.Succeeded());

View File

@ -219,10 +219,10 @@ ResultCode SVC::ControlMemory(u32* out_addr, u32 addr0, u32 addr1, u32 size, u32
"size=0x{:X}, permissions=0x{:08X}",
operation, addr0, addr1, size, permissions);
if ((addr0 & Memory::PAGE_MASK) != 0 || (addr1 & Memory::PAGE_MASK) != 0) {
if ((addr0 & Memory::CITRA_PAGE_MASK) != 0 || (addr1 & Memory::CITRA_PAGE_MASK) != 0) {
return ERR_MISALIGNED_ADDRESS;
}
if ((size & Memory::PAGE_MASK) != 0) {
if ((size & Memory::CITRA_PAGE_MASK) != 0) {
return ERR_MISALIGNED_SIZE;
}
@ -1288,7 +1288,7 @@ s64 SVC::GetSystemTick() {
/// Creates a memory block at the specified address with the specified permissions and size
ResultCode SVC::CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 my_permission,
u32 other_permission) {
if (size % Memory::PAGE_SIZE != 0)
if (size % Memory::CITRA_PAGE_SIZE != 0)
return ERR_MISALIGNED_SIZE;
std::shared_ptr<SharedMemory> shared_memory = nullptr;
@ -1393,7 +1393,7 @@ ResultCode SVC::AcceptSession(Handle* out_server_session, Handle server_port_han
return RESULT_SUCCESS;
}
static void CopyStringPart(char* out, const char* in, int offset, int max_length) {
static void CopyStringPart(char* out, const char* in, size_t offset, size_t max_length) {
size_t str_size = strlen(in);
if (offset < str_size) {
strncpy(out, in + offset, max_length - 1);
@ -1509,7 +1509,7 @@ ResultCode SVC::GetProcessInfo(s64* out, Handle process_handle, u32 type) {
// TODO(yuriks): Type 0 returns a slightly higher number than type 2, but I'm not sure
// what's the difference between them.
*out = process->memory_used;
if (*out % Memory::PAGE_SIZE != 0) {
if (*out % Memory::CITRA_PAGE_SIZE != 0) {
LOG_ERROR(Kernel_SVC, "called, memory size not page-aligned");
return ERR_MISALIGNED_SIZE;
}

View File

@ -105,9 +105,9 @@ void Thread::Stop() {
ReleaseThreadMutexes(this);
// Mark the TLS slot in the thread's page as free.
u32 tls_page = (tls_address - Memory::TLS_AREA_VADDR) / Memory::PAGE_SIZE;
u32 tls_page = (tls_address - Memory::TLS_AREA_VADDR) / Memory::CITRA_PAGE_SIZE;
u32 tls_slot =
((tls_address - Memory::TLS_AREA_VADDR) % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE;
((tls_address - Memory::TLS_AREA_VADDR) % Memory::CITRA_PAGE_SIZE) / Memory::TLS_ENTRY_SIZE;
ASSERT(owner_process.lock());
owner_process.lock()->tls_slots[tls_page].reset(tls_slot);
}
@ -374,13 +374,13 @@ ResultVal<std::shared_ptr<Thread>> KernelSystem::CreateThread(
auto memory_region = GetMemoryRegion(MemoryRegion::BASE);
// Allocate some memory from the end of the linear heap for this region.
auto offset = memory_region->LinearAllocate(Memory::PAGE_SIZE);
auto offset = memory_region->LinearAllocate(Memory::CITRA_PAGE_SIZE);
if (!offset) {
LOG_ERROR(Kernel_SVC,
"Not enough space in region to allocate a new TLS page for thread");
return ERR_OUT_OF_MEMORY;
}
owner_process->memory_used += Memory::PAGE_SIZE;
owner_process->memory_used += Memory::CITRA_PAGE_SIZE;
tls_slots.emplace_back(0); // The page is completely available at the start
available_page = tls_slots.size() - 1;
@ -390,14 +390,14 @@ ResultVal<std::shared_ptr<Thread>> KernelSystem::CreateThread(
// Map the page to the current process' address space.
vm_manager.MapBackingMemory(
Memory::TLS_AREA_VADDR + static_cast<VAddr>(available_page) * Memory::PAGE_SIZE,
memory.GetFCRAMRef(*offset), Memory::PAGE_SIZE, MemoryState::Locked);
Memory::TLS_AREA_VADDR + static_cast<VAddr>(available_page) * Memory::CITRA_PAGE_SIZE,
memory.GetFCRAMRef(*offset), Memory::CITRA_PAGE_SIZE, MemoryState::Locked);
}
// Mark the slot as used
tls_slots[available_page].set(available_slot);
thread->tls_address = Memory::TLS_AREA_VADDR +
static_cast<VAddr>(available_page) * Memory::PAGE_SIZE +
static_cast<VAddr>(available_page) * Memory::CITRA_PAGE_SIZE +
static_cast<VAddr>(available_slot) * Memory::TLS_ENTRY_SIZE;
memory.ZeroBlock(*owner_process, thread->tls_address, Memory::TLS_ENTRY_SIZE);

View File

@ -260,8 +260,8 @@ VMManager::VMAIter VMManager::StripIterConstness(const VMAHandle& iter) {
}
ResultVal<VMManager::VMAIter> VMManager::CarveVMA(VAddr base, u32 size) {
ASSERT_MSG((size & Memory::PAGE_MASK) == 0, "non-page aligned size: {:#10X}", size);
ASSERT_MSG((base & Memory::PAGE_MASK) == 0, "non-page aligned base: {:#010X}", base);
ASSERT_MSG((size & Memory::CITRA_PAGE_MASK) == 0, "non-page aligned size: {:#10X}", size);
ASSERT_MSG((base & Memory::CITRA_PAGE_MASK) == 0, "non-page aligned base: {:#010X}", base);
VMAIter vma_handle = StripIterConstness(FindVMA(base));
if (vma_handle == vma_map.end()) {
@ -296,8 +296,8 @@ ResultVal<VMManager::VMAIter> VMManager::CarveVMA(VAddr base, u32 size) {
}
ResultVal<VMManager::VMAIter> VMManager::CarveVMARange(VAddr target, u32 size) {
ASSERT_MSG((size & Memory::PAGE_MASK) == 0, "non-page aligned size: {:#10X}", size);
ASSERT_MSG((target & Memory::PAGE_MASK) == 0, "non-page aligned base: {:#010X}", target);
ASSERT_MSG((size & Memory::CITRA_PAGE_MASK) == 0, "non-page aligned size: {:#10X}", size);
ASSERT_MSG((target & Memory::CITRA_PAGE_MASK) == 0, "non-page aligned base: {:#010X}", target);
const VAddr target_end = target + size;
ASSERT(target_end >= target);

View File

@ -17,12 +17,9 @@
#include "core/file_sys/errors.h"
#include "core/file_sys/ncch_container.h"
#include "core/file_sys/title_metadata.h"
#include "core/hle/ipc.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/client_session.h"
#include "core/hle/kernel/errors.h"
#include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/server_session.h"
#include "core/hle/kernel/session.h"
#include "core/hle/service/am/am.h"
@ -610,7 +607,6 @@ void Module::Interface::FindDLCContentInfos(Kernel::HLERequestContext& ctx) {
std::string tmd_path = GetTitleMetadataPath(media_type, title_id);
u32 content_read = 0;
FileSys::TitleMetadata tmd;
if (tmd.Load(tmd_path) == Loader::ResultStatus::Success) {
std::size_t write_offset = 0;
@ -642,7 +638,6 @@ void Module::Interface::FindDLCContentInfos(Kernel::HLERequestContext& ctx) {
content_info_out.Write(&content_info, write_offset, sizeof(ContentInfo));
write_offset += sizeof(ContentInfo);
content_read++;
}
}

View File

@ -2,7 +2,6 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/common_paths.h"
#include "core/core.h"
#include "core/hle/applets/applet.h"
#include "core/hle/service/apt/applet_manager.h"
@ -27,47 +26,66 @@ struct AppletTitleData {
static constexpr std::size_t NumApplets = 29;
static constexpr std::array<AppletTitleData, NumApplets> applet_titleids = {{
{AppletId::HomeMenu, AppletId::None, 0x4003000008202, 0x4003000008F02, 0x4003000009802,
0x4003000008202, 0x400300000A102, 0x400300000A902, 0x400300000B102},
{AppletId::AlternateMenu, AppletId::None, 0x4003000008102, 0x4003000008102, 0x4003000008102,
0x4003000008102, 0x4003000008102, 0x4003000008102, 0x4003000008102},
{AppletId::Camera, AppletId::None, 0x4003000008402, 0x4003000009002, 0x4003000009902,
0x4003000008402, 0x400300000A202, 0x400300000AA02, 0x400300000B202},
{AppletId::FriendList, AppletId::None, 0x4003000008D02, 0x4003000009602, 0x4003000009F02,
0x4003000008D02, 0x400300000A702, 0x400300000AF02, 0x400300000B702},
{AppletId::GameNotes, AppletId::None, 0x4003000008702, 0x4003000009302, 0x4003000009C02,
0x4003000008702, 0x400300000A502, 0x400300000AD02, 0x400300000B502},
{AppletId::InternetBrowser, AppletId::None, 0x4003000008802, 0x4003000009402, 0x4003000009D02,
0x4003000008802, 0x400300000A602, 0x400300000AE02, 0x400300000B602},
{AppletId::InstructionManual, AppletId::None, 0x4003000008602, 0x4003000009202, 0x4003000009B02,
0x4003000008602, 0x400300000A402, 0x400300000AC02, 0x400300000B402},
{AppletId::Notifications, AppletId::None, 0x4003000008E02, 0x4003000009702, 0x400300000A002,
0x4003000008E02, 0x400300000A802, 0x400300000B002, 0x400300000B802},
{AppletId::Miiverse, AppletId::None, 0x400300000BC02, 0x400300000BD02, 0x400300000BE02,
0x400300000BC02, 0x4003000009E02, 0x4003000009502, 0x400300000B902},
{{AppletId::HomeMenu, AppletId::None},
{0x4003000008202, 0x4003000008F02, 0x4003000009802, 0x4003000008202, 0x400300000A102,
0x400300000A902, 0x400300000B102}},
{{AppletId::AlternateMenu, AppletId::None},
{0x4003000008102, 0x4003000008102, 0x4003000008102, 0x4003000008102, 0x4003000008102,
0x4003000008102, 0x4003000008102}},
{{AppletId::Camera, AppletId::None},
{0x4003000008402, 0x4003000009002, 0x4003000009902, 0x4003000008402, 0x400300000A202,
0x400300000AA02, 0x400300000B202}},
{{AppletId::FriendList, AppletId::None},
{0x4003000008D02, 0x4003000009602, 0x4003000009F02, 0x4003000008D02, 0x400300000A702,
0x400300000AF02, 0x400300000B702}},
{{AppletId::GameNotes, AppletId::None},
{0x4003000008702, 0x4003000009302, 0x4003000009C02, 0x4003000008702, 0x400300000A502,
0x400300000AD02, 0x400300000B502}},
{{AppletId::InternetBrowser, AppletId::None},
{0x4003000008802, 0x4003000009402, 0x4003000009D02, 0x4003000008802, 0x400300000A602,
0x400300000AE02, 0x400300000B602}},
{{AppletId::InstructionManual, AppletId::None},
{0x4003000008602, 0x4003000009202, 0x4003000009B02, 0x4003000008602, 0x400300000A402,
0x400300000AC02, 0x400300000B402}},
{{AppletId::Notifications, AppletId::None},
{0x4003000008E02, 0x4003000009702, 0x400300000A002, 0x4003000008E02, 0x400300000A802,
0x400300000B002, 0x400300000B802}},
{{AppletId::Miiverse, AppletId::None},
{0x400300000BC02, 0x400300000BD02, 0x400300000BE02, 0x400300000BC02, 0x4003000009E02,
0x4003000009502, 0x400300000B902}},
// These values obtained from an older NS dump firmware 4.5
{AppletId::MiiversePost, AppletId::None, 0x400300000BA02, 0x400300000BA02, 0x400300000BA02,
0x400300000BA02, 0x400300000BA02, 0x400300000BA02, 0x400300000BA02},
{{AppletId::MiiversePost, AppletId::None},
{0x400300000BA02, 0x400300000BA02, 0x400300000BA02, 0x400300000BA02, 0x400300000BA02,
0x400300000BA02, 0x400300000BA02}},
// {AppletId::MiiversePost, AppletId::None, 0x4003000008302, 0x4003000008B02, 0x400300000BA02,
// 0x4003000008302, 0x0, 0x0, 0x0},
{AppletId::AmiiboSettings, AppletId::None, 0x4003000009502, 0x4003000009E02, 0x400300000B902,
0x4003000009502, 0x0, 0x4003000008C02, 0x400300000BF02},
{AppletId::SoftwareKeyboard1, AppletId::SoftwareKeyboard2, 0x400300000C002, 0x400300000C802,
0x400300000D002, 0x400300000C002, 0x400300000D802, 0x400300000DE02, 0x400300000E402},
{AppletId::Ed1, AppletId::Ed2, 0x400300000C102, 0x400300000C902, 0x400300000D102,
0x400300000C102, 0x400300000D902, 0x400300000DF02, 0x400300000E502},
{AppletId::PnoteApp, AppletId::PnoteApp2, 0x400300000C302, 0x400300000CB02, 0x400300000D302,
0x400300000C302, 0x400300000DB02, 0x400300000E102, 0x400300000E702},
{AppletId::SnoteApp, AppletId::SnoteApp2, 0x400300000C402, 0x400300000CC02, 0x400300000D402,
0x400300000C402, 0x400300000DC02, 0x400300000E202, 0x400300000E802},
{AppletId::Error, AppletId::Error2, 0x400300000C502, 0x400300000C502, 0x400300000C502,
0x400300000C502, 0x400300000CF02, 0x400300000CF02, 0x400300000CF02},
{AppletId::Mint, AppletId::Mint2, 0x400300000C602, 0x400300000CE02, 0x400300000D602,
0x400300000C602, 0x400300000DD02, 0x400300000E302, 0x400300000E902},
{AppletId::Extrapad, AppletId::Extrapad2, 0x400300000CD02, 0x400300000CD02, 0x400300000CD02,
0x400300000CD02, 0x400300000D502, 0x400300000D502, 0x400300000D502},
{AppletId::Memolib, AppletId::Memolib2, 0x400300000F602, 0x400300000F602, 0x400300000F602,
0x400300000F602, 0x400300000F602, 0x400300000F602, 0x400300000F602},
{{AppletId::AmiiboSettings, AppletId::None},
{0x4003000009502, 0x4003000009E02, 0x400300000B902, 0x4003000009502, 0x0, 0x4003000008C02,
0x400300000BF02}},
{{AppletId::SoftwareKeyboard1, AppletId::SoftwareKeyboard2},
{0x400300000C002, 0x400300000C802, 0x400300000D002, 0x400300000C002, 0x400300000D802,
0x400300000DE02, 0x400300000E402}},
{{AppletId::Ed1, AppletId::Ed2},
{0x400300000C102, 0x400300000C902, 0x400300000D102, 0x400300000C102, 0x400300000D902,
0x400300000DF02, 0x400300000E502}},
{{AppletId::PnoteApp, AppletId::PnoteApp2},
{0x400300000C302, 0x400300000CB02, 0x400300000D302, 0x400300000C302, 0x400300000DB02,
0x400300000E102, 0x400300000E702}},
{{AppletId::SnoteApp, AppletId::SnoteApp2},
{0x400300000C402, 0x400300000CC02, 0x400300000D402, 0x400300000C402, 0x400300000DC02,
0x400300000E202, 0x400300000E802}},
{{AppletId::Error, AppletId::Error2},
{0x400300000C502, 0x400300000C502, 0x400300000C502, 0x400300000C502, 0x400300000CF02,
0x400300000CF02, 0x400300000CF02}},
{{AppletId::Mint, AppletId::Mint2},
{0x400300000C602, 0x400300000CE02, 0x400300000D602, 0x400300000C602, 0x400300000DD02,
0x400300000E302, 0x400300000E902}},
{{AppletId::Extrapad, AppletId::Extrapad2},
{0x400300000CD02, 0x400300000CD02, 0x400300000CD02, 0x400300000CD02, 0x400300000D502,
0x400300000D502, 0x400300000D502}},
{{AppletId::Memolib, AppletId::Memolib2},
{0x400300000F602, 0x400300000F602, 0x400300000F602, 0x400300000F602, 0x400300000F602,
0x400300000F602, 0x400300000F602}},
// TODO(Subv): Fill in the rest of the titleids
}};

View File

@ -10,7 +10,6 @@
#include <cryptopp/osrng.h>
#include <cryptopp/sha.h>
#include "common/archives.h"
#include "common/common_paths.h"
#include "common/file_util.h"
#include "common/logging/log.h"
#include "common/string_util.h"
@ -107,7 +106,6 @@ static_assert(sizeof(ConsoleCountryInfo) == 4, "ConsoleCountryInfo must be exact
constexpr EULAVersion MAX_EULA_VERSION{0x7F, 0x7F};
constexpr ConsoleModelInfo CONSOLE_MODEL_OLD{NINTENDO_3DS_XL, {0, 0, 0}};
constexpr ConsoleModelInfo CONSOLE_MODEL_NEW{NEW_NINTENDO_3DS_XL, {0, 0, 0}};
constexpr u8 CONSOLE_LANGUAGE = LANGUAGE_EN;
constexpr UsernameBlock CONSOLE_USERNAME_BLOCK{u"CITRA", 0, 0};
constexpr BirthdayBlock PROFILE_BIRTHDAY{3, 25}; // March 25th, 2014
@ -269,7 +267,7 @@ void Module::Interface::GetSystemModel(Kernel::HLERequestContext& ctx) {
void Module::Interface::GetModelNintendo2DS(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x06, 0, 0);
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
u32 data;
u32 data{};
// TODO(Subv): Find out the correct error codes
rb.Push(cfg->GetConfigInfoBlock(ConsoleModelBlockID, 4, 0x8, reinterpret_cast<u8*>(&data)));
@ -370,7 +368,7 @@ ResultVal<void*> Module::GetConfigInfoBlockPointer(u32 block_id, u32 size, u32 f
}
ResultCode Module::GetConfigInfoBlock(u32 block_id, u32 size, u32 flag, void* output) {
void* pointer;
void* pointer = nullptr;
CASCADE_RESULT(pointer, GetConfigInfoBlockPointer(block_id, size, flag));
memcpy(output, pointer, size);
@ -378,7 +376,7 @@ ResultCode Module::GetConfigInfoBlock(u32 block_id, u32 size, u32 flag, void* ou
}
ResultCode Module::SetConfigInfoBlock(u32 block_id, u32 size, u32 flag, const void* input) {
void* pointer;
void* pointer = nullptr;
CASCADE_RESULT(pointer, GetConfigInfoBlockPointer(block_id, size, flag));
memcpy(pointer, input, size);
return RESULT_SUCCESS;
@ -701,7 +699,7 @@ void Module::SetSystemLanguage(SystemLanguage language) {
}
SystemLanguage Module::GetSystemLanguage() {
u8 block;
u8 block{};
GetConfigInfoBlock(LanguageBlockID, sizeof(block), 8, &block);
return static_cast<SystemLanguage>(block);
}
@ -712,7 +710,7 @@ void Module::SetSoundOutputMode(SoundOutputMode mode) {
}
SoundOutputMode Module::GetSoundOutputMode() {
u8 block;
u8 block{};
GetConfigInfoBlock(SoundOutputModeBlockID, sizeof(block), 8, &block);
return static_cast<SoundOutputMode>(block);
}
@ -723,7 +721,7 @@ void Module::SetCountryCode(u8 country_code) {
}
u8 Module::GetCountryCode() {
ConsoleCountryInfo block;
ConsoleCountryInfo block{};
GetConfigInfoBlock(CountryInfoBlockID, sizeof(block), 8, &block);
return block.country_code;
}
@ -734,7 +732,7 @@ void Module::SetCountryInfo(u8 country_code, u8 state_code) {
}
u8 Module::GetStateCode() {
ConsoleCountryInfo block;
ConsoleCountryInfo block{};
GetConfigInfoBlock(CountryInfoBlockID, sizeof(block), 8, &block);
return block.state_code;
}

View File

@ -7,6 +7,7 @@
#include <array>
#include <memory>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
#include "common/common_types.h"

View File

@ -192,7 +192,7 @@ static_assert(sizeof(CaptureState) == 0x8, "CaptureState structure size is wrong
void CSND_SND::Initialize(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x01, 5, 0);
const u32 size = Common::AlignUp(rp.Pop<u32>(), Memory::PAGE_SIZE);
const u32 size = Common::AlignUp(rp.Pop<u32>(), Memory::CITRA_PAGE_SIZE);
master_state_offset = rp.Pop<u32>();
channel_state_offset = rp.Pop<u32>();
capture_state_offset = rp.Pop<u32>();

View File

@ -95,6 +95,9 @@ void DSP_DSP::WriteProcessPipe(Kernel::HLERequestContext& ctx) {
buffer[6] = 0;
buffer[7] = 0;
break;
default:
LOG_ERROR(Service_DSP, "Unknown pipe {}", pipe);
break;
}
system.DSP().PipeWrite(pipe, buffer);

View File

@ -884,6 +884,8 @@ ResultVal<u16> FS_USER::GetSpecialContentIndexFromTMD(MediaType media_type, u64
default:
ASSERT(false);
}
return ResultCode(-1);
}
FS_USER::FS_USER(Core::System& system)

View File

@ -8,9 +8,7 @@
#include "common/microprofile.h"
#include "common/swap.h"
#include "core/core.h"
#include "core/hle/ipc.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/shared_memory.h"
#include "core/hle/kernel/shared_page.h"
#include "core/hle/result.h"
@ -83,7 +81,9 @@ u32 GSP_GPU::GetUnusedThreadId() const {
if (!used_thread_ids[id])
return id;
}
ASSERT_MSG(false, "All GSP threads are in use");
UNREACHABLE_MSG("All GSP threads are in use");
return 0;
}
/// Gets a pointer to a thread command buffer in GSP shared memory

View File

@ -1502,7 +1502,7 @@ u32 CROHelper::Fix(u32 fix_level) {
}
}
fix_end = Common::AlignUp(fix_end, Memory::PAGE_SIZE);
fix_end = Common::AlignUp(fix_end, Memory::CITRA_PAGE_SIZE);
u32 fixed_size = fix_end - module_address;
SetField(FixedSize, fixed_size);
@ -1525,8 +1525,8 @@ std::tuple<VAddr, u32> CROHelper::GetExecutablePages() const {
SegmentEntry entry;
GetEntry(system.Memory(), i, entry);
if (entry.type == SegmentType::Code && entry.size != 0) {
VAddr begin = Common::AlignDown(entry.offset, Memory::PAGE_SIZE);
VAddr end = Common::AlignUp(entry.offset + entry.size, Memory::PAGE_SIZE);
VAddr begin = Common::AlignDown(entry.offset, Memory::CITRA_PAGE_SIZE);
VAddr end = Common::AlignUp(entry.offset + entry.size, Memory::CITRA_PAGE_SIZE);
return std::make_tuple(begin, end - begin);
}
}

View File

@ -87,19 +87,19 @@ void RO::Initialize(Kernel::HLERequestContext& ctx) {
return;
}
if (crs_buffer_ptr & Memory::PAGE_MASK) {
if (crs_buffer_ptr & Memory::CITRA_PAGE_MASK) {
LOG_ERROR(Service_LDR, "CRS original address is not aligned");
rb.Push(ERROR_MISALIGNED_ADDRESS);
return;
}
if (crs_address & Memory::PAGE_MASK) {
if (crs_address & Memory::CITRA_PAGE_MASK) {
LOG_ERROR(Service_LDR, "CRS mapping address is not aligned");
rb.Push(ERROR_MISALIGNED_ADDRESS);
return;
}
if (crs_size & Memory::PAGE_MASK) {
if (crs_size & Memory::CITRA_PAGE_MASK) {
LOG_ERROR(Service_LDR, "CRS size is not aligned");
rb.Push(ERROR_MISALIGNED_SIZE);
return;
@ -207,21 +207,21 @@ void RO::LoadCRO(Kernel::HLERequestContext& ctx, bool link_on_load_bug_fix) {
return;
}
if (cro_buffer_ptr & Memory::PAGE_MASK) {
if (cro_buffer_ptr & Memory::CITRA_PAGE_MASK) {
LOG_ERROR(Service_LDR, "CRO original address is not aligned");
rb.Push(ERROR_MISALIGNED_ADDRESS);
rb.Push<u32>(0);
return;
}
if (cro_address & Memory::PAGE_MASK) {
if (cro_address & Memory::CITRA_PAGE_MASK) {
LOG_ERROR(Service_LDR, "CRO mapping address is not aligned");
rb.Push(ERROR_MISALIGNED_ADDRESS);
rb.Push<u32>(0);
return;
}
if (cro_size & Memory::PAGE_MASK) {
if (cro_size & Memory::CITRA_PAGE_MASK) {
LOG_ERROR(Service_LDR, "CRO size is not aligned");
rb.Push(ERROR_MISALIGNED_SIZE);
rb.Push<u32>(0);
@ -354,7 +354,7 @@ void RO::UnloadCRO(Kernel::HLERequestContext& ctx) {
return;
}
if (cro_address & Memory::PAGE_MASK) {
if (cro_address & Memory::CITRA_PAGE_MASK) {
LOG_ERROR(Service_LDR, "CRO address is not aligned");
rb.Push(ERROR_MISALIGNED_ADDRESS);
return;
@ -421,7 +421,7 @@ void RO::LinkCRO(Kernel::HLERequestContext& ctx) {
return;
}
if (cro_address & Memory::PAGE_MASK) {
if (cro_address & Memory::CITRA_PAGE_MASK) {
LOG_ERROR(Service_LDR, "CRO address is not aligned");
rb.Push(ERROR_MISALIGNED_ADDRESS);
return;
@ -461,7 +461,7 @@ void RO::UnlinkCRO(Kernel::HLERequestContext& ctx) {
return;
}
if (cro_address & Memory::PAGE_MASK) {
if (cro_address & Memory::CITRA_PAGE_MASK) {
LOG_ERROR(Service_LDR, "CRO address is not aligned");
rb.Push(ERROR_MISALIGNED_ADDRESS);
return;

View File

@ -92,7 +92,8 @@ u16 NWM_UDS::GetNextAvailableNodeId() {
}
// Any connection attempts to an already full network should have been refused.
ASSERT_MSG(false, "No available connection slots in the network");
UNREACHABLE_MSG("No available connection slots in the network");
return 0;
}
void NWM_UDS::BroadcastNodeMap() {

View File

@ -15,9 +15,6 @@
namespace Service::NWM {
// 802.11 broadcast MAC address
constexpr MacAddress BroadcastMac = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
constexpr u64 DefaultNetworkUptime = 900000000; // 15 minutes in microseconds.
// Note: These values were taken from a packet capture of an o3DS XL

View File

@ -178,15 +178,6 @@ static const std::unordered_map<int, int> sockopt_map = {{
{0x1009, SO_ERROR},
}};
/// Converts a socket option from 3ds-specific to platform-specific
static int TranslateSockOpt(int console_opt_name) {
auto found = sockopt_map.find(console_opt_name);
if (found != sockopt_map.end()) {
return found->second;
}
return console_opt_name;
}
/// Structure to represent the 3ds' pollfd structure, which is different than most implementations
struct CTRPollFD {
u32 fd; ///< Socket handle

View File

@ -68,9 +68,11 @@ struct Regs {
case PixelFormat::RGB5A1:
case PixelFormat::RGBA4:
return 2;
default:
UNREACHABLE();
}
UNREACHABLE();
return 0;
}
INSERT_PADDING_WORDS(0x4);

View File

@ -94,13 +94,13 @@ ResultStatus AppLoader_NCCH::LoadExec(std::shared_ptr<Kernel::Process>& process)
codeset->CodeSegment().offset = 0;
codeset->CodeSegment().addr = overlay_ncch->exheader_header.codeset_info.text.address;
codeset->CodeSegment().size =
overlay_ncch->exheader_header.codeset_info.text.num_max_pages * Memory::PAGE_SIZE;
overlay_ncch->exheader_header.codeset_info.text.num_max_pages * Memory::CITRA_PAGE_SIZE;
codeset->RODataSegment().offset =
codeset->CodeSegment().offset + codeset->CodeSegment().size;
codeset->RODataSegment().addr = overlay_ncch->exheader_header.codeset_info.ro.address;
codeset->RODataSegment().size =
overlay_ncch->exheader_header.codeset_info.ro.num_max_pages * Memory::PAGE_SIZE;
overlay_ncch->exheader_header.codeset_info.ro.num_max_pages * Memory::CITRA_PAGE_SIZE;
// TODO(yuriks): Not sure if the bss size is added to the page-aligned .data size or just
// to the regular size. Playing it safe for now.
@ -111,7 +111,8 @@ ResultStatus AppLoader_NCCH::LoadExec(std::shared_ptr<Kernel::Process>& process)
codeset->RODataSegment().offset + codeset->RODataSegment().size;
codeset->DataSegment().addr = overlay_ncch->exheader_header.codeset_info.data.address;
codeset->DataSegment().size =
overlay_ncch->exheader_header.codeset_info.data.num_max_pages * Memory::PAGE_SIZE +
overlay_ncch->exheader_header.codeset_info.data.num_max_pages *
Memory::CITRA_PAGE_SIZE +
bss_page_size;
// Apply patches now that the entire codeset (including .bss) has been allocated

View File

@ -55,20 +55,20 @@ public:
private:
bool* At(VAddr addr) {
if (addr >= VRAM_VADDR && addr < VRAM_VADDR_END) {
return &vram[(addr - VRAM_VADDR) / PAGE_SIZE];
return &vram[(addr - VRAM_VADDR) / CITRA_PAGE_SIZE];
}
if (addr >= LINEAR_HEAP_VADDR && addr < LINEAR_HEAP_VADDR_END) {
return &linear_heap[(addr - LINEAR_HEAP_VADDR) / PAGE_SIZE];
return &linear_heap[(addr - LINEAR_HEAP_VADDR) / CITRA_PAGE_SIZE];
}
if (addr >= NEW_LINEAR_HEAP_VADDR && addr < NEW_LINEAR_HEAP_VADDR_END) {
return &new_linear_heap[(addr - NEW_LINEAR_HEAP_VADDR) / PAGE_SIZE];
return &new_linear_heap[(addr - NEW_LINEAR_HEAP_VADDR) / CITRA_PAGE_SIZE];
}
return nullptr;
}
std::array<bool, VRAM_SIZE / PAGE_SIZE> vram{};
std::array<bool, LINEAR_HEAP_SIZE / PAGE_SIZE> linear_heap{};
std::array<bool, NEW_LINEAR_HEAP_SIZE / PAGE_SIZE> new_linear_heap{};
std::array<bool, VRAM_SIZE / CITRA_PAGE_SIZE> vram{};
std::array<bool, LINEAR_HEAP_SIZE / CITRA_PAGE_SIZE> linear_heap{};
std::array<bool, NEW_LINEAR_HEAP_SIZE / CITRA_PAGE_SIZE> new_linear_heap{};
static_assert(sizeof(bool) == 1);
friend class boost::serialization::access;
@ -221,10 +221,10 @@ std::shared_ptr<PageTable> MemorySystem::GetCurrentPageTable() const {
void MemorySystem::MapPages(PageTable& page_table, u32 base, u32 size, MemoryRef memory,
PageType type) {
LOG_DEBUG(HW_Memory, "Mapping {} onto {:08X}-{:08X}", (void*)memory.GetPtr(), base * PAGE_SIZE,
(base + size) * PAGE_SIZE);
LOG_DEBUG(HW_Memory, "Mapping {} onto {:08X}-{:08X}", (void*)memory.GetPtr(),
base * CITRA_PAGE_SIZE, (base + size) * CITRA_PAGE_SIZE);
RasterizerFlushVirtualRegion(base << PAGE_BITS, size * PAGE_SIZE,
RasterizerFlushVirtualRegion(base << CITRA_PAGE_BITS, size * CITRA_PAGE_SIZE,
FlushMode::FlushAndInvalidate);
u32 end = base + size;
@ -235,36 +235,38 @@ void MemorySystem::MapPages(PageTable& page_table, u32 base, u32 size, MemoryRef
page_table.pointers[base] = memory;
// If the memory to map is already rasterizer-cached, mark the page
if (type == PageType::Memory && impl->cache_marker.IsCached(base * PAGE_SIZE)) {
if (type == PageType::Memory && impl->cache_marker.IsCached(base * CITRA_PAGE_SIZE)) {
page_table.attributes[base] = PageType::RasterizerCachedMemory;
page_table.pointers[base] = nullptr;
}
base += 1;
if (memory != nullptr && memory.GetSize() > PAGE_SIZE)
memory += PAGE_SIZE;
if (memory != nullptr && memory.GetSize() > CITRA_PAGE_SIZE)
memory += CITRA_PAGE_SIZE;
}
}
void MemorySystem::MapMemoryRegion(PageTable& page_table, VAddr base, u32 size, MemoryRef target) {
ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:08X}", size);
ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:08X}", base);
MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, target, PageType::Memory);
ASSERT_MSG((size & CITRA_PAGE_MASK) == 0, "non-page aligned size: {:08X}", size);
ASSERT_MSG((base & CITRA_PAGE_MASK) == 0, "non-page aligned base: {:08X}", base);
MapPages(page_table, base / CITRA_PAGE_SIZE, size / CITRA_PAGE_SIZE, target, PageType::Memory);
}
void MemorySystem::MapIoRegion(PageTable& page_table, VAddr base, u32 size,
MMIORegionPointer mmio_handler) {
ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:08X}", size);
ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:08X}", base);
MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, nullptr, PageType::Special);
ASSERT_MSG((size & CITRA_PAGE_MASK) == 0, "non-page aligned size: {:08X}", size);
ASSERT_MSG((base & CITRA_PAGE_MASK) == 0, "non-page aligned base: {:08X}", base);
MapPages(page_table, base / CITRA_PAGE_SIZE, size / CITRA_PAGE_SIZE, nullptr,
PageType::Special);
page_table.special_regions.emplace_back(SpecialRegion{base, size, mmio_handler});
}
void MemorySystem::UnmapRegion(PageTable& page_table, VAddr base, u32 size) {
ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:08X}", size);
ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:08X}", base);
MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, nullptr, PageType::Unmapped);
ASSERT_MSG((size & CITRA_PAGE_MASK) == 0, "non-page aligned size: {:08X}", size);
ASSERT_MSG((base & CITRA_PAGE_MASK) == 0, "non-page aligned base: {:08X}", base);
MapPages(page_table, base / CITRA_PAGE_SIZE, size / CITRA_PAGE_SIZE, nullptr,
PageType::Unmapped);
}
MemoryRef MemorySystem::GetPointerForRasterizerCache(VAddr addr) const {
@ -309,15 +311,15 @@ T ReadMMIO(MMIORegionPointer mmio_handler, VAddr addr);
template <typename T>
T MemorySystem::Read(const VAddr vaddr) {
const u8* page_pointer = impl->current_page_table->pointers[vaddr >> PAGE_BITS];
const u8* page_pointer = impl->current_page_table->pointers[vaddr >> CITRA_PAGE_BITS];
if (page_pointer) {
// NOTE: Avoid adding any extra logic to this fast-path block
T value;
std::memcpy(&value, &page_pointer[vaddr & PAGE_MASK], sizeof(T));
std::memcpy(&value, &page_pointer[vaddr & CITRA_PAGE_MASK], sizeof(T));
return value;
}
PageType type = impl->current_page_table->attributes[vaddr >> PAGE_BITS];
PageType type = impl->current_page_table->attributes[vaddr >> CITRA_PAGE_BITS];
switch (type) {
case PageType::Unmapped:
LOG_ERROR(HW_Memory, "unmapped Read{} @ 0x{:08X} at PC 0x{:08X}", sizeof(T) * 8, vaddr,
@ -345,14 +347,14 @@ void WriteMMIO(MMIORegionPointer mmio_handler, VAddr addr, const T data);
template <typename T>
void MemorySystem::Write(const VAddr vaddr, const T data) {
u8* page_pointer = impl->current_page_table->pointers[vaddr >> PAGE_BITS];
u8* page_pointer = impl->current_page_table->pointers[vaddr >> CITRA_PAGE_BITS];
if (page_pointer) {
// NOTE: Avoid adding any extra logic to this fast-path block
std::memcpy(&page_pointer[vaddr & PAGE_MASK], &data, sizeof(T));
std::memcpy(&page_pointer[vaddr & CITRA_PAGE_MASK], &data, sizeof(T));
return;
}
PageType type = impl->current_page_table->attributes[vaddr >> PAGE_BITS];
PageType type = impl->current_page_table->attributes[vaddr >> CITRA_PAGE_BITS];
switch (type) {
case PageType::Unmapped:
LOG_ERROR(HW_Memory, "unmapped Write{} 0x{:08X} @ 0x{:08X} at PC 0x{:08X}",
@ -376,15 +378,15 @@ void MemorySystem::Write(const VAddr vaddr, const T data) {
template <typename T>
bool MemorySystem::WriteExclusive(const VAddr vaddr, const T data, const T expected) {
u8* page_pointer = impl->current_page_table->pointers[vaddr >> PAGE_BITS];
u8* page_pointer = impl->current_page_table->pointers[vaddr >> CITRA_PAGE_BITS];
if (page_pointer) {
const auto volatile_pointer =
reinterpret_cast<volatile T*>(&page_pointer[vaddr & PAGE_MASK]);
reinterpret_cast<volatile T*>(&page_pointer[vaddr & CITRA_PAGE_MASK]);
return Common::AtomicCompareAndSwap(volatile_pointer, data, expected);
}
PageType type = impl->current_page_table->attributes[vaddr >> PAGE_BITS];
PageType type = impl->current_page_table->attributes[vaddr >> CITRA_PAGE_BITS];
switch (type) {
case PageType::Unmapped:
LOG_ERROR(HW_Memory, "unmapped Write{} 0x{:08X} @ 0x{:08X} at PC 0x{:08X}",
@ -411,14 +413,14 @@ bool MemorySystem::WriteExclusive(const VAddr vaddr, const T data, const T expec
bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) {
auto& page_table = *process.vm_manager.page_table;
auto page_pointer = page_table.pointers[vaddr >> PAGE_BITS];
auto page_pointer = page_table.pointers[vaddr >> CITRA_PAGE_BITS];
if (page_pointer)
return true;
if (page_table.attributes[vaddr >> PAGE_BITS] == PageType::RasterizerCachedMemory)
if (page_table.attributes[vaddr >> CITRA_PAGE_BITS] == PageType::RasterizerCachedMemory)
return true;
if (page_table.attributes[vaddr >> PAGE_BITS] != PageType::Special)
if (page_table.attributes[vaddr >> CITRA_PAGE_BITS] != PageType::Special)
return false;
MMIORegionPointer mmio_region = GetMMIOHandler(page_table, vaddr);
@ -434,12 +436,12 @@ bool MemorySystem::IsValidPhysicalAddress(const PAddr paddr) const {
}
u8* MemorySystem::GetPointer(const VAddr vaddr) {
u8* page_pointer = impl->current_page_table->pointers[vaddr >> PAGE_BITS];
u8* page_pointer = impl->current_page_table->pointers[vaddr >> CITRA_PAGE_BITS];
if (page_pointer) {
return page_pointer + (vaddr & PAGE_MASK);
return page_pointer + (vaddr & CITRA_PAGE_MASK);
}
if (impl->current_page_table->attributes[vaddr >> PAGE_BITS] ==
if (impl->current_page_table->attributes[vaddr >> CITRA_PAGE_BITS] ==
PageType::RasterizerCachedMemory) {
return GetPointerForRasterizerCache(vaddr);
}
@ -450,12 +452,12 @@ u8* MemorySystem::GetPointer(const VAddr vaddr) {
}
const u8* MemorySystem::GetPointer(const VAddr vaddr) const {
const u8* page_pointer = impl->current_page_table->pointers[vaddr >> PAGE_BITS];
const u8* page_pointer = impl->current_page_table->pointers[vaddr >> CITRA_PAGE_BITS];
if (page_pointer) {
return page_pointer + (vaddr & PAGE_MASK);
return page_pointer + (vaddr & CITRA_PAGE_MASK);
}
if (impl->current_page_table->attributes[vaddr >> PAGE_BITS] ==
if (impl->current_page_table->attributes[vaddr >> CITRA_PAGE_BITS] ==
PageType::RasterizerCachedMemory) {
return GetPointerForRasterizerCache(vaddr);
}
@ -487,35 +489,29 @@ const u8* MemorySystem::GetPhysicalPointer(PAddr address) const {
}
MemoryRef MemorySystem::GetPhysicalRef(PAddr address) const {
struct MemoryArea {
PAddr paddr_base;
u32 size;
constexpr std::array memory_areas = {
std::make_pair(VRAM_PADDR, VRAM_SIZE),
std::make_pair(DSP_RAM_PADDR, DSP_RAM_SIZE),
std::make_pair(FCRAM_PADDR, FCRAM_N3DS_SIZE),
std::make_pair(N3DS_EXTRA_RAM_PADDR, N3DS_EXTRA_RAM_SIZE),
};
static constexpr MemoryArea memory_areas[] = {
{VRAM_PADDR, VRAM_SIZE},
{DSP_RAM_PADDR, DSP_RAM_SIZE},
{FCRAM_PADDR, FCRAM_N3DS_SIZE},
{N3DS_EXTRA_RAM_PADDR, N3DS_EXTRA_RAM_SIZE},
};
const auto area = std::find_if(memory_areas.begin(), memory_areas.end(), [&](const auto& area) {
// Note: the region end check is inclusive because the user can pass in an address that
// represents an open right bound
return address >= area.first && address <= area.first + area.second;
});
const auto area =
std::find_if(std::begin(memory_areas), std::end(memory_areas), [&](const auto& area) {
// Note: the region end check is inclusive because the user can pass in an address that
// represents an open right bound
return address >= area.paddr_base && address <= area.paddr_base + area.size;
});
if (area == std::end(memory_areas)) {
LOG_ERROR(HW_Memory, "unknown GetPhysicalPointer @ 0x{:08X} at PC 0x{:08X}", address,
if (area == memory_areas.end()) {
LOG_ERROR(HW_Memory, "Unknown GetPhysicalPointer @ {:#08X} at PC {:#08X}", address,
Core::GetRunningCore().GetPC());
return nullptr;
}
u32 offset_into_region = address - area->paddr_base;
u32 offset_into_region = address - area->first;
std::shared_ptr<BackingMem> target_mem = nullptr;
switch (area->paddr_base) {
switch (area->first) {
case VRAM_PADDR:
target_mem = impl->vram_mem;
break;
@ -564,14 +560,14 @@ void MemorySystem::RasterizerMarkRegionCached(PAddr start, u32 size, bool cached
return;
}
u32 num_pages = ((start + size - 1) >> PAGE_BITS) - (start >> PAGE_BITS) + 1;
u32 num_pages = ((start + size - 1) >> CITRA_PAGE_BITS) - (start >> CITRA_PAGE_BITS) + 1;
PAddr paddr = start;
for (unsigned i = 0; i < num_pages; ++i, paddr += PAGE_SIZE) {
for (unsigned i = 0; i < num_pages; ++i, paddr += CITRA_PAGE_SIZE) {
for (VAddr vaddr : PhysicalToVirtualAddressForRasterizer(paddr)) {
impl->cache_marker.Mark(vaddr, cached);
for (auto page_table : impl->page_table_list) {
PageType& page_type = page_table->attributes[vaddr >> PAGE_BITS];
PageType& page_type = page_table->attributes[vaddr >> CITRA_PAGE_BITS];
if (cached) {
// Switch page type to cached if now cached
@ -582,7 +578,7 @@ void MemorySystem::RasterizerMarkRegionCached(PAddr start, u32 size, bool cached
break;
case PageType::Memory:
page_type = PageType::RasterizerCachedMemory;
page_table->pointers[vaddr >> PAGE_BITS] = nullptr;
page_table->pointers[vaddr >> CITRA_PAGE_BITS] = nullptr;
break;
default:
UNREACHABLE();
@ -596,8 +592,8 @@ void MemorySystem::RasterizerMarkRegionCached(PAddr start, u32 size, bool cached
break;
case PageType::RasterizerCachedMemory: {
page_type = PageType::Memory;
page_table->pointers[vaddr >> PAGE_BITS] =
GetPointerForRasterizerCache(vaddr & ~PAGE_MASK);
page_table->pointers[vaddr >> CITRA_PAGE_BITS] =
GetPointerForRasterizerCache(vaddr & ~CITRA_PAGE_MASK);
break;
}
default:
@ -705,12 +701,12 @@ void MemorySystem::ReadBlock(const Kernel::Process& process, const VAddr src_add
auto& page_table = *process.vm_manager.page_table;
std::size_t remaining_size = size;
std::size_t page_index = src_addr >> PAGE_BITS;
std::size_t page_offset = src_addr & PAGE_MASK;
std::size_t page_index = src_addr >> CITRA_PAGE_BITS;
std::size_t page_offset = src_addr & CITRA_PAGE_MASK;
while (remaining_size > 0) {
const std::size_t copy_amount = std::min(PAGE_SIZE - page_offset, remaining_size);
const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
const std::size_t copy_amount = std::min(CITRA_PAGE_SIZE - page_offset, remaining_size);
const VAddr current_vaddr = static_cast<VAddr>((page_index << CITRA_PAGE_BITS) + page_offset);
switch (page_table.attributes[page_index]) {
case PageType::Unmapped: {
@ -787,12 +783,12 @@ void MemorySystem::WriteBlock(const Kernel::Process& process, const VAddr dest_a
const void* src_buffer, const std::size_t size) {
auto& page_table = *process.vm_manager.page_table;
std::size_t remaining_size = size;
std::size_t page_index = dest_addr >> PAGE_BITS;
std::size_t page_offset = dest_addr & PAGE_MASK;
std::size_t page_index = dest_addr >> CITRA_PAGE_BITS;
std::size_t page_offset = dest_addr & CITRA_PAGE_MASK;
while (remaining_size > 0) {
const std::size_t copy_amount = std::min(PAGE_SIZE - page_offset, remaining_size);
const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
const std::size_t copy_amount = std::min(CITRA_PAGE_SIZE - page_offset, remaining_size);
const VAddr current_vaddr = static_cast<VAddr>((page_index << CITRA_PAGE_BITS) + page_offset);
switch (page_table.attributes[page_index]) {
case PageType::Unmapped: {
@ -836,14 +832,14 @@ void MemorySystem::ZeroBlock(const Kernel::Process& process, const VAddr dest_ad
const std::size_t size) {
auto& page_table = *process.vm_manager.page_table;
std::size_t remaining_size = size;
std::size_t page_index = dest_addr >> PAGE_BITS;
std::size_t page_offset = dest_addr & PAGE_MASK;
std::size_t page_index = dest_addr >> CITRA_PAGE_BITS;
std::size_t page_offset = dest_addr & CITRA_PAGE_MASK;
static const std::array<u8, PAGE_SIZE> zeros = {};
static const std::array<u8, CITRA_PAGE_SIZE> zeros = {};
while (remaining_size > 0) {
const std::size_t copy_amount = std::min(PAGE_SIZE - page_offset, remaining_size);
const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
const std::size_t copy_amount = std::min(CITRA_PAGE_SIZE - page_offset, remaining_size);
const VAddr current_vaddr = static_cast<VAddr>((page_index << CITRA_PAGE_BITS) + page_offset);
switch (page_table.attributes[page_index]) {
case PageType::Unmapped: {
@ -892,12 +888,12 @@ void MemorySystem::CopyBlock(const Kernel::Process& dest_process,
std::size_t size) {
auto& page_table = *src_process.vm_manager.page_table;
std::size_t remaining_size = size;
std::size_t page_index = src_addr >> PAGE_BITS;
std::size_t page_offset = src_addr & PAGE_MASK;
std::size_t page_index = src_addr >> CITRA_PAGE_BITS;
std::size_t page_offset = src_addr & CITRA_PAGE_MASK;
while (remaining_size > 0) {
const std::size_t copy_amount = std::min(PAGE_SIZE - page_offset, remaining_size);
const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
const std::size_t copy_amount = std::min(CITRA_PAGE_SIZE - page_offset, remaining_size);
const VAddr current_vaddr = static_cast<VAddr>((page_index << CITRA_PAGE_BITS) + page_offset);
switch (page_table.attributes[page_index]) {
case PageType::Unmapped: {

View File

@ -3,7 +3,6 @@
// Refer to the license.txt file included.
#pragma once
#include <array>
#include <cstddef>
#include <memory>
@ -27,17 +26,14 @@ class DspInterface;
namespace Memory {
// Are defined in a system header
#undef PAGE_SIZE
#undef PAGE_MASK
/**
* Page size used by the ARM architecture. This is the smallest granularity with which memory can
* be mapped.
*/
const u32 PAGE_SIZE = 0x1000;
const u32 PAGE_MASK = PAGE_SIZE - 1;
const int PAGE_BITS = 12;
const std::size_t PAGE_TABLE_NUM_ENTRIES = 1 << (32 - PAGE_BITS);
constexpr u32 CITRA_PAGE_SIZE = 0x1000;
constexpr u32 CITRA_PAGE_MASK = CITRA_PAGE_SIZE - 1;
constexpr int CITRA_PAGE_BITS = 12;
constexpr std::size_t PAGE_TABLE_NUM_ENTRIES = 1 << (32 - CITRA_PAGE_BITS);
enum class PageType {
/// Page is unmapped and should cause an access error.
@ -367,6 +363,7 @@ public:
u8* GetPointer(VAddr vaddr);
const u8* GetPointer(VAddr vaddr) const;
/// Returns true if the address refers to a valid memory region
bool IsValidPhysicalAddress(PAddr paddr) const;
/// Gets offset in FCRAM from a pointer inside FCRAM range

View File

@ -7,7 +7,6 @@
#include "audio_core/dsp_interface.h"
#include "core/core.h"
#include "core/gdbstub/gdbstub.h"
#include "core/hle/kernel/shared_page.h"
#include "core/hle/service/cam/cam.h"
#include "core/hle/service/hid/hid.h"
#include "core/hle/service/ir/ir_rst.h"
@ -19,10 +18,20 @@
namespace Settings {
std::string_view GetAPIName(GraphicsAPI api) {
switch (api) {
case GraphicsAPI::OpenGL:
return "OpenGL";
case GraphicsAPI::OpenGLES:
return "OpenGLES";
case GraphicsAPI::Vulkan:
return "Vulkan";
}
}
Values values = {};
void Apply() {
GDBStub::SetServerPort(values.gdbstub_port);
GDBStub::ToggleServer(values.use_gdbstub);
@ -73,62 +82,62 @@ void Apply() {
}
void LogSettings() {
const auto log_setting = [](std::string_view name, const auto& value) {
const auto LogSetting = [](std::string_view name, const auto& value) {
LOG_INFO(Config, "{}: {}", name, value);
};
LOG_INFO(Config, "Citra Configuration:");
log_setting("Core_UseCpuJit", values.use_cpu_jit);
log_setting("Core_CPUClockPercentage", values.cpu_clock_percentage);
log_setting("Renderer_UseGLES", values.use_gles);
log_setting("Renderer_UseHwRenderer", values.use_hw_renderer);
log_setting("Renderer_UseHwShader", values.use_hw_shader);
log_setting("Renderer_SeparableShader", values.separable_shader);
log_setting("Renderer_ShadersAccurateMul", values.shaders_accurate_mul);
log_setting("Renderer_UseShaderJit", values.use_shader_jit);
log_setting("Renderer_UseResolutionFactor", values.resolution_factor);
log_setting("Renderer_FrameLimit", values.frame_limit);
log_setting("Renderer_UseFrameLimitAlternate", values.use_frame_limit_alternate);
log_setting("Renderer_FrameLimitAlternate", values.frame_limit_alternate);
log_setting("Renderer_VSyncNew", values.use_vsync_new);
log_setting("Renderer_PostProcessingShader", values.pp_shader_name);
log_setting("Renderer_FilterMode", values.filter_mode);
log_setting("Renderer_TextureFilterName", values.texture_filter_name);
log_setting("Stereoscopy_Render3d", values.render_3d);
log_setting("Stereoscopy_Factor3d", values.factor_3d);
log_setting("Layout_LayoutOption", values.layout_option);
log_setting("Layout_SwapScreen", values.swap_screen);
log_setting("Layout_UprightScreen", values.upright_screen);
log_setting("Utility_DumpTextures", values.dump_textures);
log_setting("Utility_CustomTextures", values.custom_textures);
log_setting("Utility_UseDiskShaderCache", values.use_disk_shader_cache);
log_setting("Audio_EnableDspLle", values.enable_dsp_lle);
log_setting("Audio_EnableDspLleMultithread", values.enable_dsp_lle_multithread);
log_setting("Audio_OutputEngine", values.sink_id);
log_setting("Audio_EnableAudioStretching", values.enable_audio_stretching);
log_setting("Audio_OutputDevice", values.audio_device_id);
log_setting("Audio_InputDeviceType", values.mic_input_type);
log_setting("Audio_InputDevice", values.mic_input_device);
using namespace Service::CAM;
log_setting("Camera_OuterRightName", values.camera_name[OuterRightCamera]);
log_setting("Camera_OuterRightConfig", values.camera_config[OuterRightCamera]);
log_setting("Camera_OuterRightFlip", values.camera_flip[OuterRightCamera]);
log_setting("Camera_InnerName", values.camera_name[InnerCamera]);
log_setting("Camera_InnerConfig", values.camera_config[InnerCamera]);
log_setting("Camera_InnerFlip", values.camera_flip[InnerCamera]);
log_setting("Camera_OuterLeftName", values.camera_name[OuterLeftCamera]);
log_setting("Camera_OuterLeftConfig", values.camera_config[OuterLeftCamera]);
log_setting("Camera_OuterLeftFlip", values.camera_flip[OuterLeftCamera]);
log_setting("DataStorage_UseVirtualSd", values.use_virtual_sd);
log_setting("DataStorage_UseCustomStorage", values.use_custom_storage);
LogSetting("Core_UseCpuJit", values.use_cpu_jit);
LogSetting("Core_CPUClockPercentage", values.cpu_clock_percentage);
LogSetting("Renderer_GraphicsAPI", GetAPIName(values.graphics_api));
LogSetting("Renderer_AsyncRecording", values.async_command_recording);
LogSetting("Renderer_UseHwRenderer", values.use_hw_renderer);
LogSetting("Renderer_UseHwShader", values.use_hw_shader);
LogSetting("Renderer_SeparableShader", values.separable_shader);
LogSetting("Renderer_ShadersAccurateMul", values.shaders_accurate_mul);
LogSetting("Renderer_UseShaderJit", values.use_shader_jit);
LogSetting("Renderer_UseResolutionFactor", values.resolution_factor);
LogSetting("Renderer_FrameLimit", values.frame_limit);
LogSetting("Renderer_UseFrameLimitAlternate", values.use_frame_limit_alternate);
LogSetting("Renderer_FrameLimitAlternate", values.frame_limit_alternate);
LogSetting("Renderer_VSyncNew", values.use_vsync_new);
LogSetting("Renderer_PostProcessingShader", values.pp_shader_name);
LogSetting("Renderer_FilterMode", values.filter_mode);
LogSetting("Renderer_TextureFilterName", values.texture_filter_name);
LogSetting("Stereoscopy_Render3d", values.render_3d);
LogSetting("Stereoscopy_Factor3d", values.factor_3d);
LogSetting("Layout_LayoutOption", values.layout_option);
LogSetting("Layout_SwapScreen", values.swap_screen);
LogSetting("Layout_UprightScreen", values.upright_screen);
LogSetting("Utility_DumpTextures", values.dump_textures);
LogSetting("Utility_CustomTextures", values.custom_textures);
LogSetting("Utility_UseDiskShaderCache", values.use_disk_shader_cache);
LogSetting("Audio_EnableDspLle", values.enable_dsp_lle);
LogSetting("Audio_EnableDspLleMultithread", values.enable_dsp_lle_multithread);
LogSetting("Audio_OutputEngine", values.sink_id);
LogSetting("Audio_EnableAudioStretching", values.enable_audio_stretching);
LogSetting("Audio_OutputDevice", values.audio_device_id);
LogSetting("Audio_InputDeviceType", values.mic_input_type);
LogSetting("Audio_InputDevice", values.mic_input_device);
LogSetting("Camera_OuterRightName", values.camera_name[Service::CAM::OuterRightCamera]);
LogSetting("Camera_OuterRightConfig", values.camera_config[Service::CAM::OuterRightCamera]);
LogSetting("Camera_OuterRightFlip", values.camera_flip[Service::CAM::OuterRightCamera]);
LogSetting("Camera_InnerName", values.camera_name[Service::CAM::InnerCamera]);
LogSetting("Camera_InnerConfig", values.camera_config[Service::CAM::InnerCamera]);
LogSetting("Camera_InnerFlip", values.camera_flip[Service::CAM::InnerCamera]);
LogSetting("Camera_OuterLeftName", values.camera_name[Service::CAM::OuterLeftCamera]);
LogSetting("Camera_OuterLeftConfig", values.camera_config[Service::CAM::OuterLeftCamera]);
LogSetting("Camera_OuterLeftFlip", values.camera_flip[Service::CAM::OuterLeftCamera]);
LogSetting("DataStorage_UseVirtualSd", values.use_virtual_sd);
LogSetting("DataStorage_UseCustomStorage", values.use_custom_storage);
if (values.use_custom_storage) {
log_setting("DataStorage_SdmcDir", FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir));
log_setting("DataStorage_NandDir", FileUtil::GetUserPath(FileUtil::UserPath::NANDDir));
LogSetting("DataStorage_SdmcDir", FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir));
LogSetting("DataStorage_NandDir", FileUtil::GetUserPath(FileUtil::UserPath::NANDDir));
}
log_setting("System_IsNew3ds", values.is_new_3ds);
log_setting("System_RegionValue", values.region_value);
log_setting("Debugging_UseGdbstub", values.use_gdbstub);
log_setting("Debugging_GdbstubPort", values.gdbstub_port);
LogSetting("System_IsNew3ds", values.is_new_3ds);
LogSetting("System_RegionValue", values.region_value);
LogSetting("Debugging_UseGdbstub", values.use_gdbstub);
LogSetting("Debugging_GdbstubPort", values.gdbstub_port);
}
void LoadProfile(int index) {

View File

@ -14,6 +14,8 @@
namespace Settings {
enum class GraphicsAPI { OpenGL = 0, OpenGLES = 1, Vulkan = 2 };
enum class InitClock {
SystemTime = 0,
FixedTime = 1,
@ -163,13 +165,19 @@ struct Values {
u64 init_time;
// Renderer
bool use_gles;
GraphicsAPI graphics_api;
u16 physical_device;
bool spirv_shader_gen;
bool renderer_debug;
bool dump_command_buffers;
bool async_command_recording;
bool use_hw_renderer;
bool use_hw_shader;
bool separable_shader;
bool use_disk_shader_cache;
bool shaders_accurate_mul;
bool use_shader_jit;
bool use_vsync_new;
u16 resolution_factor;
bool use_frame_limit_alternate;
u16 frame_limit;
@ -203,12 +211,11 @@ struct Values {
bool filter_mode;
std::string pp_shader_name;
// Custom textures
bool dump_textures;
bool custom_textures;
bool preload_textures;
bool use_vsync_new;
// Audio
bool enable_dsp_lle;
bool enable_dsp_lle_multithread;

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