Compare commits

...

329 Commits

Author SHA1 Message Date
Marcin Mikołajczyk
824d332d0f
Setsockopt fixes (#3308)
* setsockopt: return correct error values for EPROCUNAVAIL

* setsockopt: handle SO_CONNECTTIMEO
2025-07-23 21:34:25 +03:00
TheTurtle
19c3d05ac1
shader_recompiler: Use VM bit for conditional discard (#3306) 2025-07-23 20:58:09 +03:00
Marcin Mikołajczyk
8dc50ffc79
Ssl stub (#3307)
* Correctly return zero root CA certs

* Stub sceHttpsGetCaList
2025-07-23 20:34:07 +03:00
Marcin Mikołajczyk
ea37ea11fc
Network config (#3292)
* Config entry isConnectedToNetwork

* Respect Config::isConnectedToNetwork when returning connection state

* Return connection status in NetCtlGetInfo

* Print connection data in log
2025-07-23 20:07:42 +03:00
TheTurtle
4d3578edbe
shader_recompiler: Fix incorrect bary coord loads when unsupported (#3303)
* shader_recompiler: Fix incorrect bary coord loads when unsupported

Also properly set sample rate shading

* emit_spirv: Implement BaryCoordSmoothCentroid
2025-07-23 19:46:06 +03:00
Stephen Miller
800b332f60
Core: Only update configs when using a different build. (#3299)
* Use a config version constant to check for config updates

Should address the largest issue with the prior update logic, where configs with removed/additional entries will no longer force config updates on every emulator boot.
This also makes it easier to add config entries, since you don't need to keep track of how many entries you add, or how many entries you removed.

* Use git revision hash instead of constant

In exchange for updating configs on every update, this removes the need for PR authors to manually change a constant when adding new settings.
2025-07-23 12:04:00 +03:00
DanielSvoboda
b4ec1bd371
qt: fix broken interface (#3301) 2025-07-23 11:01:55 +03:00
georgemoralis
0ad7fcb341
Microphone support (#3228)
* initial drafts

* initial implementation

* clang+reuse

* restore main

* improved AudioInInput

* fix microphone

* +

* +

* adds microphone selection to the interface

* added squidbus review fixes

* Update src/core/libraries/audio/audioin.cpp

Co-authored-by: squidbus <175574877+squidbus@users.noreply.github.com>

* Update src/core/libraries/audio/audioin.cpp

Co-authored-by: squidbus <175574877+squidbus@users.noreply.github.com>

* Increased entries in config.cpp

---------

Co-authored-by: DanielSvoboda <daniel.svoboda@hotmail.com>
Co-authored-by: squidbus <175574877+squidbus@users.noreply.github.com>
2025-07-23 06:54:18 +03:00
georgemoralis
16a6469b75
[ci skip] Qt GUI: Update Translation. (#3297)
Co-authored-by: georgemoralis <4313123+georgemoralis@users.noreply.github.com>
2025-07-23 06:53:34 +03:00
TheTurtle
7502739425
control_flow_graph: Treat empty conditional branch as noop (#3296) 2025-07-23 06:09:14 +03:00
DanielSvoboda
de11de43f2
qt: fix display full version string in Release channel (#3295) 2025-07-23 05:36:55 +03:00
georgemoralis
14ef56d148 clang fix 2025-07-23 00:11:09 +03:00
georgemoralis
9e2af5f619
New Crowdin updates (#3270)
* New translations en_us.ts (Greek)

* New translations en_us.ts (Vietnamese)

* New translations en_us.ts (Indonesian)

* New translations en_us.ts (Vietnamese)
2025-07-23 00:00:21 +03:00
Valdis Bogdāns
637e503685
Ime fixes (#3288)
* - typo fix
- added validations for sceImeKeyboardOpen/Close
- fixed mistakes in logs
- additional  log spam for debuging

* Disable user id validation

Disable user id validation until user manager is ready.

---------

Co-authored-by: w1naenator <valdis.bogdans@hotmail.com>
2025-07-22 11:27:02 +03:00
rainmakerv2
1fc9eedbab
Add default trophy sound (#3271)
* Add default trophy sound

* delete include to removed folder

* remove redundant conditions

* Change trophy sound - credit to Tlarok
2025-07-22 00:52:20 +03:00
kalaposfos13
bad9cd097a
Make remote link verification for disabling the autoupdater case-independent (#3287) 2025-07-22 00:52:01 +03:00
georgemoralis
a4c5fa4b5c
Using custom usb lib (#3284)
* added ext-libusb to overcome sysv_abi changes

* Fully remove libusb submodule
2025-07-21 12:24:11 +03:00
kalaposfos13
95a386308a
Implement sceKernelError (#3282)
* Implement sceKernelError

* Oh come on
2025-07-20 22:52:44 +03:00
Randomuser8219
0706223aaf
Small typo fix for avplayer assert (#3283)
Found that this assert message was typoed when running Knack 2 through a debugger.
2025-07-20 22:52:31 +03:00
Marcin Mikołajczyk
fd03fe2b5a
Register posix_rename (#3281) 2025-07-20 22:07:37 +03:00
kalaposfos13
f0cd981548
Implement sceAudioOutGetLastOutputTime (#3279)
* Implement sceAudioOutGetLastOutputTime

* Error returns

* Logging
2025-07-20 21:15:16 +03:00
Marcin Mikołajczyk
bd0102c8d0
Misc fixes (#3171) 2025-07-20 20:52:05 +03:00
TheTurtle
0b72a795eb
vk_rasterizer: Improve stencil clears (#3268) 2025-07-19 02:39:54 +03:00
TheTurtle
2ae7037c08
texture_cache: Clamp buffer image height to microtile height (#3261)
Co-authored-by: georgemoralis <giorgosmrls@gmail.com>
2025-07-18 13:14:41 +03:00
Valdis Bogdāns
af67473de3
Ime lib fixes (#3244)
* IME fixes

- Moved enums, flags, and structs to ime_common.h to simplify usage with Ime and ImeDialog
- Updated Ime to use an enum as the return type, consistent with ImeDialog
- Removed duplicate definition of OrbisImeKeycode
- Added OrbisImeLanguage as a flags enum
- Added missing options to OrbisImeOption
- Removed OrbisImeDialogOption; OrbisImeOption should be used instead
- Added OrbisImeTextAreaMode
- Updated OrbisImeTextAreaMode
- Fixed OrbisImeEventParam by adding the missing member OrbisImePanelType panel_type
- Updated the sceImeOpen declaration to use extended parameters (not yet implemented)
-Fixed Diablo III (CUSA00434) assertion failure on ImeDialog initialization

* Ime lib fixes
- Updated functions to consistently use the Error enum type for return values.
- Added detailed logging to aid future IME/OSK development and debugging.
- Now use OrbisUserServiceUserId (s32) and OrbisImeKeycodeState in relevant functions and structs.
- Introduced a generic template method to generate full bitmasks for all Orbis flag-style enums, simplifying validation and mask creation.
- Implemented additional parameter validations in sceImeOpen.
- Added missing enums: OrbisDisableDevice, OrbisImeInputMethodState, OrbisImeInitExtKeyboardMode, OrbisImeKeycodeState, and other USB keyboard-related enums.
- Fixed incorrect usage of format specifiers in calls to logging macros (LOG_*).

* Data Type Fixes

- Replaced the use of the type alias OrbisUserServiceUserId = s32 with Libraries::UserService::OrbisUserServiceUserId directly.

* Fixed IDE warnings
- generate_full_mask now returns const instead of constexpr.
- Added argument list to std::unique_lock<std::mutex> construction for clarity.

* Clang fixes

* Removed unneccessary comment

---------

Co-authored-by: w1naenator <valdis.bogdans@hotmail.com>
2025-07-18 12:40:05 +03:00
TheTurtle
b56039b15a
vk_pipeline_cache: Add fallbacks for R8Srgb and B5G6R5 (#3264)
* vk_pipeline_cache: Add fallbacks for R8Srgb and B5G6R5

* blit_helper: Fix validation error

* renderer_vulkan: Emulate B5G6R5 with swizzle
2025-07-18 12:25:07 +03:00
baggins183
3019bfb978
Implement MUBUF instructions for shorts/bytes (#2856)
* implement loads/store instructions for types smaller than dwords

* initialize s16/s8 types

* set profile for int8/16/64

* also need to zero extend u8/u16 to u32 result

* document unrelated bugs with atomic fmin/max

* remove profile checks and simple emit for added opcodes

---------

Co-authored-by: georgemoralis <giorgosmrls@gmail.com>
2025-07-18 12:04:50 +03:00
kalaposfos13
76f003d388
Disable autoupdate on branches that aren't the official main (#3262)
* Disable autoupdate on branches that aren't the official main

* Change to status messages because Fire Cube was complaining about this
2025-07-18 11:37:29 +03:00
UltraDaCat
fafd3fb564
Volume slider that adjusts how loud games are on a global level (#3240)
* Update config.cpp

* Update config.h

* Update sdl_audio.cpp

* Update settings_dialog.cpp

* Update settings_dialog.h

* Update settings_dialog.ui

* Update gui_settings.h

* Update audioout.cpp

* Update audioout.h

* Update settings_dialog.cpp

* remove leftover settings_dialog.ui

* Update settings_dialog.ui

---------

Co-authored-by: georgemoralis <giorgosmrls@gmail.com>
2025-07-18 11:20:05 +03:00
DanielSvoboda
e914099ae2
new compatibility repository (#3265) 2025-07-18 10:50:32 +03:00
georgemoralis
1689cdb1a2
Update Readme with new compatibility list link 2025-07-17 20:30:14 +03:00
kalaposfos13
fddded8d20
Add an unreachable on hitting ud2 instead of getting stuck in an infinite loop (#3257)
* Add an unreachable on hitting ud2 instead of getting stuck in an infinite loop

* Add [[unlikely]] to get ahead of the inevitable PR review comment
2025-07-16 18:06:58 +03:00
georgemoralis
161aa49f37
New Crowdin updates (#3219)
* New translations en_us.ts (Ukrainian)

* New translations en_us.ts (Ukrainian)

* New translations en_us.ts (Spanish)

* New translations en_us.ts (Albanian)

* New translations en_us.ts (Polish)

* New translations en_us.ts (Polish)

* New translations en_us.ts (Turkish)

* New translations en_us.ts (German)
2025-07-16 18:04:27 +03:00
kalaposfos13
68b147488e
If CONTENT_ID is empty in param.sfo, try using TITLE_ID as fallback (#3258)
* If CONTENT_ID is empty in param.sfo, try using TITLE_ID as fallback

* Remove assert that is now not needed and fix me switching up variable names
2025-07-16 18:03:39 +03:00
Stephen Miller
aeab525a7f
Fix create flag handling in open (#3255)
If the create flag is specified, but the file already exists, then the file should open successfully, regardless of permissions.
This fixes a crash seen in Phantasy Star Online 2 New Genesis (CUSA29813)
2025-07-16 12:30:20 +03:00
kalaposfos13
499451bb80
Standardize RegisterLib names for HLE libraries (#3234) 2025-07-16 12:23:03 +03:00
TheTurtle
cf8a6efd37
liverpool_to_vk: Don't use remapped format for clear value (#3254) 2025-07-16 01:54:56 +03:00
TheTurtle
6e350a5085
Avoid clearing HTILE when shader contains address calculation (#3252)
* resource_tracking: Mark image as written when its used with atomics

* texture_cache: Remove meta registered flag

Mostly useless and it is possible for images to switch metas

* vk_rasterizer: Use xor as heuristic for HTILE clear
2025-07-16 01:28:03 +03:00
DanielSvoboda
a82698d601
qt: fix gui emulatorLanguage (#3250) 2025-07-16 00:15:59 +03:00
TheTurtle
83475ac828
attribute: Correct bary coord function (#3253) 2025-07-15 22:55:57 +03:00
Marcin Mikołajczyk
6d6068e0e2
Fix ff1_i32_b64 not accepting vcc as its argument (#3251) 2025-07-15 11:39:37 -07:00
TheTurtle
4407ebdd9b
shader_recompiler: Implement guest barycentrics (#3245)
* shader_recompiler: Implement guest barycentrics

* Review comments and some cleanup
2025-07-15 18:49:12 +03:00
TheTurtle
87f6cce7b1
vk_instance: Remove usage of depth clamp control (#3248) 2025-07-15 18:36:13 +03:00
Stephen Miller
bf623d4f85
Libraries: Implement sceAudio3dTerminate (#3247)
* sceAudio3dTerminate

My First Gran Turismo® (CUSA49696) uses this while initializing it's audio system. Without it, the game spams errored sceAudio3dInitialize calls.

* Properly close AudioOut handle

Based on library decompilation.
2025-07-15 15:48:05 +03:00
Stephen Miller
97daee836a
Core: Fix read-only file unmaps on Windows (#3246)
* Fix read-only file unmaps

Fixes Genshin Impact (CUSA23681)

* Slight cleanup

Don't need `post_merge_it` anymore.
2025-07-15 14:11:56 +03:00
kalaposfos13
b68ca43166
Implement sceKernelGetSystemSwVersion (#3243)
* Implement sceKernelGetSystemSwVersion

* Set the reported firmware version to that of the game executable
2025-07-14 23:44:13 +03:00
TheTurtle
00f4eeddaf
renderer_vulkan: Handle more miscellaneous GPU settings (#3241)
* renderer_vulkan: Respect provoking vertex setting

* renderer_vulkan: Handle rasterization discard

* renderer_vulkan: Implement logic ops

* renderer_vulkan: Properly implement depth clamp and clip

* renderer_vulkan: Handle line width

* Fix build

* vk_pipeline_cache: Don't check depth clamp without a depth buffer

* liverpool: Fix line control offset

* vk_pipeline_cache: Don't run search if depth clamp is disabled

* vk_pipeline_cache: Allow using viewport range when it's more restrictive then depth clamp

* liverpool: Disable depth clip when near and far planes have different setting

* vk_graphics_pipeline: Move warning to pipeline

* vk_pipeline_cache: Revert viewport check and remove log

* vk_graphics_pipeline: Enable depth clamp when depth clip is disabled and extension is not supported

Without the depth clip extension depth clipping is controlled by depth clamping
2025-07-14 21:23:18 +03:00
TheTurtle
399a725343
shader_recompiler: Replace buffer pulling with attribute divisor for instance step rates (#3238)
* shader_recompiler: Replace buffer pulling with attribute divisor for instance step rates

* flatten_extended_userdata: Remove special step rate buffer handling

* Review comments

* spirv_emit_context: Name all instance rate attribs properly

* spirv: Merge ReadConstBuffer again

template function only has 1 user now

* attribute: Add missing attributes

* translate: Reimplement step rate instance id

* Resolve validation warnings

* shader_recompiler: Separate vertex inputs from LS stage, cleanup tess
2025-07-14 00:32:02 +03:00
TheTurtle
b403e1be33
vk_rasterizer: Set render area to max when no framebuffers are bound (#3227) 2025-07-10 22:14:02 +03:00
TheTurtle
8bc30270c8
shader_recompiler: Implement ff1 with subgroup ops (#3225) 2025-07-10 21:52:56 +03:00
TheTurtle
88abb93669
ir_passes: Fold readlane with ff1 pattern (#3224) 2025-07-10 14:19:44 +03:00
kalaposfos13
ee97c5c110
Define S_TRAP as InstCategory::FlowControl (#3223) 2025-07-10 13:53:38 +03:00
TheTurtle
27cbd6647f
shader_recompiler: Reorganize data share operations and implement GDS bit (#3222)
* shader_recompiler: Reorganize data share operations and implement GDS bit

* Review comments
2025-07-10 13:38:50 +03:00
IndecisiveTurtle
dc6ef99dc7 vector_memory: Handle immediate but non zero offset too
Signed-off-by: georgemoralis <giorgosmrls@gmail.com>
2025-07-09 18:40:05 +03:00
TheTurtle
7d4b875ee3
Random fixes (#3216)
* buffer_cache: Handle inline data to flexible memory

* control_flow: Fix single instruction scopes edge case

Fixes the following pattern

v_cmpx_gt_u32 cond
buffer_store_dword value
.LABEL:

Before
buffer[index] = value;

After
if (cond)
{
    buffer[index] = value;
}

* vector_memory: Handle soffset when offen is false

When offen is not used we can substitute the offset argument with soffset and have it handled correctly

* scalar_alu: Handle sharp moves with S_MOV_B64

This fixes unable to track sharp errors when this pattern is used in a shader

* emulator: Add log

* video_core: Bump binary info search range and buffer num
2025-07-09 17:00:06 +03:00
Paris Oplopoios
f5336358ea
Zero top bits in INSERTQ/EXTRQ (#3217)
* Zero top bits in INSERTQ/EXTRQ

* Clang-format

* Don't assert
2025-07-09 13:55:21 +03:00
Fire Cube
df4314f831
Extend Qt detection to support multiple drives (#3209) 2025-07-08 18:39:51 -07:00
kalaposfos13
e5f899aae3
Fix brace elision for designated initializer warning (#3215) 2025-07-08 18:38:28 -07:00
TheTurtle
2d1a2982df
buffer_cache: Bring back upload batching and temporary buffer (#3211)
* buffer_cache: Bring back upload batching and temporary buffer

Because that PR fused the write and read protections under a single function call, it was a requirement to move the actual memory copy part inside the lambda to perform it before the read protection kicks in. However on certain large data transfers it had potential for data corruption. If, for example, an upload had two copies, a 400MB and a 300MB one, the first one would fit in the staging buffer, very likely with an induced stall. However the second one wouldn't have space to fit alongside the other data, but it's also small enough for the buffer to fit it, so the staging buffer would cause a flush and wait to copy it, overwriting the previous transfer.

To address this the upload function has been reworked to allow for batching like previously but with the new locking behavior. Also the condition to use temporary buffers has been expanded to also include cases when staging buffer will stall, which should increase performance a little in some cases.

* buffer_cache: Move buffer barriers and copy outside of lock range
2025-07-08 10:32:39 +03:00
Valdis Bogdāns
ddede4a52d
IME fixes (#3207)
- Moved enums, flags, and structs to ime_common.h to simplify usage with Ime and ImeDialog
- Updated Ime to use an enum as the return type, consistent with ImeDialog
- Removed duplicate definition of OrbisImeKeycode
- Added OrbisImeLanguage as a flags enum
- Added missing options to OrbisImeOption
- Removed OrbisImeDialogOption; OrbisImeOption should be used instead
- Added OrbisImeTextAreaMode
- Updated OrbisImeTextAreaMode
- Fixed OrbisImeEventParam by adding the missing member OrbisImePanelType panel_type
- Updated the sceImeOpen declaration to use extended parameters (not yet implemented)
-Fixed Diablo III (CUSA00434) assertion failure on ImeDialog initialization

Co-authored-by: w1naenator <valdis.bogdans@hotmail.com>
2025-07-08 01:04:16 +03:00
Fire Cube
80f7ec2681
video_out: Internal Resolution Support (#3194)
* impl

* clang

* clang+

* update total_entries too
2025-07-07 19:17:56 +03:00
TheTurtle
7fedbd52e0
texture_cache: Async download of GPU modified linear images (#3204)
* texture_cache: Async download of GPU modified linear images

* liverpool: Back to less submits

* texture_cache: Don't download depth images

* config: Add option for linear image readback
2025-07-07 16:23:20 +03:00
georgemoralis
d6163a6edb uber fix 2025-07-07 13:37:08 +03:00
Paris Oplopoios
4eaa992aff
Rename 'AddCary' to 'AddCarry' (#3206) 2025-07-07 13:29:11 +03:00
squidbus
70eef0de90
texture_cache: Change depth resolve new image back to max of resources. (#3205) 2025-07-07 13:03:19 +03:00
Paris Oplopoios
146e81a56a
Fix V_ADDC_U32 carry-out edge cases (#3200)
* Fix V_ADDC_U32 carry-out edge cases

* Use IAddCarry instead
2025-07-07 12:44:06 +03:00
Marcin Mikołajczyk
5eef2fd28a
mmap executable memory (#3201) 2025-07-07 12:26:27 +03:00
Stephen Miller
d1f5a7e8fb
libkernel mprotect export (#3199) 2025-07-06 22:03:59 +02:00
kalaposfos13
78cb5334cf started 0.10.1 WIP 2025-07-06 20:54:56 +02:00
kalaposfos13
f56eecea44 tagged 0.10.0 2025-07-06 20:24:57 +02:00
georgemoralis
41b05ce7ed
New Crowdin updates (#3175)
* New translations en_us.ts (Catalan)

* New translations en_us.ts (Norwegian Bokmal)

* New translations en_us.ts (Italian)

* New translations en_us.ts (Russian)

* New translations en_us.ts (Swedish)

* New translations en_us.ts (Chinese Simplified)

* New translations en_us.ts (Norwegian Bokmal)

* New translations en_us.ts (Portuguese, Brazilian)

* New translations en_us.ts (Spanish)

* New translations en_us.ts (Albanian)

* New translations en_us.ts (Albanian)
2025-07-06 11:30:39 +03:00
Stephen Miller
a63db68114
Core: Update config files on startup (#3181)
* Organize settings and fix defaults

setDefaultValues was missing several rather important config options, and some of the defaults were inaccurate.

* Set alternative settings based on defaults

Reduces how many times we redefine the defaults for each setting.
I avoided changing behavior for installDirs and installDirsEnabled because I don't want to introduce any changes I can't easily test.

* Run save after loading to fill in missing config entries

A fix for the growing complaints about config files not updating when new settings are added.
Thanks to the prior changes, default settings are new properly defined everywhere, so running save here will properly fill in missing values with their expected defaults instead of the weird settings load would sometimes use.

* Clang

* Only update config when necessary

Instead of updating the config on each emulator boot, calculate the number of entries stored in the config and compare to a hardcoded constant.
If the config doesn't have the right number of entries, then regenerate it.

* Clang

* Clang
2025-07-06 11:30:10 +03:00
georgemoralis
4f99f304e6
Revert "Avoid clearing depth on partial HTILE writes (#3167)" (#3190)
This reverts commit 59dd73492b.
2025-07-04 09:57:01 +03:00
Stephen Miller
a050c9d65b
Only use TRACK_ALLOC for non-reserved mappings (#3188) 2025-07-04 01:01:07 +03:00
TheTurtle
b22da77f9a
buffer_cache: Fix various thread races on data upload and invalidation (#3186)
* buffer_cache: Fix various thread races on data upload and invalidation

* memory_tracker: Improve locking more on invalidation

---------

Co-authored-by: georgemoralis <giorgosmrls@gmail.com>
2025-07-03 22:36:01 +02:00
TheTurtle
df22c4225e
config: Add toggle for DMA (#3185)
* config: Add toggle for DMA

* config: Log new config
2025-07-03 20:03:06 +03:00
TheTurtle
48460d1cbe
vector_alu: Improve handling of mbcnt append/consume patterns (#3184)
* vector_alu: Improve handling of mbcnt append/consume patterns

The existing implementation was written to handle a single pattern of mbcnt before the DS_APPEND instruction

v_mbcnt_hi_u32_b32 vX, exec_hi, 0
v_mbcnt_lo_u32_b32 vX, exec_lo, vX
ds_append       vY offset:4 gds
v_add_i32       vX, vcc, vY, vX

In this case however the DS_APPEND is before the mbcnt pattern

ds_append       vX gds
v_mbcnt_hi_u32_b32 vY, exec_hi, vX
v_mbcnt_lo_u32_b32 vZ, exec_lo, vY

The mbcnt instructions are always in pairs of hi/lo and in general are quite flexible. But they assume the subgroup size is 64 so they are not recompiled literally. Together with DS_APPEND they are used to derive a unique per thread index in a buffer (different from using thread_id as order could be random). DS_APPEND instruction works on per subgroup level, by adding number of active threads of subgroup to the GDS counter, essentially giving a multiple-of-64 base index to all threads. Then each thread executes the mbcnt pair which returns the number of active threads with id less than the itself and adds it with the base.

The recompiler translates DS_APPEND into an atomic increment of a storage buffer counter, which already gives the desired unique index, so this pattern is a no-op. On main it was set to zero as per the first pattern to avoid altering the DS_APPEND result. The new handling passes through the initial value of the pattern instead, which has the same effect but works on either case.

* vk_rasterizer: Always sync DMA buffers
2025-07-03 13:19:38 +03:00
Marcin Mikołajczyk
7431b30005
Support for BUFFER_ATOMIC_S/UMIN_X2 (#3182)
* Fix BufferAtomicS/UMax64 SPIR-V emitting

* Support for BUFFER_ATOMIC_S/UMIN_X2
2025-07-02 18:13:07 -07:00
nickci2002
9eae6b57ce
V_CMP_EQ_U64 support (#3153)
* Added V_CMP_EQ_U64 shader opcode support and added 64-bit relational operators (<,>,<=,>=)

* Fixed clang-format crying because I typed xargs clang-format instead of xargs clang-format-19

* Replaced V_CMP_EQ_U64 code to match V_CMP_U32 to test

* Updated V_CMP_U64 for future addons
2025-07-02 19:22:30 +03:00
Lander Gallastegi
efa7093f34
Use shared_first_mutex (#3179) 2025-07-02 16:54:14 +03:00
TheTurtle
0594dac405
Readbacks proof of concept rebased (#3178)
* Readbacks proof of concept

* liverpool: Use span for acb too

* config: Add readbacks config option

* config: Log readbacks
2025-07-01 23:41:00 +03:00
kalaposfos13
5789fd881c Remove accidentally left in debug logging from touchpad input emulation 2025-06-30 21:53:45 +02:00
Marcin Mikołajczyk
1757dfaf5a
buffer_atomic_imax_x2 (#3130)
* buffer_atomic_imax_x2

* Define Int64Atomics SPIR-V capability
2025-06-29 16:16:47 -07:00
Lander Gallastegi
77117abb31
Specify compiler on linux preset (#3177) 2025-06-29 23:35:59 +02:00
Fire Cube
64dfccdf26
restore presets before ositr commit (#3176) 2025-06-29 23:38:54 +03:00
Fire Cube
6bf3c44b9c
Fix CMake presets for Linux (#3173)
* Add platform specific base presets

* Revert "Add platform specific base presets"

This reverts commit a949a9f395.

* better

* cleanup

* update REUSE
2025-06-29 22:14:52 +02:00
Missake212
434dcde9f3
Update template hyperlink (#3174) 2025-06-29 21:17:44 +03:00
Osyotr
bdd2419de9
[cmake] Show Windows presets only on Windows (#3172)
Also did a small cleanup to remove duplicated cache variables.
2025-06-29 20:38:06 +03:00
georgemoralis
7f727340aa
New Crowdin updates (#3165)
* New translations en_us.ts (Turkish)

* New translations en_us.ts (Portuguese, Brazilian)

* New translations en_us.ts (Arabic)

* New translations en_us.ts (Persian)

* New translations en_us.ts (Catalan)

* New translations en_us.ts (Serbian (Latin))

* New translations en_us.ts (Swedish)

* New translations en_us.ts (Romanian)

* New translations en_us.ts (French)

* New translations en_us.ts (Spanish)

* New translations en_us.ts (Danish)

* New translations en_us.ts (German)

* New translations en_us.ts (Greek)

* New translations en_us.ts (Finnish)

* New translations en_us.ts (Hungarian)

* New translations en_us.ts (Italian)

* New translations en_us.ts (Japanese)

* New translations en_us.ts (Korean)

* New translations en_us.ts (Lithuanian)

* New translations en_us.ts (Dutch)

* New translations en_us.ts (Polish)

* New translations en_us.ts (Portuguese)

* New translations en_us.ts (Russian)

* New translations en_us.ts (Slovenian)

* New translations en_us.ts (Albanian)

* New translations en_us.ts (Ukrainian)

* New translations en_us.ts (Chinese Simplified)

* New translations en_us.ts (Chinese Traditional)

* New translations en_us.ts (Vietnamese)

* New translations en_us.ts (Indonesian)

* New translations en_us.ts (Norwegian Bokmal)

* New translations en_us.ts (Russian)

* New translations en_us.ts (Dutch)

* New translations en_us.ts (Turkish)

* New translations en_us.ts (Turkish)

* New translations en_us.ts (Portuguese, Brazilian)
2025-06-29 11:48:44 +03:00
TheTurtle
59dd73492b
Avoid clearing depth on partial HTILE writes (#3167)
* vk_rasterizer: Avoid full depth clear in case of partial HTILE update

* resource_tracking: Mark image as written when its used with atomics
2025-06-29 00:53:14 +03:00
georgemoralis
83056712e0
[ci skip] Qt GUI: Update Translation. (#3164)
Co-authored-by: georgemoralis <4313123+georgemoralis@users.noreply.github.com>
2025-06-28 09:39:59 +03:00
rainmakerv2
fa32537f40
Controller Remapping GUI v2 (#3144)
* Remapping GUI V2 - initial commit

* Unmap button with escape key

* Allow combination inputs

* Use separate class for SDL event signals so that i can work with the SDL window event loop

* Automatically pause game when GUI open to better manage event queue

* Move sd;_gamepad_added event from remap object to GUI object to avoid conflicts with sdl window

* Use signals on button/trigger to release to make GUI more responsive

* pause game while KBM window is open for consistency

* don't check gamepad when game is running to avoid conflicts

* Block all other sdl events instead of pausing game, automatic parse inputs after saving

* Don't block window restored or window exposed cases

* Properly exit event loop thread on exit
2025-06-27 15:55:52 +02:00
rainmakerv2
09b584b23f
Kbm GUI - minor fixes (#3146)
* KBM Gui fixes

* remove unneeded activate window calls
2025-06-27 16:49:31 +03:00
nickci2002
4bfd8b967b
Changed symbol bindings to their names (#3158)
* Changed symbol bindings to their names

* Fixed kakposfos' requests on GitHub

* Fine, I'll do it myself.

---------

Co-authored-by: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com>
2025-06-27 12:55:12 +02:00
georgemoralis
52bd92b97d
New Crowdin updates (#3152)
* New translations en_us.ts (Turkish)

* New translations en_us.ts (Portuguese, Brazilian)

* New translations en_us.ts (Arabic)

* New translations en_us.ts (Persian)

* New translations en_us.ts (Catalan)

* New translations en_us.ts (Serbian (Latin))

* New translations en_us.ts (Swedish)

* New translations en_us.ts (Romanian)

* New translations en_us.ts (French)

* New translations en_us.ts (Spanish)

* New translations en_us.ts (Danish)

* New translations en_us.ts (German)

* New translations en_us.ts (Greek)

* New translations en_us.ts (Finnish)

* New translations en_us.ts (Hungarian)

* New translations en_us.ts (Italian)

* New translations en_us.ts (Japanese)

* New translations en_us.ts (Korean)

* New translations en_us.ts (Lithuanian)

* New translations en_us.ts (Dutch)

* New translations en_us.ts (Polish)

* New translations en_us.ts (Portuguese)

* New translations en_us.ts (Russian)

* New translations en_us.ts (Slovenian)

* New translations en_us.ts (Albanian)

* New translations en_us.ts (Ukrainian)

* New translations en_us.ts (Chinese Simplified)

* New translations en_us.ts (Chinese Traditional)

* New translations en_us.ts (Vietnamese)

* New translations en_us.ts (Indonesian)

* New translations en_us.ts (Norwegian Bokmal)

* New translations en_us.ts (Vietnamese)

* New translations en_us.ts (Norwegian Bokmal)

* New translations en_us.ts (Swedish)

* New translations en_us.ts (Catalan)

* New translations en_us.ts (Russian)

* New translations en_us.ts (Albanian)

* New translations en_us.ts (Chinese Simplified)

* New translations en_us.ts (Norwegian Bokmal)

* New translations en_us.ts (Turkish)

* New translations en_us.ts (Turkish)

* New translations en_us.ts (Portuguese, Brazilian)
2025-06-27 09:36:47 +03:00
TheTurtle
8e44a7099f
bit_array: Remove non const operator~ (#3161) 2025-06-26 18:07:56 -07:00
Stephen Miller
0a58ead5f6
Add alternate code paths for handling legacy struct behavior in sceVideodec2GetPictureInfo (#3154)
Older games aren't fond of how our sceVideodec2GetPictureInfo implementation outputs AVC picture info after the struct size increase.
Adding the old struct, and additional code using it for these games works around this problem.
2025-06-26 20:16:23 +03:00
Lander Gallastegi
9f37ede336
video_core: Page manager and memory tracker improvenets (#3155)
* I don't know what to put here

* clang-format

* clang-format 2.0

* Deadlock free locking

* Por boost range lock implementation

* clang-format
2025-06-26 18:38:53 +02:00
TheTurtle
a49b13fe66
shader_recompiler: Optimize general case of buffer addressing (#3159)
* shader_recompiler: Simplify dma types

Only U32 is needed for S_LOAD_DWORD

* shader_recompiler: Perform address shift on IR level

Buffer instructions now expect address in the data unit they work on. Doing the shift on IR level will allow us to optimize some operations away on common case

* shader_recompiler: Optimize common buffer access pattern

* emit_spirv: Use 32-bit integer ops for fault buffer

Not many GPUs have 8-bit bitwise or operations so that would probably require some overhead to emulate from the driver

* resource_tracking_pass: Fix texel buffer shift
2025-06-26 12:14:36 +03:00
Fire Cube
6eaec7a004
Add CMake Presets for Qt build and add auto-detection for Qt in Windows (#3141)
* add CMakePresets.json

* Update REUSE.toml

* fix vs

* impl

* adjust CMakeSettings.json

* add FindQt.cmake to reuse

* rename cmake file, add check before running cmake and add inheritation to presets

* add error check in cmake

* cleanup

* degrade not detected message and search only for x64 Qt
2025-06-25 17:02:02 +03:00
georgemoralis
075d6425e2
[ci skip] Qt GUI: Update Translation. (#3151)
Co-authored-by: georgemoralis <4313123+georgemoralis@users.noreply.github.com>
2025-06-23 12:44:26 +03:00
georgemoralis
70e4f81655
New Crowdin updates (#3140)
* New translations en_us.ts (Swedish)

* New translations en_us.ts (Chinese Simplified)

* New translations en_us.ts (Japanese)

* New translations en_us.ts (Norwegian Bokmal)

* New translations en_us.ts (Vietnamese)
2025-06-23 12:44:05 +03:00
Stephen Miller
12198f9255
libkernel: Check returned module in sceKernelGetModuleInfoFromAddr (#3147)
* Error if the module doesn't exist

Fixes another thing kalaposfos found

* Fix error returns

Based on 11.00 libkernel decomp.
2025-06-23 01:32:43 -07:00
davidantunes23
4bfa8c9fc7
Favorites in the game list (#2649) (#3071)
* Favorites in the game list (#2649)

Changed how favorites are saved to match PR #2984. Adjusted the favorite
icon size. Fixed bug where favorites were inconsistent when changing to
list mode. Instantly sort list when adding or removing a favorite.

Co-authored-by: David Antunes <david.f.antunes@tecnico.ulisboa.pt>

* fix formatting

* Favorites in the game list (#2649)

Fixed issue where background change was inconsistent while adding
favorites, unselect row when adding favorites, cleaned code, changed
right click menu options to match the game's favorite status.

* fixed right click bug

* keep row selection when adding favorites

* fixed sorting on game grid after using search bar

* change the way favorites are saved to match #3119
2025-06-22 12:53:47 +03:00
squidbus
669b19c2f3
shader_recompiler: Fix handling unbound depth image. (#3143)
* shader_recompiler: Fix handling unbound depth image.

* shader_recompiler: Consolidate unbound image handling.
2025-06-21 22:18:00 -07:00
Stephen Miller
d9dac05db2
Core: MapMemory fixes (#3142)
* Validate requested dmem range in MapMemory

Handles a rare edge case that only comes up when modding Driveclub

* Specify type

auto has failed us once again.

* Types cleanup

Just some basic tidying up.

* Clang
2025-06-21 19:22:03 -07:00
georgemoralis
802124309d
New Crowdin updates (#3134)
* New translations en_us.ts (Turkish)

* New translations en_us.ts (Portuguese, Brazilian)

* New translations en_us.ts (Arabic)

* New translations en_us.ts (Persian)

* New translations en_us.ts (Catalan)

* New translations en_us.ts (Serbian (Latin))

* New translations en_us.ts (Swedish)

* New translations en_us.ts (Romanian)

* New translations en_us.ts (French)

* New translations en_us.ts (Spanish)

* New translations en_us.ts (Danish)

* New translations en_us.ts (German)

* New translations en_us.ts (Greek)

* New translations en_us.ts (Finnish)

* New translations en_us.ts (Hungarian)

* New translations en_us.ts (Italian)

* New translations en_us.ts (Japanese)

* New translations en_us.ts (Korean)

* New translations en_us.ts (Lithuanian)

* New translations en_us.ts (Dutch)

* New translations en_us.ts (Polish)

* New translations en_us.ts (Portuguese)

* New translations en_us.ts (Russian)

* New translations en_us.ts (Slovenian)

* New translations en_us.ts (Albanian)

* New translations en_us.ts (Ukrainian)

* New translations en_us.ts (Chinese Simplified)

* New translations en_us.ts (Chinese Traditional)

* New translations en_us.ts (Vietnamese)

* New translations en_us.ts (Indonesian)

* New translations en_us.ts (Norwegian Bokmal)

* New translations en_us.ts (Catalan)

* New translations en_us.ts (Portuguese, Brazilian)

* New translations en_us.ts (Russian)
2025-06-21 20:31:26 +03:00
Daniel Öster
5b5096e9ea
Update note on recursive cloning (#3136) 2025-06-21 20:31:12 +03:00
kalaposfos13
54163ffaa5
Initialize system handle in HLE Ngs2 library (#3137) 2025-06-21 20:30:49 +03:00
kalaposfos13
2d335f436c
Stub out SetGPO and GetGPI (#3135) 2025-06-21 05:23:14 -07:00
georgemoralis
1fc95bf44b
[ci skip] Qt GUI: Update Translation. (#3133)
Co-authored-by: georgemoralis <4313123+georgemoralis@users.noreply.github.com>
2025-06-21 10:04:57 +03:00
georgemoralis
0bb1ee167f
New Crowdin updates (#3128)
* New translations en_us.ts (Albanian)

* New translations en_us.ts (Italian)
2025-06-21 10:04:23 +03:00
Fire Cube
a62027d4c2
fix potential out of bound crash (#3132) 2025-06-21 10:03:10 +03:00
nickci2002
8dcd9cc0f9
KBM Input Bug Fixes / Added Binds v2 (#3109)
* fixed nonload issues with background music (#3094)

* Fixing my pull request branch

* Pull request change part 2

* Continued changes to project and altered kbm_help_dialog.h text to QStringLiterals

* Finalized commit and changed kbm_help_dialog.h

* KBM Input Bug Fixes / Added Binds

Fixed input issues where some inputs would not bind when pressing (side mouse buttons, some symbols, etc). Also, fixed up code formatting in altered files (removed C-style casts and replaced with C++ <static_casts>, added a few macros and one member functions).
This is v2 of my commit, addressing all issues brought up by @kalaposfos

* Updated C-style casts in kbm_gui.cpp

* Fixed formatting from clang-format

* Updated expendable sections location and changed order of appearance

* Merged PR #3098 into kbm_gui.cpp

* Updates from running clang-format

* Potential MacOS error fix

Changes std::string to std::string_view, which prevented MacOS from building

* Undid MacOS commit for new PR

* Revert "Undid MacOS commit for new PR"

This reverts commit fc376c5e1f.

* Updated SDL_INVALID_ID=UINT32_MAX macro to SDL_UNMAPPED=UINT32_MAX-1

* Update from merge conflicts

Updated SDL_INVALID_ID=UINT32_MAX macro to SDL_UNMAPPED=UINT32_MAX-1

* FIxed memory.cpp errors from testing PR  #3117 (MacOS fixes)

* Removed "kp;"

* Fixed help dialogue from kalaposfos' changes

Fixed 3 edits made by kalaposfos from a recent commit.

---------

Co-authored-by: georgemoralis <giorgosmrls@gmail.com>
2025-06-20 20:33:27 +02:00
rainmakerv2
7b0249d9ca
Update gui with new touchpad inputs (#3125)
* Update gui with new touchpad inputs

* Update kbm_gui.ui

---------

Co-authored-by: rainmakerv2 <josefkarloprado@gmail.com>
2025-06-20 16:19:33 +03:00
kalaposfos13
551751df3c
Emulate motion controls with a mouse (#3122)
* Rework framework to allow for more types of mouse-to-something emulation and hook up gyro to it

* Remove the unnecessary null check now that deltatime is handled differently

* Fix toggle key

* Basic gyro emulation working for two out of the three dimensions

* clang

* Added bindable key to hold for switching from looking to the sides to rolling

* documentation
2025-06-20 13:55:41 +03:00
Lander Gallastegi
be12305f65
video_core: Page manager/region manager optimization (#3070)
* Bit array test

* Some corrections

* Fix AVX path on SetRange

* Finish bitArray

* Batched protect progress

* Inclusion fix

* Last logic fixes for BitArray

* Page manager: batch protect, masked ranges

* Page manager bitarray

* clang-format

* Fix out of bounds read

* clang

* clang

* Lock during callbacks

* Rename untracked to writeable

* Construct and mask in one step

* Sync on region mutex for thw whole protection

This is a temporary workarround until a fix is found for the page manager having issues when multiple threads update the same page at the same time.

* Bring back the gpu masking until properly handled

* Sync page manager protections

* clang-format

* Rename and fixups

* I fucked up clang-formatting one more time...

* kek
2025-06-20 13:00:23 +03:00
kalaposfos13
e214ca6884
Replace Back Button Behaviour with a rebindable solution (#3114) 2025-06-20 12:51:55 +03:00
georgemoralis
43321fb45a
QT save fixes II (#3119)
* added recentFiles save/load

* gui language

* fixups for language

* fixed language issue with savedata (it was saving based on gui language and not on console language)

* clang fix

* elf dirs added

* added theme
2025-06-20 12:28:32 +03:00
Marcin Mikołajczyk
423254692a
Implement buffer atomic fmin/fmax instructions (#3123) 2025-06-19 17:37:29 -07:00
Marcin Mikołajczyk
612f340292
Log improper image format uses (#3105) 2025-06-19 14:36:50 -07:00
kalaposfos13
6d65ea7314
Silence unmapped keybind mappings and add XBox paddles (#3121) 2025-06-19 21:35:28 +03:00
georgemoralis
e389d03601
Revert "add CMakePresets.json (#3116)" (#3120)
This reverts commit 33f46202d2.
2025-06-19 19:41:50 +03:00
Fire Cube
33f46202d2
add CMakePresets.json (#3116)
* add CMakePresets.json

* Update REUSE.toml
2025-06-19 13:17:50 +03:00
georgemoralis
8e06b1b2b0
New Crowdin updates (#3104)
* New translations en_us.ts (Catalan)

* New translations en_us.ts (Chinese Simplified)

* New translations en_us.ts (Swedish)

* New translations en_us.ts (Russian)

* New translations en_us.ts (Russian)

* New translations en_us.ts (Norwegian Bokmal)

* New translations en_us.ts (Norwegian Bokmal)

* New translations en_us.ts (Portuguese, Brazilian)
2025-06-19 13:17:29 +03:00
squidbus
1437c5a1de
ci: Work around Qt issue on new Xcode. (#3118) 2025-06-18 14:54:04 -07:00
nickci2002
20670186ab
Potential MacOS Build Fix (#3117)
* Potential MacOS build fix for update

* Imported string instead of changing name to std::string_view
2025-06-18 19:04:00 +02:00
squidbus
5bc4cc761a
shader_recompiler: Fix some shared memory accesses when workgroup struct is omitted. (#3110) 2025-06-17 00:28:44 -07:00
Marcin Mikołajczyk
efa8f6a154
Handle immediate inline samplers (#3015)
* Handle immediate inline sampler

* Simplify inline sampler handling
2025-06-16 23:42:14 -07:00
Marcin Mikołajczyk
9dd35c3a42
Fix shared memory definition when only one type is used (#3106) 2025-06-16 23:37:09 -07:00
Marcin Mikołajczyk
21d14abaee
Enable sampleRateShading (#3107) 2025-06-16 23:24:38 +03:00
TheTurtle
c27f45c8c0
texture_cache: Implement color to multisampled depth blit pass (#3103) 2025-06-16 14:39:46 +03:00
georgemoralis
d0e2a40cdc
New Crowdin updates (#3089)
* New translations en_us.ts (Catalan)

* New translations en_us.ts (Catalan)

* New translations en_us.ts (Catalan)

* New translations en_us.ts (Swedish)

* New translations en_us.ts (Turkish)

* New translations en_us.ts (Portuguese, Brazilian)

* New translations en_us.ts (Arabic)

* New translations en_us.ts (Persian)

* New translations en_us.ts (Catalan)

* New translations en_us.ts (Serbian (Latin))

* New translations en_us.ts (Swedish)

* New translations en_us.ts (Romanian)

* New translations en_us.ts (French)

* New translations en_us.ts (Spanish)

* New translations en_us.ts (Danish)

* New translations en_us.ts (German)

* New translations en_us.ts (Greek)

* New translations en_us.ts (Finnish)

* New translations en_us.ts (Hungarian)

* New translations en_us.ts (Italian)

* New translations en_us.ts (Japanese)

* New translations en_us.ts (Korean)

* New translations en_us.ts (Lithuanian)

* New translations en_us.ts (Dutch)

* New translations en_us.ts (Polish)

* New translations en_us.ts (Portuguese)

* New translations en_us.ts (Russian)

* New translations en_us.ts (Slovenian)

* New translations en_us.ts (Albanian)

* New translations en_us.ts (Ukrainian)

* New translations en_us.ts (Chinese Simplified)

* New translations en_us.ts (Chinese Traditional)

* New translations en_us.ts (Vietnamese)

* New translations en_us.ts (Indonesian)

* New translations en_us.ts (Norwegian Bokmal)
2025-06-16 13:07:09 +03:00
georgemoralis
e2b8ceb6ba
[ci skip] Qt GUI: Update Translation. (#3100)
Co-authored-by: georgemoralis <4313123+georgemoralis@users.noreply.github.com>
2025-06-16 12:34:58 +03:00
Stephen Miller
213ca72fa1
Filesystem: Fixes for posix_rename and write (#3099)
* Fix rename

We shouldn't be leaving a copy of the original filename laying around.
This fixes one of a few broken savedata checks in DRAGON BALL XENOVERSE (CUSA01341)

* sceKernelWrite hack

Seems like std::fwrite has some weird edge cases we aren't handling properly.
Until we get to the bottom of this issue, here's a hack that bypasses it.
This fixes saves in DRAGON BALL XENOVERSE (CUSA01341)

* hack fix

* Improved "hack"

* Fix rename for Windows users

Turns out, we're using copy instead of rename for a reason, and that same reason came up when adding the remove call.
Also adds a log for the sceKernelWrite issue, since that's definitely a hack that needs to be debugged.

* A real fix for the sceKernelWrite issue

Turns out, some data was just buffered.
Running Flush fixes that problem.

* Move fflush call to WriteRaw

To prevent future cases of this issue.
2025-06-15 22:43:39 +03:00
Fire Cube
de69f2b40b
Equeue: HrTimer fixes (#2987)
* initial changes

* tmp

* impl

* support wait for multiple timers

* cleanup
2025-06-15 19:03:57 +03:00
rainmakerv2
3f40a8d46e
Qt: If duplicate unique inputs found, show which buttons have duplicates (#3098)
* If duplicate unique inputs found, show which buttons have duplicates

* remove duplicate button from list

* cleanup

* Set clang-format off for long translatable string
2025-06-15 18:06:30 +03:00
georgemoralis
226058d2e9
fixed nonload issues with background music (#3094) 2025-06-12 20:29:39 +03:00
UltraDaCat
ae6f7b8d5a
remove the accidental backslash in README.md (#3093) 2025-06-12 19:20:39 +02:00
georgemoralis
1a27af6951
fixed non updated values (#3092) 2025-06-12 19:06:54 +03:00
georgemoralis
c35141b33f
New Crowdin updates (#3085)
* New translations en_us.ts (Persian)

* New translations en_us.ts (Catalan)

* New translations en_us.ts (Persian)

* New translations en_us.ts (Persian)

* New translations en_us.ts (Persian)

* New translations en_us.ts (Catalan)

* New translations en_us.ts (Catalan)

* New translations en_us.ts (Serbian (Latin))
2025-06-12 13:28:14 +03:00
georgemoralis
a1d6cd15f4
qt: save gui settings to separate file (#2984)
* initial save classes for gui save file

* fixup

* some more settings passed to the new saving file

* even more variables parsing

* more settings

* fixup

* more settings

* more settings

* clang fix

* fixed wrong setting

* more setting

* more setting

* added ca_ES

* rename to general_settings

* added set-addon-folder in main

* fixup

* fixup2

* added sr_CS

* Update CMakeLists.txt

---------

Co-authored-by: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com>
2025-06-12 13:27:52 +03:00
TheTurtle
34d0d85c15
buffer_cache: Bump device local staging buffer size (#3088) 2025-06-12 13:05:25 +03:00
squidbus
c71dc740e2
shader_recompiler: Reduce cases where shared memory to buffer pass is needed. (#3082) 2025-06-11 13:24:41 -07:00
Stephen Miller
69a50fa713
Struct update fixes (#3087)
Neither sceVideodec2Decode or sceVideodec2Flush should be modifying the output's `thisSize`, doing so breaks older games now that we have the updated structs.
We should also only set frameFormat and framePitchInBytes if the game inputted the newer struct, since otherwise we're modifying memory the game never gave us.
These changes might fix the regression in Hatsune Miku Project Diva X, though it's hard to tell due to some weird caching issue with Windows, and the ancient regression this game had on Linux.
2025-06-11 22:22:34 +03:00
Missake212
34a1ffbcda
Few changes to the README.md (#3086)
* Update README.md

* backslash
2025-06-11 22:21:55 +03:00
Stephen Miller
3e0ec9ebef
Core: Merge Direct Memory Areas (#3084)
* Merge dmem areas

* Fix DirectMemoryArea::CanMergeWith

Don't merge dmem areas if the memory types are different.

* Reduce some warnings to info

Both functions should behave properly now, there's no reason to warn about their use.

* Clang
2025-06-11 17:34:00 +03:00
georgemoralis
2741829545
New translations en_us.ts (Arabic) (#3081) 2025-06-11 12:02:59 +03:00
TheTurtle
dedf6de2ac
texture_cache: Implement color<->depth copies (#3079)
* texture_cache: Implement color to depth copies and vise versa

* ir_passes: Adjust shared memory barrier pass to cover more cases

* texture_cache: Remove unused code

* review comment
2025-06-11 01:34:37 -07:00
Stephen Miller
fc4fd0107d
libSceNpTrophy: Change initial context and handle values (#3080)
* Change default context and handle values

libSceNpToolkit internally uses context/handle values of zero to indicate NpTrophy calls failed.
This PR returns handle/context as index + 1 instead, avoiding this issue.

* Fix log message
2025-06-10 15:43:11 -07:00
squidbus
ca92e72efe
shader_recompiler: Various fixes to shared memory and atomics. (#3075)
* shader_recompiler: Various fixes to shared memory and atomics.

* shader_recompiler: Re-type non-32bit load/stores.
2025-06-10 15:41:58 -07:00
Stephen Miller
b49340dff8
libSceVideodec2: Update structs to match newer firmwares (#3077)
* Update file_system.cpp

* libSceVideodec2 struct fixes

Our code was based on an old version of the libSceVideodec2 library. Based on what I've decompiled, these structs changed somewhere around firmware 6.50, and newer versions of the library have these flexible checks to accommodate both variants of the structs.

* Static assert for AvcPictureInfo struct

All the other Videodec2 structs have static asserts, might as well use one here too.

* Initialize new values

Set proper values for frameFormat and framePitchInBytes.
`frame->linesize[0]` appears to be in bytes already, I'm not sure if that means framePitch is being set wrong though.
2025-06-10 13:22:50 -07:00
Fire Cube
9981c8df03
Add option to ignore game patch (#3039)
* impl

* fix

* cleanup

* more

* clang +

* why
2025-06-10 12:30:45 -07:00
TheTurtle
e0c930f2d8
shader_recompiler: Cleanup fragment attribute handling (#3076)
* image: Take minimum of mip levels

Avoids validation error

* texture_cache: Update depth target image

Avoids using undefined depth target in rendering

* shader_recompiler: Cleanup fragment attribute handling
2025-06-10 18:57:16 +03:00
squidbus
e2b726382e
vulkan: Fix two validation errors introduced by shared memory changes. (#3074) 2025-06-09 19:48:20 -07:00
squidbus
0444e590e0
mac: Fix building on macOS 26. (#3073) 2025-06-09 19:29:15 -07:00
Connor Garey
64bbedeb82
changed package name to openal-soft-devel reflecting the fedora name package change (#3069) 2025-06-09 15:25:57 -07:00
Marcin Mikołajczyk
217d32b502
Handle DS_READ_U16, DS_WRITE_B16, DS_ADD_U64 (#3007)
* Handle DS_READ_U16 & DS_WRITE_B16

* Refactor DS translation

* Translate DS_ADD_U64

* format

* Fix RingAccessElimination after changing WriteShared64 type

* Simplify bounds checking in generated SPIR-V
2025-06-09 22:03:38 +03:00
Lander Gallastegi
a71bfb30a2
shader_recompiler: Patch SRT walker on segfault (#2991)
* Patch srt walker access violations

* Fix range

* clang-format lolz

* Lower log from warning to debug
2025-06-09 13:04:21 +03:00
mailwl
046cf50412
PM4 type 2 in acb (#3047)
* Stub PM4 type 0

* fix command size

* revert command size to actual

* return unreachable for PM4t0

* remove skipping command body
2025-06-09 01:27:37 -07:00
TheTurtle
d7051f15f4
texture_cache: Basic handling of partially resident images (#3066)
* texture_cache: Avoid gpu tracking assert on sparse image

At the moment just take the easy way of creating the entire image normally and uploading unmapped subresources are zero

* tile_manager: Downgrade assert to error

* fix macos
2025-06-09 01:26:10 -07:00
TheTurtle
12f4a8f073
tile_manager: Downgrade assert to error (#3067) 2025-06-09 09:35:43 +03:00
TheTurtle
c20d02dd40
shader_recompiler: Better handling of geometry shader scenario G (#3064) 2025-06-08 17:31:51 -07:00
squidbus
ae2053c487 fix: Disable eBlockTexelViewCompatible on MoltenVK 2025-06-08 15:41:58 -07:00
TheTurtle
14b082f5ea
buffer_cache: Inline data to cpu unless gpu modified (#3061) 2025-06-08 15:28:00 -07:00
TheTurtle
ce42eccc9d
texture_cache: Handle compressed views of uncompressed images (#3056)
* pixel_format: Remove unused tables, refactor

* host_compatibilty: Cleanup and support uncompressed views of compressed formats

* texture_cache: Handle compressed views of uncompressed images

* tile_manager: Bump max supported mips to 16

Fixes a crash during start

* oops

* texture_cache: Fix order of format compat check
2025-06-08 23:09:08 +03:00
TheTurtle
8ffcfc87bd
shader_recompiler: Implement linear interpolation support (#3055) 2025-06-08 22:46:34 +03:00
Paris Oplopoios
5004e41100
Patch movntss and movntsd (#3049)
* Patch movntss and movntsd

* clang-format

* Deduplication

* Allow rep to be in other places
2025-06-08 22:29:33 +03:00
TheTurtle
a07a6bb9d3
buffer_cache: Better image search for buffer validation (#3057) 2025-06-08 22:14:09 +03:00
squidbus
f2bbb6847d fix: Missing switch case for BUFFER_ATOMIC_CMPSWAP 2025-06-08 11:53:11 -07:00
Marcin Mikołajczyk
ce84e80f65
BUFFER_ATOMIC_CMPSWAP (#3045) 2025-06-08 11:43:58 -07:00
TheTurtle
952cef5a15
shader_recompiler: Implement dual source blending (#3054) 2025-06-08 21:38:58 +03:00
Mahmoud Adel
2bc199a41b
black image error fix (#3051) 2025-06-08 11:33:08 -07:00
Fire Cube
5d064dd89f
Dev Tools: Fix Module Viewer HLE detection (#3058)
* fix

* clang
2025-06-08 21:04:55 +03:00
Stephen Miller
2857ef34f0
Don't coalesce dmem pages (#3059)
Looks like this change is what broke P.T.
I'll need to look closer at this when I have a chance, clearly we're doing something wrong here.
2025-06-08 21:04:43 +03:00
Stephen Miller
5edd9ff54b
Improved sceKernelMapNamedFlexibleMemory logging (#3050)
* More descriptive sceKernelMapNamedFlexibleMemory logging

* Misc exports

These functions are used by Overwatch: Origins Edition

* Clang

* Function parameter cleanup

Changes the parameters on our sceKernelMapNamedFlexibleMemory and sceKernelMapFlexibleMemory functions to better align with our current standards.
2025-06-08 00:17:45 +03:00
Marcin Mikołajczyk
91d29459fb
Implement PM4CondExec (#3046) 2025-06-05 20:19:05 -07:00
Marcin Mikołajczyk
fff3bf9917
s_flbit_i32_b64 (#3033)
* s_flbit_i32_b64

* Split FindUMsb64 into two 32bit ops
2025-06-05 14:33:25 -07:00
Stephen Miller
43bf4ed1bc
sceVideoOutGetResolutionStatus error behavior (#3044) 2025-06-05 12:14:34 -07:00
¥IGA
3b3026ff1c
[CI] Update Qt to 6.9.1 (#3037) 2025-06-05 16:44:02 +03:00
Stephen Miller
0e9420a7b2
Fix request queues in libSceZlib (#3041)
Queues are a FIFO data structure, so pop() removes the front, not the end.
2025-06-05 16:43:39 +03:00
georgemoralis
93222c6f9f
New Crowdin updates (#3038)
* New translations en_us.ts (Portuguese, Brazilian)

* New translations en_us.ts (Turkish)
2025-06-05 08:49:32 +03:00
DanielSvoboda
285df1b5be
QT: AutoUpdate - Fix Changelog Error (#3042) 2025-06-05 08:48:47 +03:00
Marcin Mikołajczyk
d4fbeea085
Stub PM4 COPY_DATA opcode (#3032) 2025-06-04 17:00:11 -07:00
Marcin Mikołajczyk
4d1a1ce9c2
v_rcp_legacy_f32 (#3040) 2025-06-04 16:55:47 -07:00
Stephen Miller
23710f397e
Reduce clamp threshold to 2MB (#3034)
A proposed solution to the non-GPU memory asserts seen in RESIDENT EVIL 2 (CUSA09193)
2025-06-03 22:17:35 -07:00
Dmugetsu
88f6cb4d41
clean up main window from extraction remains (#3035) 2025-06-04 00:26:04 +03:00
Marcin Mikołajczyk
5b6fc788b3
Fix passing user data in user-triggered equeue events (#2948) 2025-06-03 11:42:20 -07:00
Stephen Miller
8cdd8dd725
Core: Pthread affinity fixups (#3021)
* posix_pthread_attr_getschedparam

* Fixes for scePthreadGetAffinity and scePthreadSetAffinity

Looking at FreeBSD source, and our other pthread functions, we should be using our FindThread function to get the appropriate thread if thread != g_curthread.
2025-06-03 03:43:56 -07:00
Fire Cube
c09d1c3cff
Add support for game folder and fail early if eboot.bin is missing or corrupt (#3027) 2025-06-03 13:34:29 +03:00
Schweeeeeeeeeeeeeeee
ca0f458505
Add missing dependency for Fedora (#3005)
Propablly missing because of fedora 42?
2025-06-03 09:40:31 +03:00
Stephen Miller
bb3f8af81a
Core: Protect fixes (#3029)
* Swap do-while to while

If we use a do-while loop, we waste time if `aligned_size = 0`.  This is also still accurate to FreeBSD behavior, where it returns success if `start == end` during mprotect.
This also effectively prevents the memory assert seen in updated versions of RESIDENT EVIL 2 (CUSA09193)

* Move prot validation outside loop

The prot variable shouldn't change during a mprotect call, so we can check the flags before protecting instead.
Also cleans up the code for prot validation.
This should improve performance, and is more accurate to FreeBSD code.

* Add logging for protect calls

This will help in debugging future problems
2025-06-03 09:29:25 +03:00
mailwl
eed99141b3
Network Play: set user signed in (#2944)
* Network Play: set user signed in

* get signedIn status from config

---------

Co-authored-by: georgemoralis <giorgosmrls@gmail.com>
2025-06-03 09:11:18 +03:00
Stephen Miller
2c78272185
Emulate libSceGnmDriver's init behavior (#3024)
This time, perform it after the LoadSharedLibraries call, which places it after the various init memory mappings GFD engine titles perform.
2025-06-03 08:02:51 +03:00
kalaposfos13
1930a2132c
Fix SSH remote links (#3025) 2025-06-02 19:02:37 +03:00
Stephen Miller
6bdd83684b
Libs: libSceVoice stubs (#3022)
* voice lib stubs

Primarily for GTA V

* Clang
2025-06-01 19:30:03 +03:00
WujekFoliarz
b1af1334c9
Fix touchpad handling and change gyro calculation (#3006)
* Change touchpad handling and orientation calculation

* remove unnecessary includes in pad.cpp

* remove the cmake command arguments

* remove the weird file

* try to fix formatting

* limit new gyro and touchpad logic to controller 1

* remove cout

* fix formatting and add the handle check to scePadRead

* swap y and z back
2025-06-01 19:13:02 +03:00
¥IGA
bb199865cf
Qt: Set Minimum Icon Size List to 48 (#3018) 2025-06-01 14:52:09 +03:00
Stephen Miller
c09e463b8e
Revert new GPU map logic (#3019)
Something's wrong somewhere, and there's just too many places that somewhere could be for me to debug it right now.
2025-05-31 17:35:52 +03:00
Marcin Mikołajczyk
4019319d92
Provide custom border color to samplers (#3014) 2025-05-30 12:04:31 -07:00
Marcin Mikołajczyk
790b54bf29
Misc opcodes fixes (#3009) 2025-05-29 18:51:36 -07:00
Marcin Mikołajczyk
2091bc5651
Handle R128 bit in MIMG instructions (#3010) 2025-05-29 16:56:24 -07:00
Marcin Mikołajczyk
8fffdc3918
Handle V_CVT_F64_U32 (#3008) 2025-05-29 12:20:16 -07:00
Stephen Miller
6cdc52cdde
Core: More Memory Cleanup & Fixes (#2997)
* Only perform GPU memory mapping when GPU can access it

This better aligns with hardware observations, and should also speed up unmaps and decommits, since they don't need to be compared with the GPU max address anymore.

* Reserve fixes

ReserveVirtualRange seems to follow the 0x200000000 base address like MemoryPoolReserve does.
Both also need checks in their flags Fixed path to ensure we're mapping in-bounds. If we're not in mapping to our address space, we'll end up reserving and returning the wrong address, which could lead to weird memory issues in games.

I'll need to test on real hardware to verify if such changes are appropriate.

* Better sceKernelMmap

Handles errors where we would previously throw exceptions. Also moves the file logic to MapFile, since that way all the possible errors are in one place.
Also fixes some function parameters to align with our current standards.

* Major refactor

MapDirectMemory, MapFlexibleMemory, ReserveVirtualRange, and MemoryPoolReserve all internally use mmap to perform their mappings. Naturally, this means that all functions have similar behaviors, and a lot of duplicate code.
This add necessary conditional behavior to MapMemory so MemoryPoolReserve and ReserveVirtualRange can use it, without disrupting the behavior of MapDirectMemory or MapFlexibleMemory calls.

* Accurate phys_addr for non-direct mappings

* Properly handle GPU access rights

Since my first commit restricts GPU mappings to memory areas with GPU access permissions, we also need to be updating the GPU mappings appropriately during Protect calls too.

* Update memory.cpp

* Update memory.h

* Update memory.cpp

* Update memory.cpp

* Update memory.cpp

* Revert "Update memory.cpp"

This reverts commit 2c55d014c0.

* Coalesce dmem map

Aligns with hardware observations, hopefully shouldn't break anything since nothing should change hardware-wise when release dmem calls and unmap calls are performed?
Either that or Windows breaks because Windows, will need to test.

* Implement posix_mprotect

Unity calls this
Also fixes the names of sceKernelMprotect and sceKernelMtypeprotect, though that's more of a style change and can be reverted if requested.

* Fix sceKernelSetVirtualRangeName

Partially addresses a "regression" introduced when I fixed up some asserts.
As noted in the code, this implementation is still slightly inaccurate, as handling this properly could cause regressions on Windows.

* Unconditional assert in MapFile

* Remove protect warning

This is expected behavior, shouldn't need any logging.

* Respect alignment

Forgot to properly do this when updating ReserveVirtualRange and MemoryPoolReserve

* Fix Mprotect on free memory

On real hardware, this just does nothing. If something did get protected, there's no way to query that information.
Therefore, it seems pretty safe to just behave like munmap and return size here.

* Minor tidy-up

No functional difference, but looks better.
2025-05-29 18:56:03 +03:00
georgemoralis
aca8e7e9eb
New Crowdin updates (#2982)
* New translations en_us.ts (Spanish)

* New translations en_us.ts (Spanish)

* New translations en_us.ts (Turkish)
2025-05-29 12:42:52 +03:00
Fire Cube
eb9f66c349
Libs: CompanionUtil (#2963)
* impl

* more

* move log

* cleanup type definitions

* error code cleanup and clang

* cleanup ugly RE code

* shame

* clang

---------

Co-authored-by: georgemoralis <giorgosmrls@gmail.com>
2025-05-29 12:33:56 +03:00
georgemoralis
7f0503bf8b
Implemented sceNetInetNtop in RE (#3003)
* implemented sceNetInetNtop in RE

* some logging

* added freebsd_inet_ntop4

* freebsd_inet_ntop6

* fixups based on reviews

* review fixes
2025-05-29 11:59:34 +03:00
squidbus
95f04b746d
equeue: Move small timer check to WaitForEvents. (#3000) 2025-05-28 19:54:47 +03:00
Fire Cube
e0309a4b01
Equeue: fix WaitEqueue assert on nullptr (#2994)
* fix

* fix infinite call of waitforsmalltimer

* fix wrong nullptr check

* add comment back

* fix discrepancy

* remove assert

---------

Co-authored-by: georgemoralis <giorgosmrls@gmail.com>
2025-05-27 14:47:54 -07:00
Marcin Mikołajczyk
139a253edc
Stub PM4 0x8E opcode (#2998) 2025-05-27 12:09:03 -07:00
Lander Gallastegi
99ccf56938
Fix float on f64 (#2985) 2025-05-25 03:49:39 -07:00
Fire Cube
149898193f
Devtools: Add Module Viewer (#2976)
* impl

* add User or Sysmodule detection

* fix compiler warning

* clang

* fix string

* add HLE

* prevent crash

* fix mutex

* remove ref in arg

* cleanup

* move gamefolder to elfinfo
2025-05-24 09:15:10 -03:00
Lander Gallastegi
10d09ac977
Added back the "Attempted to track non-GPU memory" assert. (#2980)
* Fix log message

* Add non-GPU memory assert back
2025-05-24 01:48:40 +03:00
squidbus
e5c6c88835
texture_cache: Handle overlap with equal address and different tiling mode (#2981) 2025-05-23 10:56:46 -07:00
squidbus
d124f40503
externals: Update MoltenVK (#2979) 2025-05-22 18:22:05 -07:00
Marcin Mikołajczyk
e518a7062c
Fix image extent in buffer copy to image (#2961) 2025-05-22 12:17:34 -07:00
Lander Gallastegi
f9bbde9c79
video_core: Implement DMA. (#2819)
* Import memory

* 64K pages and fix memory mapping

* Queue coverage

* Buffer syncing, faulted readback adn BDA in Buffer

* Base DMA implementation

* Preparations for implementing SPV DMA access

* Base impl (pending 16K pages and getbuffersize)

* 16K pages and stack overflow fix

* clang-format

* clang-format but for real this time

* Try to fix macOS build

* Correct decltype

* Add testing log

* Fix stride and patch phi node blocks

* No need to check if it is a deleted buffer

* Clang format once more

* Offset in bytes

* Removed host buffers (may do it in another PR)

Also some random barrier fixes

* Add IR dumping from my read-const branch

* clang-format

* Correct size insteed of end

* Fix incorrect assert

* Possible fix for NieR deadlock

* Copy to avoid deadlock

* Use 2 mutexes insteed of copy

* Attempt to range sync error

* Revert "Attempt to range sync error"

This reverts commit dd287b48682b50f215680bb0956e39c2809bf3fe.

* Fix size truncated when syncing range

And memory barrier

* Some fixes (and async testing (doesn't work))

* Use compute to parse fault buffer

* Process faults on submit

* Only sync in the first time we see a readconst

Thsi is partialy wrong. We need to save the state into the submission context itself, not the rasterizer since we can yield and process another sumission (if im not understanding wrong).

* Use spec const and 32 bit atomic

* 32 bit counter

* Fix store_index

* Better sync (WIP, breaks PR now)

* Fixes for better sync

* Better sync

* Remove memory coveragte logic

* Point sirit to upstream

* Less waiting and barriers

* Correctly checkout moltenvk

* Bring back applying pending operations in wait

* Sync the whole buffer insteed of only the range

* Implement recursive shared/scoped locks

* Iterators

* Faster syncing with ranges

* Some alignment fixes

* fixed clang format

* Fix clang-format again

* Port page_manager from readbacks-poc

* clang-format

* Defer memory protect

* Remove RENDERER_TRACE

* Experiment: only sync on first readconst

* Added profiling (will be removed)

* Don't sync entire buffers

* Added logging for testing

* Updated temporary workaround to use 4k pages

* clang.-format

* Cleanup part 1

* Make ReadConst a SPIR-V function

---------

Co-authored-by: georgemoralis <giorgosmrls@gmail.com>
2025-05-22 21:00:15 +03:00
georgemoralis
37887e8fde starting 0.9.1 WIP 2025-05-22 19:11:25 +03:00
georgemoralis
9c2f71326a tagged 0.9.0 release 2025-05-22 18:52:44 +03:00
georgemoralis
b55c3f4555
Trophy fix (#2975)
* fixed invalid handle destroy

* removed log
2025-05-22 05:35:00 -07:00
squidbus
3f949d2b6c
amdgpu: Handle 32-bit Unorm formats. (#2974) 2025-05-22 03:16:20 -07:00
squidbus
f4eb0b9b9e
shader_recompiler: Fix buffer type reading from step rate attribute. (#2973) 2025-05-22 03:03:24 -07:00
squidbus
6935b24440
savedata: Fix missing uses of config based save data dir. (#2971) 2025-05-22 11:28:41 +03:00
kalaposfos13
786ad6f71e
Fork detection fixes IIIIX (#2966)
* Fix local builds

* Add remote fork windows title to release builds too

* Remove trailing slah from remote links before processing
2025-05-21 23:00:11 +03:00
kalaposfos13
eb21083078
Lower stack size to clear from 13 to 12 KB (#2967) 2025-05-21 16:22:38 -03:00
Lander Gallastegi
1b952bf173
ReadConst debug msg (#2964) 2025-05-21 19:08:27 +03:00
georgemoralis
60224e1d22
New Crowdin updates (#2953)
* New translations en_us.ts (Portuguese)

* New translations en_us.ts (Portuguese)

* New translations en_us.ts (Albanian)

* New translations en_us.ts (Russian)

* New translations en_us.ts (Norwegian Bokmal)

* New translations en_us.ts (French)

* New translations en_us.ts (Swedish)

* New translations en_us.ts (Norwegian Bokmal)
2025-05-21 13:57:52 +03:00
squidbus
034ae8cffa
qt: Update save data dir open to use name from PSF. (#2954) 2025-05-18 13:16:31 -07:00
Vinicius Rangel
5eb58799fe
SaveData: respect install dir in param.sfo to select the game save folder (#2951) 2025-05-17 12:00:35 -03:00
georgemoralis
6ee205d4e2
New Crowdin updates (#2946)
* New translations en_us.ts (Korean)

* New translations en_us.ts (Romanian)

* New translations en_us.ts (French)

* New translations en_us.ts (Spanish)

* New translations en_us.ts (Arabic)

* New translations en_us.ts (Danish)

* New translations en_us.ts (German)

* New translations en_us.ts (Greek)

* New translations en_us.ts (Finnish)

* New translations en_us.ts (Hungarian)

* New translations en_us.ts (Italian)

* New translations en_us.ts (Japanese)

* New translations en_us.ts (Lithuanian)

* New translations en_us.ts (Dutch)

* New translations en_us.ts (Polish)

* New translations en_us.ts (Portuguese)

* New translations en_us.ts (Russian)

* New translations en_us.ts (Slovenian)

* New translations en_us.ts (Albanian)

* New translations en_us.ts (Swedish)

* New translations en_us.ts (Turkish)

* New translations en_us.ts (Ukrainian)

* New translations en_us.ts (Chinese Simplified)

* New translations en_us.ts (Chinese Traditional)

* New translations en_us.ts (Vietnamese)

* New translations en_us.ts (Portuguese, Brazilian)

* New translations en_us.ts (Indonesian)

* New translations en_us.ts (Persian)

* New translations en_us.ts (Norwegian Bokmal)

* New translations en_us.ts (Chinese Simplified)

* New translations en_us.ts (Italian)
2025-05-17 17:33:24 +03:00
Vinicius Rangel
5f447a815e
SaveDataDialog: fix possible null access (#2947) 2025-05-17 10:41:16 -03:00
tlarok
e2513d50be
New kbm icon (#2898)
* Update kbm_gui.cpp

* Update kbm_gui.cpp

* Update kbm_gui.h

* Update kbm_gui.cpp

* lunix test

* linux test

* Update kbm_gui.h

* Update kbm_gui.cpp

* Update kbm_gui.cpp

* Update kbm_gui.cpp

* Update kbm_gui.cpp

* Update kbm_gui.h

* Update kbm_gui.cpp

* Update kbm_gui.h

* Update kbm_gui.cpp

* Update kbm_gui.h

* Update kbm_gui.cpp

* kbm_gui.cpp's names fix

just cleaning my code

* name fix

* Update kbm_gui.cpp

* Update kbm_gui.h

* Update kbm_gui.cpp

* Update src/qt_gui/kbm_gui.cpp

Co-authored-by: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com>

* clean up from main

* bruh, welp here we go again

* Update KBM.png

* resize kbm.png

* Update kbm_gui.ui

* test update kbm_gui.ui

---------

Co-authored-by: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com>
2025-05-17 11:39:35 +03:00
georgemoralis
a09f7158b8
New translations en_us.ts (Korean) (#2943) 2025-05-17 11:38:38 +03:00
georgemoralis
251d0f0d7c
[ci skip] Qt GUI: Update Translation. (#2910)
Co-authored-by: georgemoralis <4313123+georgemoralis@users.noreply.github.com>
2025-05-17 11:38:04 +03:00
Stephen Miller
a0acb47185
Only align when flags Fixed is not present (#2945)
Should fix some remaining memory issues.
2025-05-16 14:21:13 -07:00
mailwl
ffd31589cf
Fix reading not existing savedata (#2941)
* Fix reading not existing savedata

* alloc save memory instead return error

* save memory saze to save slot instead of global

* remove unused enum

* remove unneeded memory clean
2025-05-16 13:22:47 -03:00
Stephen Miller
4d769d9c7e
Proper error handling for MapMemory errors (#2938)
* Properly handle ENOMEM error return in MapMemory

Needed for Assassin's Creed Unity to behave properly.

* Change error message

If I left the message as-is, we'd probably see inexperienced people claiming the assert means your device needs more memory, which is completely false.

* Clang

You know you're doing something right when Clang complains.

* Attempt to handle MemoryMapFlags::NoOverwrite

Based on my interpretation of red_prig's descriptions. These changes are untested, as I'm not able to test right now.

* Fix flag description

* Move overwrite check to while condition
2025-05-16 17:41:22 +03:00
georgemoralis
7de6aec337
[Libs] Companion httpd (#2942)
* stubbed companion httpd

* sceCompanionHttpdGetEvent returns disconnected device

* more function definations

* added error codes file
2025-05-16 16:17:37 +03:00
Stephen Miller
18ff65efc8
Implement sceKernelMapDirectMemory2 (#2940)
* Implement sceKernelMapDirectMemory2

Behaves similarly to sceKernelMapDirectMemory, but has a type parameter.

* Simplify

No need to copy all the MapDirectMemory code over, can just call the function, then do the SetDirectMemoryType call

* Clang
2025-05-16 05:38:40 -07:00
squidbus
aeb4536988
externals: Remove winpthreads. (#2932) 2025-05-15 13:59:34 -07:00
MajorP93
98faff425e
build: Target x86-64-v3 CPU architecture (#2934) 2025-05-14 10:37:16 -07:00
Stephen Miller
6d38100a41
Avoid logging nulls in sceKernelIsStack (#2933)
Games would crash if providing nullptr to start or end.
Also don't need the :# part when logging pointers, as they're automatically formatted.
2025-05-14 17:09:23 +03:00
squidbus
26c965cf4a equeue: Fix timer cancel error code check. 2025-05-13 17:31:23 -07:00
squidbus
99eaba7c96
liverpool: Lower SetQueueReg to warning log. (#2930) 2025-05-13 16:08:25 -07:00
squidbus
1639640902 event_flag: Lower error logs to debug. 2025-05-13 14:46:59 -07:00
Marcin Mikołajczyk
647b1d3ee4
Handle VgtStreamoutFlush event (#2929) 2025-05-13 14:34:22 -07:00
Marcin Mikołajczyk
6abda17532
Avoid post-increment of SGPR in S_*_LOAD_DWORD (#2928) 2025-05-13 14:31:14 -07:00
squidbus
3ab69e24db fix: Compiling with newer Boost 2025-05-13 14:22:44 -07:00
squidbus
073f931729 fix: PM4CmdWaitRegMem memory address 2025-05-13 14:14:11 -07:00
squidbus
0d127a82dd
equeue: Clean up timers implementation. (#2925) 2025-05-13 14:05:29 -07:00
Marcin Mikołajczyk
e5b675d607
Handle IT_WAIT_REG_MEM with Register argument (#2927) 2025-05-13 13:56:20 -07:00
Marcin Mikołajczyk
1832ec2ac2
Implement sceKernelIsStack (#2917) 2025-05-13 13:54:22 -07:00
Marcin Mikołajczyk
484fbcc320
Handle -1 as V_CMP_NE_U64 argument (#2919) 2025-05-13 13:19:56 -07:00
Fire Cube
7334fb620b
sceKernelAddTimerEvent implementation (#2906)
* implementation

* add backend (WIP)

* now should be good
- fix implementation based on homebrew tests
- demote log to debug
- make squidbus happy (hopefully)

* fix moved m_name

* fix clang

* replace existing event when its same id and filter

* run timercallback after addEvent and remove useless code

* move KernelSignalRequest to the end

* clang (i hate you)
2025-05-13 12:16:53 -07:00
georgemoralis
f97c0deea9
ngs2: removed possible nullptr value from logging (#2924) 2025-05-13 11:29:47 -07:00
squidbus
4cd13ea9d8 fix: Disable emitting bounds checks until fixed. 2025-05-12 23:10:48 -07:00
georgemoralis
e6a144ddb0
[Libs] sceNet IV (#2867)
* dummy returns in p2p sockets

* added logging for sceNetSetsockopt

* possible fix for ORBIS_NET_SO_LINGER set

* logging for getsockoption as well

* disable kernel getsockname (seems to create issues with cyberpunk)

* some fixes with SetSocketOptions

* arggg

* posix_getsockname try

* mutex protection

* removed duplicated include (diegolix29)

* posix_getsockname appears to have issues in cyberpunk , comment it for now
2025-05-13 08:54:38 +03:00
squidbus
3a10fda008 kernel: Simplify sceKernelUuidCreate 2025-05-12 22:15:04 -07:00
Roman
2a3a701115
kernel: macos/linux Implement sceKernelUuidCreate (#2923)
* kernel: macos/linux Implement sceKernelUuidCreate

* Fix clang-format

* Fix Linux build

* Fix Linux build (2)

---------

Co-authored-by: squidbus <175574877+squidbus@users.noreply.github.com>
2025-05-12 22:10:33 -07:00
squidbus
6bbb424c28
vk_instance: Enable robustImageAccess2 (#2922) 2025-05-12 18:03:55 -07:00
Marcin Mikołajczyk
3a3a6d8e45
Mprotect only over whole pages (#2918)
* Mprotect only over whole pages

* Fix aligned_size error and clang-format.

---------

Co-authored-by: squidbus <175574877+squidbus@users.noreply.github.com>
2025-05-12 16:55:19 -07:00
squidbus
b23f6fdc1d
buffer_cache: Split updateBuffer calls into 65536 byte chunks. (#2915) 2025-05-12 15:27:47 -07:00
Randomuser8219
9baa58dd92
renderer_vulkan: Properly enable dualSrcBlend feature. (#2921)
* renderer_vulkan: Properly enable dualSrcBlend feature

* whoops
2025-05-12 15:26:55 -07:00
Vinicius Rangel
5ab5fa7024
hotfix: replace memset declaration by cstring include
fixes the Arch package build (https://aur.archlinux.org/packages/shadps4-git#comment-1023984)
2025-05-12 18:35:04 -03:00
ringolol
b3abb83fc5
fix rough mouse movement due to incorrect check (#2911)
Co-authored-by: rnglol <kek@example.com>
2025-05-12 21:39:50 +02:00
squidbus
f94c7e52b7
kernel: Implement scePthreadGetaffinity (#2916) 2025-05-12 10:46:53 -07:00
squidbus
8909d9bb89
shader_recompiler: Always mark buffers as storage buffers. (#2914) 2025-05-12 10:46:40 -07:00
squidbus
678f18ddb9
core: Introduce host call wrapper. (#2913) 2025-05-11 20:27:54 -07:00
squidbus
02d3ed4973
liverpool: Log more information on SetQueueReg. (#2912) 2025-05-11 20:27:43 -07:00
Stephen Miller
6206986914
libkernel: Implement sceKernelMemoryPoolBatch (#2909)
* Implement sceKernelMemoryPoolBatch

I've tested Commit and Decommit on real hardware, haven't tested Protect or TypeProtect yet.

Implementation is primarily based on our sceKernelBatchMap implementation.

* Clang
2025-05-11 19:51:03 -07:00
squidbus
c0562a6b1b
qt: Delay physical device enumeration to settings open. (#2908) 2025-05-11 14:23:49 -07:00
squidbus
3a090e988c
kernel: Clean up and fix some mistakes. (#2907) 2025-05-11 14:22:17 -07:00
georgemoralis
ff1339b0b6
[Libs] Camera (#2902)
* stubbed camera lib

* function definations

* added error codes
2025-05-11 19:03:55 +03:00
Stephen Miller
afcf3a12a3
Core: Pooled Memory Fixes (#2895)
* Update sceKernelMemoryPoolExpand

Hardware tests show that this function is basically the same as sceKernelAllocateDirectMemory, with some minor differences.
Update the memory searching code to match my updated AllocateDirectMemory code, with appropriate error conditions.

* Update MemoryPoolReserve

Only difference between real hw and our code is behavior with addr = 0.

* Don't coalesce PoolReserved areas.

Real hardware doesn't coalesce them.

* Update PoolCommit

Plenty of edge case behaviors to handle here.
Addresses are treated as fixed, EINVAL is returned for bad mappings, name should be preserved from PoolReserving, committed areas should coalesce, reserved areas get their phys_base updated

* Formatting

* Adjust fixed PoolReserve path

Hardware tests suggest this will overwrite all VMAs in the range. Run UnmapMemoryImpl on the full area, then reserve. Same logic applies to normal reservations too.

Also adjusts logic of the non-fixed path to more closely align with hardware observations.

* Remove phys_base modifications

This can be handled later. Doing the logic properly would likely take work in MergeAdjacent, and would probably need to be applied to normal dmem mappings too.

* Use VMAHandle.Contains()

Why do extra math when we have a function specifically for this?

* Update memory.cpp

* Remove unnecessary code

Since I've removed those two asserts, these two lines of code effectively do nothing.

* Clang

* Fix names

* Fix PoolDecommit

Should fix the address space regressions in UE titles on Windows.

* Fix error log

Should make the cause of this clearer?

* Clang

* Oops

* Remove coalesce on PoolCommit

Windows makes this more difficult.

* Track pool budgets

If you try to commit more pooled memory than is allocated, PoolCommit returns ENOMEM.
Also fixes error conditions for PoolDecommit, that should return EINVAL if given an address that isn't part of the pool.

Note: Seems like the pool budget can't hit zero? I used a <= comparison based on hardware tests, otherwise we're able to make more mappings than real hardware can.
2025-05-11 02:59:14 -07:00
Stephen Miller
6ece91c763
sceKernelVirtualQuery Fixes VI (#2904)
* Reduce bitfield size

Linux compilers automatically convert this, Windows not so much.

* Static assert for VirtualQueryInfo struct size

Since compilers can be weird, having a static assert for this will be helpful.
Granted, this probably wont need changing after this PR.
2025-05-10 20:02:00 -07:00
georgemoralis
7eea1fc4d6
log error for videodec ,videodec2 (#2900) 2025-05-10 23:29:23 +03:00
squidbus
c6ea7d8f76
externals: Update SDL3 (#2896) 2025-05-10 13:02:45 +03:00
Stephen Miller
6477dc4f1e
Core: Memory Fixes (#2872)
* Fix VirtualQuery behavior on low addresses.

* Fix VirtualQuery struct

Somewhere in our BitField and array use, the size of our VirtualQuery struct became larger than the struct used on real hardware.
Fixing this fixes some data corruption visible in the name parameter during my tests.

* Default name to anon

On real hardware, nameless mappings are given the name "anon:address" where address appears to be the address that made the memory call.
For simplicity sake, I'll stick to the name "anon" for now.

* Place an upper bound on returns from SearchFree

Right now, this upper bound is set based on the limitations of our GPU buffer cache and page table.
Someone with more experience in that area of code should probably fix that at some point.

* More anons

* Clang

* Fix name in sceKernelMapNamedDirectMemory

* strncpy instead of strcpy

Hardcoded the constant size for now, I need to review how real hardware behaves here to determine if anything else is necessary for this to be accurate.

* Fix name behavior

All memory naming functions restrict the name size to a 31 character limit, and return `ORBIS_KERNEL_ERROR_ENAMETOOLONG` if that limit is exceeded.
Since this value is constant for all functions involving names, I've defined it as a constant in kernel's memory.h, and used that in place of any hardcoded 32 character limits.

* Error logging

Hopefully this helps in catching the UFC regression?

* Increase address space upper bound

Probably needs heavy testing, especially on Mac/Windows.
This increases the address space, as needed to accommodate strange memory behaviors seen in UFC.

* VirtualQuery fix

Due to limitations of certain platforms, we initialize our vma_map with 3 separate free mappings.
As such, we need to use a while loop here to accurately query mappings with high addresses

* Fix mappings to high addresses

The PS4's GPU can only handle 40bit addresses. Our texture cache and buffer cache were designed around these limits, and mapping to higher addresses would cause segmentation faults and access violations.
To fix these crashes, only map to the GPU if the mapping is fully contained within the address space the GPU should access.
I'm open to suggestions on how to make this cleaner

* Revert "Increase address space upper bound"

This reverts commit 3d50eeeebb.

* Revert VirtualQuery while loop

Windows wasn't happy with this, again.
Will try to debug and properly fix this when I have a good chance.

* Fix asserts

FindVMA, due to the way it's programmed, never actually returns vma_map.end(), the furthest it ever returns is the last valid memory area. All those asserts we involving vma_map.end() never actually trigger due to this.
This commit removes redundant asserts, adds messages to asserts that were lacking them, and fixes all asserts designed to detect out of bounds memory accesses so they actually trigger.
I've also fixed some potential memory safety issues.

* Proper error behavior in QueryProtection

Might as well handle this properly while I'm here.

* Clang

* More information about ReserveVirtualRange results

Should help debug issues like the one in The Order: 1886 (CUSA00076)

* Fix assert message

* Update assert message

Extra space

* Fix my bug

Oh hey, finally something that's my fault.

* Fix rasterizer unmaps

Should use adjusted_size here, otherwise we could unmap too much.
Thanks to diegolix29 for spotting this.

* Fix edge case in MapMemory

Code comments explain everything.
This should fix some memory asserts.

* Fix fix

Avoid running the code path if it's unnecessary, since there are many additional edge cases to handle when the VMA map is small.

* Fix fix fix

Should prevent infinite loops, haven't tested properly yet though.

* Split logging for inputs and out_addr in ReserveVirtualRange

Addresses review comments.
2025-05-09 12:33:04 -07:00
squidbus
a1439b15cf
gnm: Implement sceGnmDrawIndexIndirectMulti (#2889) 2025-05-09 10:04:37 -07:00
Missake212
8d7cbf9943
Adding opcode IMAGE_SAMPLE_B_O (#2894)
* Adding opcode IMAGE_SAMPLE_B_O:

* fix clang (my first time !)
2025-05-09 09:01:34 -07:00
squidbus
b130fe6ed5
vulkan: Handle incompatible depth format using null binding. (#2892)
Co-authored-by: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com>
2025-05-09 08:43:20 -07:00
kalaposfos13
8e7c5a4d99
Remove deprecated include (#2893) 2025-05-09 08:33:32 -07:00
mailwl
46b88bd10f
[Libs] Stubs sceSigninDialog (#2890)
* [Libs] Stubs SigninDialog

* clang-format

* clang-format again

* remove magic constant

* log dialog finished status
2025-05-09 11:08:22 +03:00
Paris Oplopoios
58df609ba0
Optimize games that hit unpatchable EXTRQ/INSERTQ (#2888)
* Make signal handler faster

* I love clang-format

* Use faster decoding

* MacOS CI
2025-05-08 19:59:12 +03:00
Vinicius Rangel
3b7c36e1ba
Clear stack before executing guest code (#2877)
* Clear stack before executing guest code

* clang, don't optimize me 🚨

avoid ClearStack function being optimized in release builds
2025-05-07 15:20:55 -07:00
Fire Cube
1aa7eb8a42
add scePthreadSetaffinity and emulate affinity (#2885)
* add implementation

* fix preprocessor

* fixes squidbus's comments

* fix clang

* comment became fucked up?

* fix removed return
2025-05-07 14:50:16 -07:00
MajorP93
c7fb3ebd93
shader_recompiler: Widen num_conversion bitfield (#2886)
We do this in order to be able to actually fit in all possible values from AmdGpu::NumberConversion.

Fixes gcc compiler warnings:
warning: ‘Shader::PsColorBuffer::num_conversion’ is too small to hold all values of ‘enum class AmdGpu::NumberConversion’
2025-05-06 17:11:32 -07:00
Stephen Miller
fed064931a
Core: Fix module load addresses (#2879)
* Fix module map addresses

Most modules are mapped starting at 0x800000000, with no gaps between mappings.

* Hardcode hardware accurate base address

Looking at our address space, all platforms will have this base address mapped, so there shouldn't be any problem in using it.

* Clang

* Swap module mapping to NoFlags, remove offset code

Since real hardware has no gap between module mappings, the Fixed flag is just an annoyance to work around, and has no impact on the actual mappings.
Swapping the module mappings to use flags NoFlags instead simplifies our code slightly.

* Fix module mapping names

On real hardware, the file extension is part of the mapping name. Easiest way to manage this is to swap the name to be `file.filename().string()` instead of `file.stem().string()`

* Fix patches

Completely missed this, whoops.
2025-05-05 03:24:08 -07:00
oltolm
9a22185ab7
vulkan: do not use VK_EXT_extended_dynamic_state (#2880)
fixes Bloodborne crashing on RX 580
2025-05-04 03:11:02 -07:00
squidbus
17b6343f18
emulator: Fix log initialization order. (#2878) 2025-05-03 13:47:03 -07:00
Vinicius Rangel
d542d952f4
Savefixes VIII (#2851)
* savedata dialog: fix SaveDialogUi move semantics

fix possible dangling points

* savedata dialog: removed unnecessary firmware version checks
2025-05-03 12:51:10 -03:00
Stephen Miller
0ba9ea6a3b
Only perform early read-write open when truncating is needed (#2874)
Should stop some fs error spam when games open files from /app0, as this open call would fail from reduced permissions.
2025-05-02 11:22:05 -07:00
squidbus
eb09c4ccce
vk_presenter: Use correct format for output frame image and view. (#2871) 2025-05-01 20:10:42 -07:00
Stephen Miller
6c39bf229c
libkernel: Various filesystem fixes (#2868)
* Proper handling of whence 3 & 4

* Accurate directory handling in open

Directories can be opened, and can be created in open, these changes should handle that more accurately.

* Mount /app0 as read only

On real hardware, it's read only.

* Proper directory flag handling.

Even when directory is specified, it will still succeed to open non-directories.

* Check for read only directories

* Earlier ro check in posix_rmdir

Hardware tests suggest these checks are in a different order

* Clear temp folder on boot

My tests rely on this, and some games do too.
Two birds with one stone

* Clang

* Add missing DeleteHandle calls

Whoops

* Final flags adjustment in sceKernelOpen

All my current tests are now hardware accurate.

* Fix truncates

Host ftruncate consistently fails on EINVAL, I'll need to test if this issue affected Windows too.

* Windows hacks

Windows is more limiting about how folders are opened and things like that. For now, pretend these calls didn't error.
Also fixes compilation for Windows

* Final touch-ups

After expanding my test suite further, I found a couple more edge cases that needed addressing.
Bloodborne audio is still broken, I'll look into that soon.

* Remove hacky read-only behavior in posix_stat

Bloodborne apparently uses the mode parameter here when querying it's audio files, and the mode we returned led to it disabling audio entirely.

* Clang

* Cleaner code

* Combine fsync and sync flags

According to FreeBSD docs, the "sync" flag is synonymous with the fsync flag, and is only included to meet the POSIX spec.

* Log if any currently unhandled flags are encountered.

These are rare and probably not too important, but log a warning when they're seen.

* Update file_system.cpp

* Update file_system.cpp

* Clang

* Revert truncate fix

Using ftruncate works fine after moving the call to before the proper file opening code.

* Truncate before open

Open the file as read-write, then try truncating.
This fixes read | truncate flag behavior on Windows.

* Slightly adjust check for invalid flags

Any open call with invalid flags should return EINVAL, regardless of other errors parameters might cause.
2025-05-01 14:47:43 +03:00
Mahmoud Adel
b0e4e87ff3
Implement SnormNz conversion (#2841)
* +

* +

* Unpack Snorm 2x16

* +

* SintToSnormNz

* all is broken ig....

* review changes

* my stupid ass messed all while trying to resolve the conflicts..

* +

* +

* fix rebase

* clang-format fix (1)

* clang-format fix (2)

---------

Co-authored-by: squidbus <175574877+squidbus@users.noreply.github.com>
2025-05-01 02:12:15 -07:00
squidbus
4202d9d621 fix: Add missing ctime includes. 2025-04-30 23:37:37 -07:00
squidbus
5fd5b62539
shader_recompiler: Few fixes for buffer number conversions. (#2869)
* liverpool: Pass correct color buffer number type for conversion mapping.

* shader_recompiler: Apply number conversion to vertex inputs.
2025-04-30 20:46:16 -07:00
squidbus
10b24d04bc fix: Add new image atomic instructions to relevant lists. 2025-04-30 17:55:50 -07:00
anna12831920
c47d9b2ad6
Export eboot address (#2866) 2025-04-30 22:56:44 +03:00
squidbus
ede60e8f7f fix: Do not declare atomic float capability when not supported. 2025-04-30 11:43:51 -07:00
Marcin Mikołajczyk
c08f92aca1
Implement IMAGE_ATOMIC_FMIN and IMAGE_ATOMIC_FMAX for 32bit floats (#2820)
* Implement IMAGE_ATOMIC_FMIN and IMAGE_ATOMIC_FMAX for 32bit floats

* Handle missing VK_EXT_shader_atomic_float2
2025-04-30 11:42:08 -07:00
squidbus
a3bbf2274f fix: Mistake in store bounds check index. 2025-04-30 11:39:42 -07:00
georgemoralis
bb59cd81fa
[Libs] sceNet (#2815)
* implemented sceNetGetMacAddress

* added all error codes

* added ORBIS_NET_CTL_INFO_DEVICE , ORBIS_NET_CTL_INFO_MTU

* RE sceNetConnect

* sceNetBind RE

* RE sceNetAccept

* RE sceNetGetpeername ,sceNetGetsockname

* fixup

* RE sceNetListen ,sceNetSetsockopt

* sceNetShutdown,sceNetSocket,sceNetSocketAbort,sceNetSocketClose

* sceSend,sceSendTo,sceSendMsg

* sceNetRecv,sceNetRecvFrom,sceNetRecvMsg RE

* some kernel net calls

* init winsock2

* logging

* sockets interface

* added winsock to SCE* error codes conversion

* implemented net basic calls

* some net calls implementation

* clang fixes

* fixes for linux+macOS

* more fix

* added sys_accept implementation

* more posix net calls

* implemented sys_getsockname

* fixed redirection

* fixed posix socket?

* posix_sendto , recvfrom

* added sys_socketclose

* unsigned error log

* added setsocketoptions

* added more posix net calls

* implement getsocketOptions

* stubbed p2p calls
2025-04-30 17:58:39 +03:00
georgemoralis
53b2ccffca
New Crowdin updates (#2846)
* New translations en_us.ts (Vietnamese)

* New translations en_us.ts (Vietnamese)

* New translations en_us.ts (Vietnamese)

* New translations en_us.ts (Vietnamese)
2025-04-30 12:41:30 +03:00
Marcin Mikołajczyk
fa9f58446f
Implement sceKernelPwritev (#2865) 2025-04-30 02:09:40 -07:00
squidbus
5e3157a82c
vk_rasterizer: Fix updating wrong color attachment when skipped by mask. (#2859) 2025-04-29 16:29:35 -07:00
lcjh
beb9c86749
Code Review: SuspiciousPriority (#2854)
Priority of the '&&' operation is higher than that of the '||' operation.It's possible that parentheses should be used in the expression.
2025-04-28 11:27:25 -07:00
squidbus
81fa9b7fff
shader_recompiler: Add lowering pass for when 64-bit float is unsupported. (#2858)
* shader_recompiler: Add lowering pass for when 64-bit float is unsupported.

* shader_recompiler: Fix PackDouble2x32/UnpackDouble2x32 type.

* shader_recompiler: Remove extra bit cast implementations.
2025-04-28 00:04:16 -07:00
squidbus
385c5a4507 fix: Add missing OpSelectionMerge in bounds check. 2025-04-27 21:53:36 -07:00
squidbus
59d060bc16 fix: gcc compile 2025-04-27 21:06:10 -07:00
squidbus
83fd0683fa fix: Properly enable depthBounds feature. 2025-04-27 20:57:04 -07:00
squidbus
81ad31ce31
pp_pass: Use correct surface format. (#2860) 2025-04-27 20:56:17 -07:00
MajorP93
ff984d3cde
ci: Use mold linker for Linux builds (#2847)
* The default linker which happens to be BFD in Ubuntu 24.04 does not support Clang's ThinLTO which CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE=ON tries to enable.
* Using mold linker fixes this and reduces build time a bit.
* For consistency reasons we enable mold linker for GCC builds aswell.
2025-04-27 20:34:59 -07:00
squidbus
b505829e16
lower_buffer_format_to_raw: Fix handling of format remapping. (#2857) 2025-04-27 16:52:52 -07:00
Valdis Bogdāns
254375ef0c
Update ime_dialog.h (#2853)
Fix the incorrect ORBIS_IME_DIALOG_MAX_TEXT_LENGTH; a larger value is required for at least the game Undertale
2025-04-27 20:57:20 +03:00
Vinicius Rangel
cef795b80b
devtools: persist fsr configs (#2852)
Saves FSR config to imgui.ini so it won't reset every startup
2025-04-27 13:32:29 -03:00
Stephen Miller
410313ca87
Implement sceKernelGetModuleInfo, sceKernelGetModuleInfoInternal, and sceKernelGetModuleList (#2850)
* Fix GetModule exception

Simple mistake

* Prevent OOB writes in add_segment

Due to mistakes in our linker logic, OpenOrbis' libSceFios2 causes OOB writes here.
While the ideal solution would be to fix the erroneous behavior, the best I'm capable of right now is just preventing the OOB writes.

* Implement sceKernelGetModuleInfo, sceKernelGetModuleInfoInternal, sceKernelGetModuleList

These are implemented based on hardware observations and a homebrew sample made by red_prig. I've yet to test what error cases can show up.

* Clang

* Accurate error returns

If there are more modules than provided space, then return kernel ENOMEM.
If either handles or out_count are null, return kernel EFAULT.

* Accurate error checks in ModuleInfo functions

* Clang
2025-04-27 09:32:01 +03:00
Stephen Miller
c09fff2da6
VideoOut event cleanup (#2849)
* Readable VideoOutEvent data packing

Inspired by the work of former shadPS4 devs and mostly based on red_prig's current code.

* Apply DceData struct to sceVideoOutGetEventCount

Makes the code easier to read

* Update equeue.h

* Update main.cpp

* Update equeue.h

* Proper struct names

* Fix hint mask

Thanks to red_prig for catching my mistake here.

* Clang

* Fix header discrepancy
2025-04-27 09:04:17 +03:00
baggins183
e816bc4b99
Use GetSrc in VALU insts instead of assuming vector reg (was vcc_lo) (#2845)
* Use GetSrc in v_add_i32 instead of assuming vector reg (was vcc_lo)

* some other cases
2025-04-25 19:44:03 -07:00
MajorP93
632ed99ee7
ci: Bump Clang to 19 for Linux builds, align LLVM repository with runner version (#2844)
* ci: Bump Clang to 19 for Linux builds
* PR #2434 was intended to bump Clang to 19. In reality it only made sure that clang-format-19 is being used and that the shadPS4 codebase can be compiled with Clang 19.
This PR makes sure that Clang 19 is actually being used for Linux builds which makes sense since we use Clang 19 for Windows builds already (Since Visual Studio 17.13 Clang 19 is being shipped).

* ci: Use noble variant of LLVM repository
* shadPS4 has been using Ubuntu 24.04 runners for some time now. This commit makes sure the correct LLVM repository is being used.
2025-04-25 15:06:51 -07:00
squidbus
15d6a45dcd
externals: Simplify MoltenVK bundling. (#2842) 2025-04-24 19:40:50 -07:00
Dmugetsu
d370ea32f4
Sysmodules (#2826)
* Some sysmodules inconsistencies fixed. Based on Visual studio flags if they are irrelevant lmk

* Suggestions - info passed to sceKernelGetModuleInfoForUnwind and if name field matches it gets zeroed

* Final suggestions

* reverting OrbisModuleInfoForUnwind and modifing header.
2025-04-24 14:46:22 -07:00
kalaposfos13
c01590175a
Implement sceImeDialogGetPanelSize (#2839)
* Implement sceImeDialogGetPanelSize

* Fix header

* Clang

* Adjust values that are different from Ime

* Add original sizes as comments

* clang

* At this point half of the PR is from squidbus, and I'm just typing out what they say

---------

Co-authored-by: squidbus <175574877+squidbus@users.noreply.github.com>
2025-04-24 13:13:44 -07:00
Stephen Miller
a12d447bd6
sceKernelAllocateDirectMemory hotfixes (#2838)
* Update memory.cpp

* Clean logic

FindDmemArea guarantees that the first dmem area we check contains search_start. Any dmem areas beyond the first one will be entirely past search_start, so checking against it in the loop is unnecessary.
2025-04-24 12:21:14 -07:00
squidbus
ce3aded3e5 fix: Intel crash on startup. 2025-04-23 11:09:04 -07:00
squidbus
4ecdcf77d1 build: Update MoltenVK ICD API version. 2025-04-23 09:58:00 -07:00
tlarok
3f4249084c
multikey for kbm_gui (#2778)
* Update kbm_gui.cpp

* Update kbm_gui.cpp

* Update kbm_gui.h

* Update kbm_gui.cpp

* lunix test

* linux test

* Update kbm_gui.h

* Update kbm_gui.cpp

* Update kbm_gui.cpp

* Update kbm_gui.cpp

* Update kbm_gui.cpp

* Update kbm_gui.h

* Update kbm_gui.cpp

* Update kbm_gui.h

* Update kbm_gui.cpp

* Update kbm_gui.h

* Update kbm_gui.cpp

* kbm_gui.cpp's names fix

just cleaning my code

* name fix

* Update kbm_gui.cpp

* Update kbm_gui.h

* Update kbm_gui.cpp

* Update src/qt_gui/kbm_gui.cpp

Co-authored-by: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com>

* clean up from main

* bruh, welp here we go again

---------

Co-authored-by: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com>
2025-04-23 13:41:14 +03:00
squidbus
aeee7706ee
renderer_vulkan: Restore Vulkan version to 1.3 (#2827)
Co-authored-by: georgemoralis <giorgosmrls@gmail.com>
2025-04-23 13:28:31 +03:00
georgemoralis
5db162cbcd started 0.8.1 WIP 2025-04-23 13:24:57 +03:00
449 changed files with 28745 additions and 10562 deletions

View File

@ -17,7 +17,7 @@ body:
This repository does not provide support for game patches. If you are having issues with patches please refer to [Cheats and Patches Repository](https://github.com/shadps4-emu/ps4_cheats). This repository does not provide support for game patches. If you are having issues with patches please refer to [Cheats and Patches Repository](https://github.com/shadps4-emu/ps4_cheats).
Before submitting an issue please check [Game Compatibility Repository](https://github.com/shadps4-emu/shadps4-game-compatibility) for the information about the status of the game. Before submitting an issue please check [Game Compatibility Repository](https://github.com/shadps4-compatibility/shadps4-game-compatibility) for the information about the status of the game.
Please make an effort to make sure your issue isn't already reported. Please make an effort to make sure your issue isn't already reported.
@ -35,7 +35,7 @@ body:
required: true required: true
- label: I have disabled all patches and cheats and the issue is still present. - label: I have disabled all patches and cheats and the issue is still present.
required: true required: true
- label: I have all the required [system modules](https://github.com/shadps4-emu/shadps4-game-compatibility?tab=readme-ov-file#informations) installed. - label: I have all the required [system modules](https://github.com/shadps4-emu/shadPS4/wiki/I.-Quick-start-%5BUsers%5D#4-adding-modules) installed.
required: true required: true
- type: textarea - type: textarea
id: desc id: desc

View File

@ -30,7 +30,7 @@ jobs:
- name: Install - name: Install
run: | run: |
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
sudo add-apt-repository 'deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-19 main' sudo add-apt-repository 'deb http://apt.llvm.org/noble/ llvm-toolchain-noble-19 main'
sudo apt update sudo apt update
sudo apt install clang-format-19 sudo apt install clang-format-19
- name: Build - name: Build
@ -76,18 +76,13 @@ jobs:
${{ env.cache-name }}- ${{ env.cache-name }}-
- name: Cache CMake Build - name: Cache CMake Build
uses: hendrikmuhs/ccache-action@v1.2.17 uses: hendrikmuhs/ccache-action@v1.2.18
env: env:
cache-name: ${{ runner.os }}-sdl-cache-cmake-build cache-name: ${{ runner.os }}-sdl-cache-cmake-build
with: with:
append-timestamp: false append-timestamp: false
key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }} key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}
- name: Setup VS Environment
uses: ilammy/msvc-dev-cmd@v1.13.0
with:
arch: amd64
- name: Configure CMake - name: Configure CMake
run: cmake --fresh -G Ninja -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE=ON -DCMAKE_C_COMPILER=clang-cl -DCMAKE_CXX_COMPILER=clang-cl -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache run: cmake --fresh -G Ninja -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE=ON -DCMAKE_C_COMPILER=clang-cl -DCMAKE_CXX_COMPILER=clang-cl -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
@ -111,7 +106,7 @@ jobs:
- name: Setup Qt - name: Setup Qt
uses: jurplel/install-qt-action@v4 uses: jurplel/install-qt-action@v4
with: with:
version: 6.9.0 version: 6.9.1
host: windows host: windows
target: desktop target: desktop
arch: win64_msvc2022_64 arch: win64_msvc2022_64
@ -130,18 +125,13 @@ jobs:
${{ env.cache-name }}- ${{ env.cache-name }}-
- name: Cache CMake Build - name: Cache CMake Build
uses: hendrikmuhs/ccache-action@v1.2.17 uses: hendrikmuhs/ccache-action@v1.2.18
env: env:
cache-name: ${{ runner.os }}-qt-cache-cmake-build cache-name: ${{ runner.os }}-qt-cache-cmake-build
with: with:
append-timestamp: false append-timestamp: false
key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }} key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}
- name: Setup VS Environment
uses: ilammy/msvc-dev-cmd@v1.13.0
with:
arch: amd64
- name: Configure CMake - name: Configure CMake
run: cmake --fresh -G Ninja -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DENABLE_QT_GUI=ON -DENABLE_UPDATER=ON -DCMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE=ON -DCMAKE_C_COMPILER=clang-cl -DCMAKE_CXX_COMPILER=clang-cl -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache run: cmake --fresh -G Ninja -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DENABLE_QT_GUI=ON -DENABLE_UPDATER=ON -DCMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE=ON -DCMAKE_C_COMPILER=clang-cl -DCMAKE_CXX_COMPILER=clang-cl -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
@ -186,7 +176,7 @@ jobs:
${{ env.cache-name }}- ${{ env.cache-name }}-
- name: Cache CMake Build - name: Cache CMake Build
uses: hendrikmuhs/ccache-action@v1.2.17 uses: hendrikmuhs/ccache-action@v1.2.18
env: env:
cache-name: ${{runner.os}}-sdl-cache-cmake-build cache-name: ${{runner.os}}-sdl-cache-cmake-build
with: with:
@ -228,13 +218,16 @@ jobs:
- name: Setup Qt - name: Setup Qt
uses: jurplel/install-qt-action@v4 uses: jurplel/install-qt-action@v4
with: with:
version: 6.9.0 version: 6.9.1
host: mac host: mac
target: desktop target: desktop
arch: clang_64 arch: clang_64
archives: qtbase qttools archives: qtbase qttools
modules: qtmultimedia modules: qtmultimedia
- name: Workaround Qt <=6.9.1 issue
run: sed -i '' '/target_link_libraries(WrapOpenGL::WrapOpenGL INTERFACE ${__opengl_agl_fw_path})/d' ${{env.QT_ROOT_DIR}}/lib/cmake/Qt6/FindWrapOpenGL.cmake
- name: Cache CMake Configuration - name: Cache CMake Configuration
uses: actions/cache@v4 uses: actions/cache@v4
env: env:
@ -247,7 +240,7 @@ jobs:
${{ env.cache-name }}- ${{ env.cache-name }}-
- name: Cache CMake Build - name: Cache CMake Build
uses: hendrikmuhs/ccache-action@v1.2.17 uses: hendrikmuhs/ccache-action@v1.2.18
env: env:
cache-name: ${{runner.os}}-qt-cache-cmake-build cache-name: ${{runner.os}}-qt-cache-cmake-build
with: with:
@ -281,8 +274,13 @@ jobs:
with: with:
submodules: recursive submodules: recursive
- name: Add LLVM repository
run: |
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
sudo add-apt-repository 'deb http://apt.llvm.org/noble/ llvm-toolchain-noble-19 main'
- name: Install dependencies - name: Install dependencies
run: sudo apt-get update && sudo apt install -y libx11-dev libxext-dev libwayland-dev libdecor-0-dev libxkbcommon-dev libglfw3-dev libgles2-mesa-dev libfuse2 clang build-essential libasound2-dev libpulse-dev libopenal-dev libudev-dev run: sudo apt-get update && sudo apt install -y libx11-dev libxext-dev libwayland-dev libdecor-0-dev libxkbcommon-dev libglfw3-dev libgles2-mesa-dev libfuse2 clang-19 mold build-essential libasound2-dev libpulse-dev libopenal-dev libudev-dev
- name: Cache CMake Configuration - name: Cache CMake Configuration
uses: actions/cache@v4 uses: actions/cache@v4
@ -296,7 +294,7 @@ jobs:
${{ env.cache-name }}- ${{ env.cache-name }}-
- name: Cache CMake Build - name: Cache CMake Build
uses: hendrikmuhs/ccache-action@v1.2.17 uses: hendrikmuhs/ccache-action@v1.2.18
env: env:
cache-name: ${{ runner.os }}-sdl-cache-cmake-build cache-name: ${{ runner.os }}-sdl-cache-cmake-build
with: with:
@ -304,7 +302,7 @@ jobs:
key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }} key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}
- name: Configure CMake - name: Configure CMake
run: cmake --fresh -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE=ON -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache run: cmake --fresh -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE=ON -DCMAKE_C_COMPILER=clang-19 -DCMAKE_CXX_COMPILER=clang++-19 -DCMAKE_EXE_LINKER_FLAGS="-fuse-ld=mold" -DCMAKE_SHARED_LINKER_FLAGS="-fuse-ld=mold" -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
- name: Build - name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $(nproc) run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $(nproc)
@ -337,8 +335,13 @@ jobs:
with: with:
submodules: recursive submodules: recursive
- name: Add LLVM repository
run: |
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
sudo add-apt-repository 'deb http://apt.llvm.org/noble/ llvm-toolchain-noble-19 main'
- name: Install dependencies - name: Install dependencies
run: sudo apt-get update && sudo apt install -y libx11-dev libxext-dev libwayland-dev libdecor-0-dev libxkbcommon-dev libglfw3-dev libgles2-mesa-dev libfuse2 clang build-essential qt6-base-dev qt6-tools-dev qt6-multimedia-dev libasound2-dev libpulse-dev libopenal-dev libudev-dev run: sudo apt-get update && sudo apt install -y libx11-dev libxext-dev libwayland-dev libdecor-0-dev libxkbcommon-dev libglfw3-dev libgles2-mesa-dev libfuse2 clang-19 mold build-essential qt6-base-dev qt6-tools-dev qt6-multimedia-dev libasound2-dev libpulse-dev libopenal-dev libudev-dev
- name: Cache CMake Configuration - name: Cache CMake Configuration
uses: actions/cache@v4 uses: actions/cache@v4
@ -352,7 +355,7 @@ jobs:
${{ env.cache-name }}- ${{ env.cache-name }}-
- name: Cache CMake Build - name: Cache CMake Build
uses: hendrikmuhs/ccache-action@v1.2.17 uses: hendrikmuhs/ccache-action@v1.2.18
env: env:
cache-name: ${{ runner.os }}-qt-cache-cmake-build cache-name: ${{ runner.os }}-qt-cache-cmake-build
with: with:
@ -360,7 +363,7 @@ jobs:
key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }} key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}
- name: Configure CMake - name: Configure CMake
run: cmake --fresh -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE=ON -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DENABLE_QT_GUI=ON -DENABLE_UPDATER=ON -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache run: cmake --fresh -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE=ON -DCMAKE_C_COMPILER=clang-19 -DCMAKE_CXX_COMPILER=clang++-19 -DCMAKE_EXE_LINKER_FLAGS="-fuse-ld=mold" -DCMAKE_SHARED_LINKER_FLAGS="-fuse-ld=mold" -DENABLE_QT_GUI=ON -DENABLE_UPDATER=ON -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
- name: Build - name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $(nproc) run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $(nproc)
@ -385,7 +388,7 @@ jobs:
submodules: recursive submodules: recursive
- name: Install dependencies - name: Install dependencies
run: sudo apt-get update && sudo apt install -y libx11-dev libxext-dev libwayland-dev libdecor-0-dev libxkbcommon-dev libglfw3-dev libgles2-mesa-dev libfuse2 gcc-14 build-essential libasound2-dev libpulse-dev libopenal-dev libudev-dev run: sudo apt-get update && sudo apt install -y libx11-dev libxext-dev libwayland-dev libdecor-0-dev libxkbcommon-dev libglfw3-dev libgles2-mesa-dev libfuse2 gcc-14 mold build-essential libasound2-dev libpulse-dev libopenal-dev libudev-dev
- name: Cache CMake Configuration - name: Cache CMake Configuration
uses: actions/cache@v4 uses: actions/cache@v4
@ -399,7 +402,7 @@ jobs:
${{ env.cache-name }}- ${{ env.cache-name }}-
- name: Cache CMake Build - name: Cache CMake Build
uses: hendrikmuhs/ccache-action@v1.2.17 uses: hendrikmuhs/ccache-action@v1.2.18
env: env:
cache-name: ${{ runner.os }}-sdl-gcc-cache-cmake-build cache-name: ${{ runner.os }}-sdl-gcc-cache-cmake-build
with: with:
@ -407,7 +410,7 @@ jobs:
key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }} key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}
- name: Configure CMake - name: Configure CMake
run: cmake --fresh -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE=ON -DCMAKE_C_COMPILER=gcc-14 -DCMAKE_CXX_COMPILER=g++-14 -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache run: cmake --fresh -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE=ON -DCMAKE_C_COMPILER=gcc-14 -DCMAKE_CXX_COMPILER=g++-14 -DCMAKE_EXE_LINKER_FLAGS="-fuse-ld=mold" -DCMAKE_SHARED_LINKER_FLAGS="-fuse-ld=mold" -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
- name: Build - name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $(nproc) run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $(nproc)
@ -421,7 +424,7 @@ jobs:
submodules: recursive submodules: recursive
- name: Install dependencies - name: Install dependencies
run: sudo apt-get update && sudo apt install -y libx11-dev libxext-dev libwayland-dev libdecor-0-dev libxkbcommon-dev libglfw3-dev libgles2-mesa-dev libfuse2 gcc-14 build-essential qt6-base-dev qt6-tools-dev qt6-multimedia-dev libasound2-dev libpulse-dev libopenal-dev libudev-dev run: sudo apt-get update && sudo apt install -y libx11-dev libxext-dev libwayland-dev libdecor-0-dev libxkbcommon-dev libglfw3-dev libgles2-mesa-dev libfuse2 gcc-14 mold build-essential qt6-base-dev qt6-tools-dev qt6-multimedia-dev libasound2-dev libpulse-dev libopenal-dev libudev-dev
- name: Cache CMake Configuration - name: Cache CMake Configuration
uses: actions/cache@v4 uses: actions/cache@v4
@ -435,7 +438,7 @@ jobs:
${{ env.cache-name }}- ${{ env.cache-name }}-
- name: Cache CMake Build - name: Cache CMake Build
uses: hendrikmuhs/ccache-action@v1.2.17 uses: hendrikmuhs/ccache-action@v1.2.18
env: env:
cache-name: ${{ runner.os }}-qt-gcc-cache-cmake-build cache-name: ${{ runner.os }}-qt-gcc-cache-cmake-build
with: with:
@ -443,7 +446,7 @@ jobs:
key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }} key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}
- name: Configure CMake - name: Configure CMake
run: cmake --fresh -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE=ON -DCMAKE_C_COMPILER=gcc-14 -DCMAKE_CXX_COMPILER=g++-14 -DENABLE_QT_GUI=ON -DENABLE_UPDATER=ON -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache run: cmake --fresh -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE=ON -DCMAKE_C_COMPILER=gcc-14 -DCMAKE_CXX_COMPILER=g++-14 -DCMAKE_EXE_LINKER_FLAGS="-fuse-ld=mold" -DCMAKE_SHARED_LINKER_FLAGS="-fuse-ld=mold" -DENABLE_QT_GUI=ON -DENABLE_UPDATER=ON -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
- name: Build - name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $(nproc) run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $(nproc)
@ -484,7 +487,7 @@ jobs:
with: with:
token: ${{ secrets.SHADPS4_TOKEN_REPO }} token: ${{ secrets.SHADPS4_TOKEN_REPO }}
name: "Pre-release-shadPS4-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }}" name: "Pre-release-shadPS4-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }}"
tag: "Pre-release-shadPS4-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }}" tag: "Pre-release-shadPS4-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.fullhash }}"
draft: false draft: false
prerelease: true prerelease: true
body: "Full Changelog: [${{ env.last_release_tag }}...${{ needs.get-info.outputs.shorthash }}](https://github.com/shadps4-emu/shadPS4/compare/${{ env.last_release_tag }}...${{ needs.get-info.outputs.fullhash }})" body: "Full Changelog: [${{ env.last_release_tag }}...${{ needs.get-info.outputs.shorthash }}](https://github.com/shadps4-emu/shadPS4/compare/${{ env.last_release_tag }}...${{ needs.get-info.outputs.fullhash }})"
@ -520,14 +523,14 @@ jobs:
# Check if release already exists and get ID # Check if release already exists and get ID
release_id=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \ release_id=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \
"https://api.github.com/repos/$REPO/releases/tags/Pre-release-shadPS4-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }}" | jq -r '.id') "https://api.github.com/repos/$REPO/releases/tags/Pre-release-shadPS4-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.fullhash }}" | jq -r '.id')
if [[ "$release_id" == "null" ]]; then if [[ "$release_id" == "null" ]]; then
echo "Creating release in $REPO for $filename" echo "Creating release in $REPO for $filename"
release_id=$(curl -s -X POST -H "Authorization: token $GITHUB_TOKEN" \ release_id=$(curl -s -X POST -H "Authorization: token $GITHUB_TOKEN" \
-H "Accept: application/vnd.github.v3+json" \ -H "Accept: application/vnd.github.v3+json" \
-d '{ -d '{
"tag_name": "Pre-release-shadPS4-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }}", "tag_name": "Pre-release-shadPS4-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.fullhash }}",
"name": "Pre-release-shadPS4-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }}", "name": "Pre-release-shadPS4-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }}",
"draft": false, "draft": false,
"prerelease": true, "prerelease": true,

10
.gitmodules vendored
View File

@ -30,10 +30,6 @@
path = externals/xbyak path = externals/xbyak
url = https://github.com/herumi/xbyak.git url = https://github.com/herumi/xbyak.git
shallow = true shallow = true
[submodule "externals/winpthreads"]
path = externals/winpthreads
url = https://github.com/shadps4-emu/winpthreads.git
shallow = true
[submodule "externals/magic_enum"] [submodule "externals/magic_enum"]
path = externals/magic_enum path = externals/magic_enum
url = https://github.com/Neargye/magic_enum.git url = https://github.com/Neargye/magic_enum.git
@ -107,6 +103,6 @@
path = externals/MoltenVK/cereal path = externals/MoltenVK/cereal
url = https://github.com/USCiLab/cereal url = https://github.com/USCiLab/cereal
shallow = true shallow = true
[submodule "externals/libusb"] [submodule "externals/ext-libusb"]
path = externals/libusb path = externals/ext-libusb
url = https://github.com/libusb/libusb-cmake.git url = https://github.com/shadps4-emu/ext-libusb.git

21
CMakeLinuxPresets.json Normal file
View File

@ -0,0 +1,21 @@
{
"version": 9,
"cmakeMinimumRequired": {
"major": 3,
"minor": 30,
"patch": 0
},
"configurePresets": [
{
"name": "x64-Clang-Base",
"hidden": true,
"generator": "Ninja",
"binaryDir": "${sourceDir}/Build/${presetName}",
"cacheVariables": {
"CMAKE_C_COMPILER": "clang",
"CMAKE_CXX_COMPILER": "clang++",
"CMAKE_INSTALL_PREFIX": "${sourceDir}/Build/${presetName}"
}
}
]
}

164
CMakeLists.txt Executable file → Normal file
View File

@ -54,9 +54,9 @@ else()
endif() endif()
if (ARCHITECTURE STREQUAL "x86_64") if (ARCHITECTURE STREQUAL "x86_64")
# Target the same CPU architecture as the PS4, to maintain the same level of compatibility. # Target x86-64-v3 CPU architecture as this is a good balance between supporting performance critical
# Exclude SSE4a as it is only available on AMD CPUs. # instructions like AVX2 and maintaining support for older CPUs.
add_compile_options(-march=btver2 -mtune=generic -mno-sse4a) add_compile_options(-march=x86-64-v3)
endif() endif()
if (APPLE AND ARCHITECTURE STREQUAL "x86_64" AND CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "arm64") if (APPLE AND ARCHITECTURE STREQUAL "x86_64" AND CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "arm64")
@ -126,7 +126,7 @@ execute_process(
# If there's no upstream set or the command failed, check remote.pushDefault # If there's no upstream set or the command failed, check remote.pushDefault
if (GIT_REMOTE_RESULT OR GIT_REMOTE_NAME STREQUAL "") if (GIT_REMOTE_RESULT OR GIT_REMOTE_NAME STREQUAL "")
message("check default push") message(STATUS "check default push")
execute_process( execute_process(
COMMAND git config --get remote.pushDefault COMMAND git config --get remote.pushDefault
OUTPUT_VARIABLE GIT_REMOTE_NAME OUTPUT_VARIABLE GIT_REMOTE_NAME
@ -134,29 +134,30 @@ if (GIT_REMOTE_RESULT OR GIT_REMOTE_NAME STREQUAL "")
ERROR_QUIET ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_STRIP_TRAILING_WHITESPACE
) )
message(STATUS "got remote: ${GIT_REMOTE_NAME}")
endif() endif()
# If running in GitHub Actions and the above fails # If running in GitHub Actions and the above fails
if (GIT_REMOTE_RESULT OR GIT_REMOTE_NAME STREQUAL "") if (GIT_REMOTE_RESULT OR GIT_REMOTE_NAME STREQUAL "")
message("check github") message(STATUS "check github")
set(GIT_REMOTE_NAME "origin") set(GIT_REMOTE_NAME "origin")
# Retrieve environment variables # Retrieve environment variables
if (DEFINED ENV{GITHUB_HEAD_REF} AND NOT "$ENV{GITHUB_HEAD_REF}" STREQUAL "") if (DEFINED ENV{GITHUB_HEAD_REF} AND NOT "$ENV{GITHUB_HEAD_REF}" STREQUAL "")
message("github head ref: $ENV{GITHUB_HEAD_REF}") message(STATUS "github head ref: $ENV{GITHUB_HEAD_REF}")
set(GITHUB_HEAD_REF "$ENV{GITHUB_HEAD_REF}") set(GITHUB_HEAD_REF "$ENV{GITHUB_HEAD_REF}")
else() else()
set(GITHUB_HEAD_REF "") set(GITHUB_HEAD_REF "")
endif() endif()
if (DEFINED ENV{GITHUB_REF} AND NOT "$ENV{GITHUB_REF}" STREQUAL "") if (DEFINED ENV{GITHUB_REF} AND NOT "$ENV{GITHUB_REF}" STREQUAL "")
message("github ref: $ENV{GITHUB_REF}") message(STATUS "github ref: $ENV{GITHUB_REF}")
string(REGEX REPLACE "^refs/[^/]*/" "" GITHUB_BRANCH "$ENV{GITHUB_REF}") string(REGEX REPLACE "^refs/[^/]*/" "" GITHUB_BRANCH "$ENV{GITHUB_REF}")
string(REGEX MATCH "refs/pull/([0-9]+)/merge" MATCHED_REF "$ENV{GITHUB_REF}") string(REGEX MATCH "refs/pull/([0-9]+)/merge" MATCHED_REF "$ENV{GITHUB_REF}")
if (MATCHED_REF) if (MATCHED_REF)
set(PR_NUMBER "${CMAKE_MATCH_1}") set(PR_NUMBER "${CMAKE_MATCH_1}")
set(GITHUB_BRANCH "") set(GITHUB_BRANCH "")
message("PR number: ${PR_NUMBER}") message(STATUS "PR number: ${PR_NUMBER}")
else() else()
set(PR_NUMBER "") set(PR_NUMBER "")
endif() endif()
@ -177,8 +178,8 @@ if (GIT_REMOTE_RESULT OR GIT_REMOTE_NAME STREQUAL "")
set(GIT_BRANCH "${GITHUB_BRANCH}") set(GIT_BRANCH "${GITHUB_BRANCH}")
elseif ("${PR_NUMBER}" STREQUAL "" AND NOT "${GITHUB_REF}" STREQUAL "") elseif ("${PR_NUMBER}" STREQUAL "" AND NOT "${GITHUB_REF}" STREQUAL "")
set(GIT_BRANCH "${GITHUB_REF}") set(GIT_BRANCH "${GITHUB_REF}")
else() elseif("${GIT_BRANCH}" STREQUAL "")
message("couldn't find branch") message(STATUS "couldn't find branch")
set(GIT_BRANCH "detached-head") set(GIT_BRANCH "detached-head")
endif() endif()
else() else()
@ -186,14 +187,14 @@ else()
string(FIND "${GIT_REMOTE_NAME}" "/" INDEX) string(FIND "${GIT_REMOTE_NAME}" "/" INDEX)
if (INDEX GREATER -1) if (INDEX GREATER -1)
string(SUBSTRING "${GIT_REMOTE_NAME}" 0 "${INDEX}" GIT_REMOTE_NAME) string(SUBSTRING "${GIT_REMOTE_NAME}" 0 "${INDEX}" GIT_REMOTE_NAME)
else() elseif("${GIT_REMOTE_NAME}" STREQUAL "")
# If no remote is present (only a branch name), default to origin message(STATUS "reset to origin")
set(GIT_REMOTE_NAME "origin") set(GIT_REMOTE_NAME "origin")
endif() endif()
endif() endif()
# Get remote link # Get remote link
message("getting remote link") message(STATUS "getting remote link")
execute_process( execute_process(
COMMAND git config --get remote.${GIT_REMOTE_NAME}.url COMMAND git config --get remote.${GIT_REMOTE_NAME}.url
OUTPUT_VARIABLE GIT_REMOTE_URL OUTPUT_VARIABLE GIT_REMOTE_URL
@ -202,16 +203,26 @@ execute_process(
# Set Version # Set Version
set(EMULATOR_VERSION_MAJOR "0") set(EMULATOR_VERSION_MAJOR "0")
set(EMULATOR_VERSION_MINOR "8") set(EMULATOR_VERSION_MINOR "10")
set(EMULATOR_VERSION_PATCH "0") set(EMULATOR_VERSION_PATCH "1")
set_source_files_properties(src/shadps4.rc PROPERTIES COMPILE_DEFINITIONS "EMULATOR_VERSION_MAJOR=${EMULATOR_VERSION_MAJOR};EMULATOR_VERSION_MINOR=${EMULATOR_VERSION_MINOR};EMULATOR_VERSION_PATCH=${EMULATOR_VERSION_PATCH}") set_source_files_properties(src/shadps4.rc PROPERTIES COMPILE_DEFINITIONS "EMULATOR_VERSION_MAJOR=${EMULATOR_VERSION_MAJOR};EMULATOR_VERSION_MINOR=${EMULATOR_VERSION_MINOR};EMULATOR_VERSION_PATCH=${EMULATOR_VERSION_PATCH}")
set(APP_VERSION "${EMULATOR_VERSION_MAJOR}.${EMULATOR_VERSION_MINOR}.${EMULATOR_VERSION_PATCH}") set(APP_VERSION "${EMULATOR_VERSION_MAJOR}.${EMULATOR_VERSION_MINOR}.${EMULATOR_VERSION_PATCH} WIP")
set(APP_IS_RELEASE true) set(APP_IS_RELEASE false)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/common/scm_rev.cpp.in" "${CMAKE_CURRENT_BINARY_DIR}/src/common/scm_rev.cpp" @ONLY) configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/common/scm_rev.cpp.in" "${CMAKE_CURRENT_BINARY_DIR}/src/common/scm_rev.cpp" @ONLY)
message("end git things, remote: ${GIT_REMOTE_NAME}, branch: ${GIT_BRANCH}") message("-- end git things, remote: ${GIT_REMOTE_NAME}, branch: ${GIT_BRANCH}, link: ${GIT_REMOTE_URL}")
string(TOLOWER "${GIT_REMOTE_URL}" GIT_REMOTE_URL_LOWER)
if(NOT GIT_REMOTE_URL_LOWER MATCHES "shadps4-emu/shadps4" OR NOT GIT_BRANCH STREQUAL "main")
message(STATUS "not main, disabling auto update")
set(ENABLE_UPDATER OFF)
endif()
if(WIN32 AND ENABLE_QT_GUI AND NOT CMAKE_PREFIX_PATH)
include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/DetectQtInstallation.cmake")
endif ()
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
find_package(Boost 1.84.0 CONFIG) find_package(Boost 1.84.0 CONFIG)
@ -226,26 +237,18 @@ find_package(SDL3 3.1.2 CONFIG)
find_package(stb MODULE) find_package(stb MODULE)
find_package(toml11 4.2.0 CONFIG) find_package(toml11 4.2.0 CONFIG)
find_package(tsl-robin-map 1.3.0 CONFIG) find_package(tsl-robin-map 1.3.0 CONFIG)
find_package(VulkanHeaders 1.4.309 CONFIG) find_package(VulkanHeaders 1.4.314 CONFIG)
find_package(VulkanMemoryAllocator 3.1.0 CONFIG) find_package(VulkanMemoryAllocator 3.1.0 CONFIG)
find_package(xbyak 7.07 CONFIG) find_package(xbyak 7.07 CONFIG)
find_package(xxHash 0.8.2 MODULE) find_package(xxHash 0.8.2 MODULE)
find_package(ZLIB 1.3 MODULE) find_package(ZLIB 1.3 MODULE)
find_package(Zydis 5.0.0 CONFIG) find_package(Zydis 5.0.0 CONFIG)
find_package(pugixml 1.14 CONFIG) find_package(pugixml 1.14 CONFIG)
find_package(libusb 1.0.27 MODULE)
if (APPLE) if (APPLE)
find_package(date 3.0.1 CONFIG) find_package(date 3.0.1 CONFIG)
endif() endif()
list(POP_BACK CMAKE_MODULE_PATH) list(POP_BACK CMAKE_MODULE_PATH)
# Note: Windows always has these functions through winpthreads
include(CheckSymbolExists)
check_symbol_exists(pthread_mutex_timedlock "pthread.h" HAVE_PTHREAD_MUTEX_TIMEDLOCK)
if(HAVE_PTHREAD_MUTEX_TIMEDLOCK OR WIN32)
add_compile_options(-DHAVE_PTHREAD_MUTEX_TIMEDLOCK)
endif()
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
# libc++ requires -fexperimental-library to enable std::jthread and std::stop_token support. # libc++ requires -fexperimental-library to enable std::jthread and std::stop_token support.
include(CheckCXXSymbolExists) include(CheckCXXSymbolExists)
@ -257,7 +260,6 @@ endif()
add_subdirectory(externals) add_subdirectory(externals)
include_directories(src) include_directories(src)
include_directories(Resources)
if(ENABLE_QT_GUI) if(ENABLE_QT_GUI)
find_package(Qt6 REQUIRED COMPONENTS Widgets Concurrent LinguistTools Network Multimedia) find_package(Qt6 REQUIRED COMPONENTS Widgets Concurrent LinguistTools Network Multimedia)
@ -302,6 +304,10 @@ set(AJM_LIB src/core/libraries/ajm/ajm.cpp
set(AUDIO_LIB src/core/libraries/audio/audioin.cpp set(AUDIO_LIB src/core/libraries/audio/audioin.cpp
src/core/libraries/audio/audioin.h src/core/libraries/audio/audioin.h
src/core/libraries/audio/sdl_in.h
src/core/libraries/audio/sdl_in.cpp
src/core/libraries/voice/voice.cpp
src/core/libraries/voice/voice.h
src/core/libraries/audio/audioout.cpp src/core/libraries/audio/audioout.cpp
src/core/libraries/audio/audioout.h src/core/libraries/audio/audioout.h
src/core/libraries/audio/audioout_backend.h src/core/libraries/audio/audioout_backend.h
@ -371,11 +377,19 @@ set(NETWORK_LIBS src/core/libraries/network/http.cpp
src/core/libraries/network/net_ctl_obj.cpp src/core/libraries/network/net_ctl_obj.cpp
src/core/libraries/network/net_ctl_obj.h src/core/libraries/network/net_ctl_obj.h
src/core/libraries/network/net_ctl_codes.h src/core/libraries/network/net_ctl_codes.h
src/core/libraries/network/net_util.cpp
src/core/libraries/network/net_util.h
src/core/libraries/network/net_error.h
src/core/libraries/network/net.h src/core/libraries/network/net.h
src/core/libraries/network/ssl.cpp src/core/libraries/network/ssl.cpp
src/core/libraries/network/ssl.h src/core/libraries/network/ssl.h
src/core/libraries/network/ssl2.cpp src/core/libraries/network/ssl2.cpp
src/core/libraries/network/ssl2.h src/core/libraries/network/ssl2.h
src/core/libraries/network/sys_net.cpp
src/core/libraries/network/sys_net.h
src/core/libraries/network/posix_sockets.cpp
src/core/libraries/network/p2p_sockets.cpp
src/core/libraries/network/sockets.h
) )
set(AVPLAYER_LIB src/core/libraries/avplayer/avplayer_common.cpp set(AVPLAYER_LIB src/core/libraries/avplayer/avplayer_common.cpp
@ -408,6 +422,7 @@ set(SYSTEM_LIBS src/core/libraries/system/commondialog.cpp
src/core/libraries/save_data/save_memory.h src/core/libraries/save_data/save_memory.h
src/core/libraries/save_data/savedata.cpp src/core/libraries/save_data/savedata.cpp
src/core/libraries/save_data/savedata.h src/core/libraries/save_data/savedata.h
src/core/libraries/save_data/savedata_error.h
src/core/libraries/save_data/dialog/savedatadialog.cpp src/core/libraries/save_data/dialog/savedatadialog.cpp
src/core/libraries/save_data/dialog/savedatadialog.h src/core/libraries/save_data/dialog/savedatadialog.h
src/core/libraries/save_data/dialog/savedatadialog_ui.cpp src/core/libraries/save_data/dialog/savedatadialog_ui.cpp
@ -589,8 +604,21 @@ set(MISC_LIBS src/core/libraries/screenshot/screenshot.cpp
src/core/libraries/move/move.h src/core/libraries/move/move.h
src/core/libraries/ulobjmgr/ulobjmgr.cpp src/core/libraries/ulobjmgr/ulobjmgr.cpp
src/core/libraries/ulobjmgr/ulobjmgr.h src/core/libraries/ulobjmgr/ulobjmgr.h
src/core/libraries/signin_dialog/signindialog.cpp
src/core/libraries/signin_dialog/signindialog.h
) )
set(CAMERA_LIBS src/core/libraries/camera/camera.cpp
src/core/libraries/camera/camera.h
src/core/libraries/camera/camera_error.h
)
set(COMPANION_LIBS src/core/libraries/companion/companion_httpd.cpp
src/core/libraries/companion/companion_httpd.h
src/core/libraries/companion/companion_util.cpp
src/core/libraries/companion/companion_util.h
src/core/libraries/companion/companion_error.h
)
set(DEV_TOOLS src/core/devtools/layer.cpp set(DEV_TOOLS src/core/devtools/layer.cpp
src/core/devtools/layer.h src/core/devtools/layer.h
src/core/devtools/options.cpp src/core/devtools/options.cpp
@ -608,6 +636,8 @@ set(DEV_TOOLS src/core/devtools/layer.cpp
src/core/devtools/widget/imgui_memory_editor.h src/core/devtools/widget/imgui_memory_editor.h
src/core/devtools/widget/memory_map.cpp src/core/devtools/widget/memory_map.cpp
src/core/devtools/widget/memory_map.h src/core/devtools/widget/memory_map.h
src/core/devtools/widget/module_list.cpp
src/core/devtools/widget/module_list.h
src/core/devtools/widget/reg_popup.cpp src/core/devtools/widget/reg_popup.cpp
src/core/devtools/widget/reg_popup.h src/core/devtools/widget/reg_popup.h
src/core/devtools/widget/reg_view.cpp src/core/devtools/widget/reg_view.cpp
@ -633,6 +663,7 @@ set(COMMON src/common/logging/backend.cpp
src/common/arch.h src/common/arch.h
src/common/assert.cpp src/common/assert.cpp
src/common/assert.h src/common/assert.h
src/common/bit_array.h
src/common/bit_field.h src/common/bit_field.h
src/common/bounded_threadsafe_queue.h src/common/bounded_threadsafe_queue.h
src/common/concepts.h src/common/concepts.h
@ -658,9 +689,13 @@ set(COMMON src/common/logging/backend.cpp
src/common/path_util.h src/common/path_util.h
src/common/object_pool.h src/common/object_pool.h
src/common/polyfill_thread.h src/common/polyfill_thread.h
src/common/range_lock.h
src/common/rdtsc.cpp src/common/rdtsc.cpp
src/common/rdtsc.h src/common/rdtsc.h
src/common/recursive_lock.cpp
src/common/recursive_lock.h
src/common/sha1.h src/common/sha1.h
src/common/shared_first_mutex.h
src/common/signal_context.h src/common/signal_context.h
src/common/signal_context.cpp src/common/signal_context.cpp
src/common/singleton.h src/common/singleton.h
@ -754,6 +789,8 @@ set(CORE src/core/aerolib/stubs.cpp
${FIBER_LIB} ${FIBER_LIB}
${VDEC_LIB} ${VDEC_LIB}
${VR_LIBS} ${VR_LIBS}
${CAMERA_LIBS}
${COMPANION_LIBS}
${DEV_TOOLS} ${DEV_TOOLS}
src/core/debug_state.cpp src/core/debug_state.cpp
src/core/debug_state.h src/core/debug_state.h
@ -840,13 +877,16 @@ set(SHADER_RECOMPILER src/shader_recompiler/exception.h
src/shader_recompiler/ir/passes/identity_removal_pass.cpp src/shader_recompiler/ir/passes/identity_removal_pass.cpp
src/shader_recompiler/ir/passes/ir_passes.h src/shader_recompiler/ir/passes/ir_passes.h
src/shader_recompiler/ir/passes/lower_buffer_format_to_raw.cpp src/shader_recompiler/ir/passes/lower_buffer_format_to_raw.cpp
src/shader_recompiler/ir/passes/lower_fp64_to_fp32.cpp
src/shader_recompiler/ir/passes/readlane_elimination_pass.cpp src/shader_recompiler/ir/passes/readlane_elimination_pass.cpp
src/shader_recompiler/ir/passes/resource_tracking_pass.cpp src/shader_recompiler/ir/passes/resource_tracking_pass.cpp
src/shader_recompiler/ir/passes/ring_access_elimination.cpp src/shader_recompiler/ir/passes/ring_access_elimination.cpp
src/shader_recompiler/ir/passes/shader_info_collection_pass.cpp src/shader_recompiler/ir/passes/shader_info_collection_pass.cpp
src/shader_recompiler/ir/passes/shared_memory_barrier_pass.cpp src/shader_recompiler/ir/passes/shared_memory_barrier_pass.cpp
src/shader_recompiler/ir/passes/shared_memory_simplify_pass.cpp
src/shader_recompiler/ir/passes/shared_memory_to_storage_pass.cpp src/shader_recompiler/ir/passes/shared_memory_to_storage_pass.cpp
src/shader_recompiler/ir/passes/ssa_rewrite_pass.cpp src/shader_recompiler/ir/passes/ssa_rewrite_pass.cpp
src/shader_recompiler/ir/abstract_syntax_list.cpp
src/shader_recompiler/ir/abstract_syntax_list.h src/shader_recompiler/ir/abstract_syntax_list.h
src/shader_recompiler/ir/attribute.cpp src/shader_recompiler/ir/attribute.cpp
src/shader_recompiler/ir/attribute.h src/shader_recompiler/ir/attribute.h
@ -886,9 +926,10 @@ set(VIDEO_CORE src/video_core/amdgpu/liverpool.cpp
src/video_core/buffer_cache/buffer.h src/video_core/buffer_cache/buffer.h
src/video_core/buffer_cache/buffer_cache.cpp src/video_core/buffer_cache/buffer_cache.cpp
src/video_core/buffer_cache/buffer_cache.h src/video_core/buffer_cache/buffer_cache.h
src/video_core/buffer_cache/memory_tracker_base.h src/video_core/buffer_cache/memory_tracker.h
src/video_core/buffer_cache/range_set.h src/video_core/buffer_cache/range_set.h
src/video_core/buffer_cache/word_manager.h src/video_core/buffer_cache/region_definitions.h
src/video_core/buffer_cache/region_manager.h
src/video_core/renderer_vulkan/liverpool_to_vk.cpp src/video_core/renderer_vulkan/liverpool_to_vk.cpp
src/video_core/renderer_vulkan/liverpool_to_vk.h src/video_core/renderer_vulkan/liverpool_to_vk.h
src/video_core/renderer_vulkan/vk_common.cpp src/video_core/renderer_vulkan/vk_common.cpp
@ -925,6 +966,10 @@ set(VIDEO_CORE src/video_core/amdgpu/liverpool.cpp
src/video_core/renderer_vulkan/host_passes/fsr_pass.h src/video_core/renderer_vulkan/host_passes/fsr_pass.h
src/video_core/renderer_vulkan/host_passes/pp_pass.cpp src/video_core/renderer_vulkan/host_passes/pp_pass.cpp
src/video_core/renderer_vulkan/host_passes/pp_pass.h src/video_core/renderer_vulkan/host_passes/pp_pass.h
src/video_core/texture_cache/blit_helper.cpp
src/video_core/texture_cache/blit_helper.h
src/video_core/texture_cache/host_compatibility.cpp
src/video_core/texture_cache/host_compatibility.h
src/video_core/texture_cache/image.cpp src/video_core/texture_cache/image.cpp
src/video_core/texture_cache/image.h src/video_core/texture_cache/image.h
src/video_core/texture_cache/image_info.cpp src/video_core/texture_cache/image_info.cpp
@ -938,7 +983,6 @@ set(VIDEO_CORE src/video_core/amdgpu/liverpool.cpp
src/video_core/texture_cache/tile_manager.cpp src/video_core/texture_cache/tile_manager.cpp
src/video_core/texture_cache/tile_manager.h src/video_core/texture_cache/tile_manager.h
src/video_core/texture_cache/types.h src/video_core/texture_cache/types.h
src/video_core/texture_cache/host_compatibility.h
src/video_core/page_manager.cpp src/video_core/page_manager.cpp
src/video_core/page_manager.h src/video_core/page_manager.h
src/video_core/multi_level_page_table.h src/video_core/multi_level_page_table.h
@ -1027,6 +1071,12 @@ set(QT_GUI src/qt_gui/about_dialog.cpp
src/qt_gui/settings_dialog.h src/qt_gui/settings_dialog.h
src/qt_gui/settings_dialog.ui src/qt_gui/settings_dialog.ui
src/qt_gui/main.cpp src/qt_gui/main.cpp
src/qt_gui/gui_settings.cpp
src/qt_gui/gui_settings.h
src/qt_gui/settings.cpp
src/qt_gui/settings.h
src/qt_gui/sdl_event_wrapper.cpp
src/qt_gui/sdl_event_wrapper.h
${EMULATOR} ${EMULATOR}
${RESOURCE_FILES} ${RESOURCE_FILES}
${TRANSLATIONS} ${TRANSLATIONS}
@ -1077,57 +1127,56 @@ if (ENABLE_DISCORD_RPC)
target_compile_definitions(shadps4 PRIVATE ENABLE_DISCORD_RPC) target_compile_definitions(shadps4 PRIVATE ENABLE_DISCORD_RPC)
endif() endif()
# Optional due to https://github.com/shadps4-emu/shadPS4/issues/1704 if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" AND ENABLE_USERFAULTFD) # Optional due to https://github.com/shadps4-emu/shadPS4/issues/1704
target_compile_definitions(shadps4 PRIVATE ENABLE_USERFAULTFD) if (ENABLE_USERFAULTFD)
target_compile_definitions(shadps4 PRIVATE ENABLE_USERFAULTFD)
endif()
target_link_libraries(shadps4 PRIVATE uuid)
endif() endif()
if (APPLE) if (APPLE)
# Include MoltenVK, along with an ICD file so it can be found by the system Vulkan loader if used for loading layers. # Include MoltenVK, along with an ICD file so it can be found by the system Vulkan loader if used for loading layers.
set(MVK_DYLIB_SRC ${CMAKE_CURRENT_BINARY_DIR}/externals/MoltenVK/libMoltenVK.dylib)
if (ENABLE_QT_GUI) if (ENABLE_QT_GUI)
set_property(TARGET shadps4 APPEND PROPERTY BUILD_RPATH "@executable_path/../Frameworks") set(MVK_BUNDLE_PATH "Resources/vulkan/icd.d")
set(MVK_ICD_DST ${CMAKE_CURRENT_BINARY_DIR}/shadps4.app/Contents/Resources/vulkan/icd.d/MoltenVK_icd.json) set_property(TARGET shadps4 APPEND PROPERTY BUILD_RPATH "@executable_path/../${MVK_BUNDLE_PATH}")
set(MVK_DYLIB_DST ${CMAKE_CURRENT_BINARY_DIR}/shadps4.app/Contents/Frameworks/libMoltenVK.dylib) set(MVK_DST ${CMAKE_CURRENT_BINARY_DIR}/shadps4.app/Contents/${MVK_BUNDLE_PATH})
set(MVK_DYLIB_ICD_PATH "../../../Frameworks/libMoltenVK.dylib")
add_custom_command(
OUTPUT ${MVK_DST}
COMMAND ${CMAKE_COMMAND} -E make_directory ${MVK_DST})
else() else()
set_property(TARGET shadps4 APPEND PROPERTY BUILD_RPATH "@executable_path") set_property(TARGET shadps4 APPEND PROPERTY BUILD_RPATH "@executable_path")
set(MVK_ICD_DST ${CMAKE_CURRENT_BINARY_DIR}/MoltenVK_icd.json) set(MVK_DST ${CMAKE_CURRENT_BINARY_DIR})
set(MVK_DYLIB_DST ${CMAKE_CURRENT_BINARY_DIR}/libMoltenVK.dylib)
set(MVK_DYLIB_ICD_PATH "./libMoltenVK.dylib")
endif() endif()
cmake_path(GET MVK_ICD_DST PARENT_PATH MVK_ICD_DST_PARENT) set(MVK_DYLIB_SRC ${CMAKE_CURRENT_BINARY_DIR}/externals/MoltenVK/libMoltenVK.dylib)
cmake_path(GET MVK_DYLIB_DST PARENT_PATH MVK_DYLIB_DST_PARENT) set(MVK_DYLIB_DST ${MVK_DST}/libMoltenVK.dylib)
set(MVK_ICD_SRC ${CMAKE_CURRENT_SOURCE_DIR}/externals/MoltenVK/MoltenVK/MoltenVK/icd/MoltenVK_icd.json)
set(MVK_ICD_DST ${MVK_DST}/MoltenVK_icd.json)
set(MVK_ICD "\\\{ \\\"file_format_version\\\": \\\"1.0.0\\\", \\\"ICD\\\": \\\{ \\\"library_path\\\": \\\"${MVK_DYLIB_ICD_PATH}\\\", \\\"api_version\\\": \\\"1.2.0\\\", \\\"is_portability_driver\\\": true \\\} \\\}")
add_custom_command( add_custom_command(
OUTPUT ${MVK_ICD_DST} OUTPUT ${MVK_ICD_DST}
COMMAND ${CMAKE_COMMAND} -E make_directory ${MVK_ICD_DST_PARENT} && ${CMAKE_COMMAND} -E echo ${MVK_ICD} > ${MVK_ICD_DST}) DEPENDS ${MVK_ICD_SRC} ${MVK_DST}
COMMAND ${CMAKE_COMMAND} -E copy ${MVK_ICD_SRC} ${MVK_ICD_DST})
add_custom_command( add_custom_command(
OUTPUT ${MVK_DYLIB_DST} OUTPUT ${MVK_DYLIB_DST}
DEPENDS ${MVK_DYLIB_SRC} DEPENDS ${MVK_DYLIB_SRC} ${MVK_DST}
COMMAND ${CMAKE_COMMAND} -E make_directory ${MVK_DYLIB_DST_PARENT} && ${CMAKE_COMMAND} -E copy ${MVK_DYLIB_SRC} ${MVK_DYLIB_DST}) COMMAND ${CMAKE_COMMAND} -E copy ${MVK_DYLIB_SRC} ${MVK_DYLIB_DST})
add_custom_target(CopyMoltenVK DEPENDS ${MVK_ICD_DST} ${MVK_DYLIB_DST}) add_custom_target(CopyMoltenVK DEPENDS ${MVK_ICD_DST} ${MVK_DYLIB_DST})
add_dependencies(CopyMoltenVK MoltenVK) add_dependencies(CopyMoltenVK MoltenVK)
add_dependencies(shadps4 CopyMoltenVK) add_dependencies(shadps4 CopyMoltenVK)
if (ARCHITECTURE STREQUAL "x86_64") if (ARCHITECTURE STREQUAL "x86_64")
# Reserve system-managed memory space. # Reserve system-managed memory space.
target_link_options(shadps4 PRIVATE -Wl,-no_pie,-no_fixup_chains,-no_huge,-pagezero_size,0x4000,-segaddr,TCB_SPACE,0x4000,-segaddr,SYSTEM_MANAGED,0x400000,-segaddr,SYSTEM_RESERVED,0x7FFFFC000,-image_base,0x20000000000) target_link_options(shadps4 PRIVATE -Wl,-ld_classic,-no_pie,-no_fixup_chains,-no_huge,-pagezero_size,0x4000,-segaddr,TCB_SPACE,0x4000,-segaddr,SYSTEM_MANAGED,0x400000,-segaddr,SYSTEM_RESERVED,0x7FFFFC000,-image_base,0x20000000000)
endif() endif()
# Replacement for std::chrono::time_zone # Replacement for std::chrono::time_zone
target_link_libraries(shadps4 PRIVATE date::date-tz) target_link_libraries(shadps4 PRIVATE date::date-tz)
endif() endif()
if (NOT ENABLE_QT_GUI)
target_link_libraries(shadps4 PRIVATE SDL3::SDL3)
endif()
if (ENABLE_QT_GUI) if (ENABLE_QT_GUI)
target_link_libraries(shadps4 PRIVATE Qt6::Widgets Qt6::Concurrent Qt6::Network Qt6::Multimedia) target_link_libraries(shadps4 PRIVATE Qt6::Widgets Qt6::Concurrent Qt6::Network Qt6::Multimedia)
add_definitions(-DENABLE_QT_GUI) add_definitions(-DENABLE_QT_GUI)
@ -1137,7 +1186,7 @@ if (ENABLE_QT_GUI)
endif() endif()
if (WIN32) if (WIN32)
target_link_libraries(shadps4 PRIVATE mincore winpthreads) target_link_libraries(shadps4 PRIVATE mincore)
if (MSVC) if (MSVC)
# MSVC likes putting opinions on what people can use, disable: # MSVC likes putting opinions on what people can use, disable:
@ -1194,6 +1243,7 @@ include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/CMakeRC.cmake")
cmrc_add_resource_library(embedded-resources cmrc_add_resource_library(embedded-resources
ALIAS res::embedded ALIAS res::embedded
NAMESPACE res NAMESPACE res
src/images/trophy.wav
src/images/bronze.png src/images/bronze.png
src/images/gold.png src/images/gold.png
src/images/platinum.png src/images/platinum.png

62
CMakePresets.json Normal file
View File

@ -0,0 +1,62 @@
{
"version": 9,
"cmakeMinimumRequired": {
"major": 3,
"minor": 30,
"patch": 0
},
"include": ["CMake${hostSystemName}Presets.json"],
"configurePresets": [
{
"name": "x64-Clang-Debug",
"displayName": "Clang x64 Debug",
"inherits": ["x64-Clang-Base"],
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "x64-Clang-Debug-Qt",
"displayName": "Clang x64 Debug with Qt",
"inherits": ["x64-Clang-Base"],
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"ENABLE_QT_GUI": "ON"
}
},
{
"name": "x64-Clang-Release",
"displayName": "Clang x64 Release",
"inherits": ["x64-Clang-Base"],
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
},
{
"name": "x64-Clang-Release-Qt",
"displayName": "Clang x64 Release with Qt",
"inherits": ["x64-Clang-Base"],
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"ENABLE_QT_GUI": "ON"
}
},
{
"name": "x64-Clang-RelWithDebInfo",
"displayName": "Clang x64 RelWithDebInfo",
"inherits": ["x64-Clang-Base"],
"cacheVariables": {
"CMAKE_BUILD_TYPE": "RelWithDebInfo"
}
},
{
"name": "x64-Clang-RelWithDebInfo-Qt",
"displayName": "Clang x64 RelWithDebInfo with Qt",
"inherits": ["x64-Clang-Base"],
"cacheVariables": {
"CMAKE_BUILD_TYPE": "RelWithDebInfo",
"ENABLE_QT_GUI": "ON"
}
}
]
}

View File

@ -12,6 +12,18 @@
"inheritEnvironments": [ "clang_cl_x64_x64" ], "inheritEnvironments": [ "clang_cl_x64_x64" ],
"intelliSenseMode": "windows-clang-x64" "intelliSenseMode": "windows-clang-x64"
}, },
{
"name": "x64-Clang-Release-Qt",
"generator": "Ninja",
"configurationType": "Release",
"buildRoot": "${projectDir}\\Build\\${name}",
"installRoot": "${projectDir}\\Install\\${name}",
"cmakeCommandArgs": "-DENABLE_QT_GUI=ON",
"buildCommandArgs": "",
"ctestCommandArgs": "",
"inheritEnvironments": [ "clang_cl_x64_x64" ],
"intelliSenseMode": "windows-clang-x64"
},
{ {
"name": "x64-Clang-Debug", "name": "x64-Clang-Debug",
"generator": "Ninja", "generator": "Ninja",
@ -24,6 +36,18 @@
"inheritEnvironments": [ "clang_cl_x64_x64" ], "inheritEnvironments": [ "clang_cl_x64_x64" ],
"intelliSenseMode": "windows-clang-x64" "intelliSenseMode": "windows-clang-x64"
}, },
{
"name": "x64-Clang-Debug-Qt",
"generator": "Ninja",
"configurationType": "Debug",
"buildRoot": "${projectDir}\\Build\\${name}",
"installRoot": "${projectDir}\\Install\\${name}",
"cmakeCommandArgs": "-DENABLE_QT_GUI=ON",
"buildCommandArgs": "",
"ctestCommandArgs": "",
"inheritEnvironments": [ "clang_cl_x64_x64" ],
"intelliSenseMode": "windows-clang-x64"
},
{ {
"name": "x64-Clang-RelWithDebInfo", "name": "x64-Clang-RelWithDebInfo",
"generator": "Ninja", "generator": "Ninja",
@ -35,6 +59,18 @@
"ctestCommandArgs": "", "ctestCommandArgs": "",
"inheritEnvironments": [ "clang_cl_x64_x64" ], "inheritEnvironments": [ "clang_cl_x64_x64" ],
"intelliSenseMode": "windows-clang-x64" "intelliSenseMode": "windows-clang-x64"
},
{
"name": "x64-Clang-RelWithDebInfo-Qt",
"generator": "Ninja",
"configurationType": "RelWithDebInfo",
"buildRoot": "${projectDir}\\Build\\${name}",
"installRoot": "${projectDir}\\Install\\${name}",
"cmakeCommandArgs": "-DENABLE_QT_GUI=ON",
"buildCommandArgs": "",
"ctestCommandArgs": "",
"inheritEnvironments": [ "clang_cl_x64_x64" ],
"intelliSenseMode": "windows-clang-x64"
} }
] ]
} }

26
CMakeWindowsPresets.json Normal file
View File

@ -0,0 +1,26 @@
{
"version": 9,
"cmakeMinimumRequired": {
"major": 3,
"minor": 30,
"patch": 0
},
"configurePresets": [
{
"name": "x64-Clang-Base",
"hidden": true,
"generator": "Ninja",
"binaryDir": "${sourceDir}/Build/${presetName}",
"cacheVariables": {
"CMAKE_C_COMPILER": "clang-cl",
"CMAKE_CXX_COMPILER": "clang-cl",
"CMAKE_INSTALL_PREFIX": "${sourceDir}/Build/${presetName}"
},
"vendor": {
"microsoft.com/VisualStudioSettings/CMake/1.0": {
"intelliSenseMode": "windows-clang-x64"
}
}
}
]
}

View File

@ -36,8 +36,8 @@ SPDX-License-Identifier: GPL-2.0-or-later
**shadPS4** is an early **PlayStation 4** emulator for **Windows**, **Linux** and **macOS** written in C++. **shadPS4** is an early **PlayStation 4** emulator for **Windows**, **Linux** and **macOS** written in C++.
If you encounter problems or have doubts, do not hesitate to look at the [**Quickstart**](https://github.com/shadps4-emu/shadPS4/blob/main/documents/Quickstart/Quickstart.md).\ If you encounter problems or have doubts, do not hesitate to look at the [**Quickstart**](https://github.com/shadps4-emu/shadPS4/wiki/I.-Quick-start-%5BUsers%5D).\
To verify that a game works, you can look at [**shadPS4 Game Compatibility**](https://github.com/shadps4-emu/shadps4-game-compatibility).\ To verify that a game works, you can look at [**shadPS4 Game Compatibility**](https://github.com/shadps4-compatibility/shadps4-game-compatibility).\
To discuss shadPS4 development, suggest ideas or to ask for help, join our [**Discord server**](https://discord.gg/bFJxfftGW6).\ To discuss shadPS4 development, suggest ideas or to ask for help, join our [**Discord server**](https://discord.gg/bFJxfftGW6).\
To get the latest news, go to our [**X (Twitter)**](https://x.com/shadps4) or our [**website**](https://shadps4.net/).\ To get the latest news, go to our [**X (Twitter)**](https://x.com/shadps4) or our [**website**](https://shadps4.net/).\
For those who'd like to donate to the project, we now have a [**Kofi page**](https://ko-fi.com/shadps4)! For those who'd like to donate to the project, we now have a [**Kofi page**](https://ko-fi.com/shadps4)!
@ -124,8 +124,8 @@ Keyboard and mouse inputs can be customized in the settings menu by clicking the
# Firmware files # Firmware files
shadPS4 can load some PlayStation 4 firmware files, these must be dumped from your legally owned PlayStation 4 console.\ shadPS4 can load some PlayStation 4 firmware files, these must be dumped from your legally owned PlayStation 4 console.
The following firmware modules are supported and must be placed in shadPS4's `user/sys_modules` folder. The following firmware modules are supported and must be placed in shadPS4's `sys_modules` folder.
<div align="center"> <div align="center">
@ -138,8 +138,7 @@ The following firmware modules are supported and must be placed in shadPS4's `us
</div> </div>
> [!Caution] > [!Caution]
> The above modules are required to run the games properly and must be extracted from your PlayStation 4.\ > The above modules are required to run the games properly and must be extracted from your PlayStation 4.
> **We do not provide any information or support on how to do this**.
@ -148,7 +147,7 @@ The following firmware modules are supported and must be placed in shadPS4's `us
- [**georgemoralis**](https://github.com/georgemoralis) - [**georgemoralis**](https://github.com/georgemoralis)
- [**psucien**](https://github.com/psucien) - [**psucien**](https://github.com/psucien)
- [**viniciuslrangel**](https://github.com/viniciuslrangel) - [**viniciuslrangel**](https://github.com/viniciuslrangel)
- [**roamic**](https://github.com/vladmikhalin) - [**roamic**](https://github.com/roamic)
- [**squidbus**](https://github.com/squidbus) - [**squidbus**](https://github.com/squidbus)
- [**frodo**](https://github.com/baggins183) - [**frodo**](https://github.com/baggins183)
- [**Stephen Miller**](https://github.com/StevenMiller123) - [**Stephen Miller**](https://github.com/StevenMiller123)
@ -158,7 +157,7 @@ Logo is done by [**Xphalnos**](https://github.com/Xphalnos)
# Contributing # Contributing
If you want to contribute, please look the [**CONTRIBUTING.md**](https://github.com/shadps4-emu/shadPS4/blob/main/CONTRIBUTING.md) file.\ If you want to contribute, please read the [**CONTRIBUTING.md**](https://github.com/shadps4-emu/shadPS4/blob/main/CONTRIBUTING.md) file.\
Open a PR and we'll check it :) Open a PR and we'll check it :)
# Translations # Translations

View File

@ -5,10 +5,13 @@ path = [
"REUSE.toml", "REUSE.toml",
"crowdin.yml", "crowdin.yml",
"CMakeSettings.json", "CMakeSettings.json",
"CMakeLinuxPresets.json",
"CMakeWindowsPresets.json",
"CMakePresets.json",
".github/FUNDING.yml", ".github/FUNDING.yml",
".github/shadps4.png", ".github/shadps4.png",
".github/workflows/scripts/update_translation.sh", ".github/workflows/scripts/update_translation.sh",
".github/workflows/update_translation.yml", ".github/workflows/update_translation.yml",
".gitmodules", ".gitmodules",
"dist/MacOSBundleInfo.plist.in", "dist/MacOSBundleInfo.plist.in",
"dist/net.shadps4.shadPS4.desktop", "dist/net.shadps4.shadPS4.desktop",
@ -29,6 +32,7 @@ path = [
"src/images/discord.png", "src/images/discord.png",
"src/images/dump_icon.png", "src/images/dump_icon.png",
"src/images/exit_icon.png", "src/images/exit_icon.png",
"src/images/favorite_icon.png",
"src/images/file_icon.png", "src/images/file_icon.png",
"src/images/trophy_icon.png", "src/images/trophy_icon.png",
"src/images/flag_china.png", "src/images/flag_china.png",
@ -69,9 +73,10 @@ path = [
"src/images/shadps4.svg", "src/images/shadps4.svg",
"src/images/website.svg", "src/images/website.svg",
"src/images/youtube.svg", "src/images/youtube.svg",
"src/images/trophy.wav",
"src/shadps4.qrc", "src/shadps4.qrc",
"src/shadps4.rc", "src/shadps4.rc",
"src/qt_gui/translations/update_translation.sh", "src/qt_gui/translations/update_translation.sh",
] ]
precedence = "aggregate" precedence = "aggregate"
SPDX-FileCopyrightText = "shadPS4 Emulator Project" SPDX-FileCopyrightText = "shadPS4 Emulator Project"

View File

@ -0,0 +1,28 @@
# SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
set(highest_version "0")
set(CANDIDATE_DRIVES A B C D E F G H I J K L M N O P Q R S T U V W X Y Z)
foreach(drive ${CANDIDATE_DRIVES})
file(GLOB kits LIST_DIRECTORIES true CONFIGURE_DEPENDS "${drive}:/Qt/*/msvc*_64")
foreach(kit IN LISTS kits)
get_filename_component(version_dir "${kit}" DIRECTORY)
get_filename_component(kit_version "${version_dir}" NAME)
message(STATUS "DetectQtInstallation.cmake: Detected Qt: ${kit}")
if (kit_version VERSION_GREATER highest_version)
set(highest_version "${kit_version}")
set(QT_PREFIX "${kit}")
endif()
endforeach()
endforeach()
if(QT_PREFIX)
set(CMAKE_PREFIX_PATH "${QT_PREFIX}" CACHE PATH "Qt prefix autodetected" FORCE)
message(STATUS "DetectQtInstallation.cmake: Choose newest Qt: ${QT_PREFIX}")
else()
message(STATUS "DetectQtInstallation.cmake: No QtDirectory found in <drive>:/Qt please set CMAKE_PREFIX_PATH manually")
endif()

View File

@ -37,7 +37,13 @@
<category translate="no">Game</category> <category translate="no">Game</category>
</categories> </categories>
<releases> <releases>
<release version="0.8.0" date="2025-05-23"> <release version="0.10.0" date="2025-07-06">
<url>https://github.com/shadps4-emu/shadPS4/releases/tag/v.0.10.0</url>
</release>
<release version="0.9.0" date="2025-05-22">
<url>https://github.com/shadps4-emu/shadPS4/releases/tag/v.0.9.0</url>
</release>
<release version="0.8.0" date="2025-04-23">
<url>https://github.com/shadps4-emu/shadPS4/releases/tag/v.0.8.0</url> <url>https://github.com/shadps4-emu/shadPS4/releases/tag/v.0.8.0</url>
</release> </release>
<release version="0.7.0" date="2025-03-23"> <release version="0.7.0" date="2025-03-23">

View File

@ -147,7 +147,7 @@ Accurately identifying games will help other developers that own that game recog
- If your issue is small or you aren't sure whether you have properly identified something, [join the Discord server](https://discord.gg/MyZRaBngxA) and use the #development channel - If your issue is small or you aren't sure whether you have properly identified something, [join the Discord server](https://discord.gg/MyZRaBngxA) and use the #development channel
to concisely explain the issue, as well as any findings you currently have. to concisely explain the issue, as well as any findings you currently have.
- It is recommended that you check the [game compatibility issue tracker](https://github.com/shadps4-emu/shadps4-game-compatibility/issues) and post very short summaries of progress changes there, - It is recommended that you check the [game compatibility issue tracker](https://github.com/shadps4-compatibility/shadps4-game-compatibility/issues) and post very short summaries of progress changes there,
(such as the game now booting into the menu or getting in-game) for organizational and status update purposes. (such as the game now booting into the menu or getting in-game) for organizational and status update purposes.
- ⚠ **Do not post theoretical, unproven game-specific issues in the emulator issue tracker that you cannot verify and locate in the emulator source code as being a bug.**\ - ⚠ **Do not post theoretical, unproven game-specific issues in the emulator issue tracker that you cannot verify and locate in the emulator source code as being a bug.**\

View File

@ -21,9 +21,9 @@ SPDX-License-Identifier: GPL-2.0-or-later
- A processor with at least 4 cores and 6 threads - A processor with at least 4 cores and 6 threads
- Above 2.5 GHz frequency - Above 2.5 GHz frequency
- A CPU supporting the following instruction sets: MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, AVX, F16C, CLMUL, AES, BMI1, MOVBE, XSAVE, ABM - A CPU supporting the x86-64-v3 baseline.
- **Intel**: Haswell generation or newer - **Intel**: Haswell generation or newer
- **AMD**: Jaguar generation or newer - **AMD**: Excavator generation or newer
- **Apple**: Rosetta 2 on macOS 15.4 or newer - **Apple**: Rosetta 2 on macOS 15.4 or newer
### GPU ### GPU
@ -55,4 +55,4 @@ To configure the emulator, you can go through the interface and go to "settings"
You can also configure the emulator by editing the `config.toml` file located in the `user` folder created after the application is started (Mostly useful if you are using the SDL version). You can also configure the emulator by editing the `config.toml` file located in the `user` folder created after the application is started (Mostly useful if you are using the SDL version).
Some settings may be related to more technical development and debugging.\ Some settings may be related to more technical development and debugging.\
For more information on this, see [**Debugging**](https://github.com/shadps4-emu/shadPS4/blob/main/documents/Debugging/Debugging.md#configuration). For more information on this, see [**Debugging**](https://github.com/shadps4-emu/shadPS4/blob/main/documents/Debugging/Debugging.md#configuration).

View File

@ -25,11 +25,11 @@ sudo apt install build-essential clang git cmake libasound2-dev \
```bash ```bash
sudo dnf install clang git cmake libatomic alsa-lib-devel \ sudo dnf install clang git cmake libatomic alsa-lib-devel \
pipewire-jack-audio-connection-kit-devel openal-devel \ pipewire-jack-audio-connection-kit-devel openal-soft-devel \
openssl-devel libevdev-devel libudev-devel libXext-devel \ openssl-devel libevdev-devel libudev-devel libXext-devel \
qt6-qtbase-devel qt6-qtbase-private-devel \ qt6-qtbase-devel qt6-qtbase-private-devel \
qt6-qtmultimedia-devel qt6-qtsvg-devel qt6-qttools-devel \ qt6-qtmultimedia-devel qt6-qtsvg-devel qt6-qttools-devel \
vulkan-devel vulkan-validation-layers libpng-devel vulkan-devel vulkan-validation-layers libpng-devel libuuid-devel
``` ```
#### Arch Linux #### Arch Linux
@ -74,6 +74,7 @@ and install the dependencies on that container as cited above.
This option is **highly recommended** for distributions with immutable/atomic filesystems (example: Fedora Kinoite, SteamOS). This option is **highly recommended** for distributions with immutable/atomic filesystems (example: Fedora Kinoite, SteamOS).
### Cloning ### Cloning
The project uses submodules to manage dependencies, and they need to be initialized before you can build the project. To achieve this, make sure you've cloned the repository with the --recursive flag
```bash ```bash
git clone --recursive https://github.com/shadps4-emu/shadPS4.git git clone --recursive https://github.com/shadps4-emu/shadPS4.git

View File

@ -137,12 +137,6 @@ if (NOT TARGET Zydis::Zydis)
add_subdirectory(zydis) add_subdirectory(zydis)
endif() endif()
# Winpthreads
if (WIN32)
add_subdirectory(winpthreads)
target_include_directories(winpthreads INTERFACE winpthreads/include)
endif()
# sirit # sirit
add_subdirectory(sirit) add_subdirectory(sirit)
if (WIN32) if (WIN32)
@ -203,7 +197,7 @@ endif()
# libusb # libusb
if (NOT TARGET libusb::usb) if (NOT TARGET libusb::usb)
add_subdirectory(libusb) add_subdirectory(ext-libusb)
add_library(libusb::usb ALIAS usb-1.0) add_library(libusb::usb ALIAS usb-1.0)
endif() endif()

@ -1 +1 @@
Subproject commit 4cf8f94684c53e581eb9cc694dd3305d1f7d9959 Subproject commit 00abd384ce01cbd439045905d2fa6cf799dfa2f6

@ -1 +1 @@
Subproject commit 2275d0efc4f2fa46851035d9d3c67c105bc8b99e Subproject commit 1a69a919fa302e92b337594bd0a8aaea61037d91

1
externals/ext-libusb vendored Submodule

@ -0,0 +1 @@
Subproject commit e1f4ac1472bdf6aab27f8b836a2f47df85465bac

1
externals/libusb vendored

@ -1 +0,0 @@
Subproject commit a63a7e43e0950a595cf4b98a0eaf4051749ace5f

2
externals/sdl3 vendored

@ -1 +1 @@
Subproject commit 4093e4a193971ef1d4928158e0a1832be42e4599 Subproject commit 86b206dadf8ad40e6657fa37db371a0aeff74e9c

2
externals/sirit vendored

@ -1 +1 @@
Subproject commit 427a42c9ed99b38204d9107bc3dc14e92458acf1 Subproject commit 282083a595dcca86814dedab2f2b0363ef38f1ec

@ -1 +1 @@
Subproject commit 5ceb9ed481e58e705d0d9b5326537daedd06b97d Subproject commit 9c77de5c3dd216f28e407eec65ed9c0a296c1f74

@ -1 +0,0 @@
Subproject commit f35b0948d36a736e6a2d052ae295a3ffde09703f

View File

@ -18,6 +18,9 @@ public:
void unlock() { void unlock() {
pthread_mutex_unlock(&mutex); pthread_mutex_unlock(&mutex);
} }
[[nodiscard]] bool try_lock() {
return pthread_mutex_trylock(&mutex) == 0;
}
private: private:
pthread_mutex_t mutex = PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP; pthread_mutex_t mutex = PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP;

406
src/common/bit_array.h Normal file
View File

@ -0,0 +1,406 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <array>
#include <cstddef>
#include "common/types.h"
#ifdef __AVX2__
#define BIT_ARRAY_USE_AVX
#include <immintrin.h>
#endif
namespace Common {
template <size_t N>
class BitArray {
static_assert(N % 64 == 0, "BitArray size must be a multiple of 64 bits.");
static constexpr size_t BITS_PER_WORD = 64;
static constexpr size_t WORD_COUNT = N / BITS_PER_WORD;
static constexpr size_t WORDS_PER_AVX = 4;
static constexpr size_t AVX_WORD_COUNT = WORD_COUNT / WORDS_PER_AVX;
public:
using Range = std::pair<size_t, size_t>;
class Iterator {
public:
explicit Iterator(const BitArray& bit_array_, u64 start) : bit_array(bit_array_) {
range = bit_array.FirstRangeFrom(start);
}
Iterator& operator++() {
range = bit_array.FirstRangeFrom(range.second);
return *this;
}
bool operator==(const Iterator& other) const {
return range == other.range;
}
bool operator!=(const Iterator& other) const {
return !(*this == other);
}
const Range& operator*() const {
return range;
}
const Range* operator->() const {
return &range;
}
private:
const BitArray& bit_array;
Range range;
};
using const_iterator = Iterator;
using iterator_category = std::forward_iterator_tag;
using value_type = Range;
using difference_type = std::ptrdiff_t;
using pointer = const Range*;
using reference = const Range&;
BitArray() = default;
BitArray(const BitArray& other) = default;
BitArray& operator=(const BitArray& other) = default;
BitArray(BitArray&& other) noexcept = default;
BitArray& operator=(BitArray&& other) noexcept = default;
~BitArray() = default;
BitArray(const BitArray& other, size_t start, size_t end) {
if (start >= end || end > N) {
return;
}
const size_t first_word = start / BITS_PER_WORD;
const size_t last_word = (end - 1) / BITS_PER_WORD;
const size_t start_bit = start % BITS_PER_WORD;
const size_t end_bit = (end - 1) % BITS_PER_WORD;
const u64 start_mask = ~((1ULL << start_bit) - 1);
const u64 end_mask = end_bit == BITS_PER_WORD - 1 ? ~0ULL : (1ULL << (end_bit + 1)) - 1;
if (first_word == last_word) {
data[first_word] = other.data[first_word] & (start_mask & end_mask);
} else {
data[first_word] = other.data[first_word] & start_mask;
size_t i = first_word + 1;
#ifdef BIT_ARRAY_USE_AVX
for (; i + WORDS_PER_AVX <= last_word; i += WORDS_PER_AVX) {
const __m256i current =
_mm256_loadu_si256(reinterpret_cast<const __m256i*>(&other.data[i]));
_mm256_storeu_si256(reinterpret_cast<__m256i*>(&data[i]), current);
}
#endif
for (; i < last_word; ++i) {
data[i] = other.data[i];
}
data[last_word] = other.data[last_word] & end_mask;
}
}
BitArray(const BitArray& other, const Range& range)
: BitArray(other, range.first, range.second) {}
const_iterator begin() const {
return Iterator(*this, 0);
}
const_iterator end() const {
return Iterator(*this, N);
}
inline constexpr void Set(size_t idx) {
data[idx / BITS_PER_WORD] |= (1ULL << (idx % BITS_PER_WORD));
}
inline constexpr void Unset(size_t idx) {
data[idx / BITS_PER_WORD] &= ~(1ULL << (idx % BITS_PER_WORD));
}
inline constexpr bool Get(size_t idx) const {
return (data[idx / BITS_PER_WORD] & (1ULL << (idx % BITS_PER_WORD))) != 0;
}
inline void SetRange(size_t start, size_t end) {
if (start >= end || end > N) {
return;
}
const size_t first_word = start / BITS_PER_WORD;
const size_t last_word = (end - 1) / BITS_PER_WORD;
const size_t start_bit = start % BITS_PER_WORD;
const size_t end_bit = (end - 1) % BITS_PER_WORD;
const u64 start_mask = ~((1ULL << start_bit) - 1);
const u64 end_mask = end_bit == BITS_PER_WORD - 1 ? ~0ULL : (1ULL << (end_bit + 1)) - 1;
if (first_word == last_word) {
data[first_word] |= start_mask & end_mask;
} else {
data[first_word] |= start_mask;
size_t i = first_word + 1;
#ifdef BIT_ARRAY_USE_AVX
const __m256i value = _mm256_set1_epi64x(-1);
for (; i + WORDS_PER_AVX <= last_word; i += WORDS_PER_AVX) {
_mm256_storeu_si256(reinterpret_cast<__m256i*>(&data[i]), value);
}
#endif
for (; i < last_word; ++i) {
data[i] = ~0ULL;
}
data[last_word] |= end_mask;
}
}
inline void UnsetRange(size_t start, size_t end) {
if (start >= end || end > N) {
return;
}
size_t first_word = start / BITS_PER_WORD;
const size_t last_word = (end - 1) / BITS_PER_WORD;
const size_t start_bit = start % BITS_PER_WORD;
const size_t end_bit = (end - 1) % BITS_PER_WORD;
const u64 start_mask = (1ULL << start_bit) - 1;
const u64 end_mask = end_bit == BITS_PER_WORD - 1 ? 0ULL : ~((1ULL << (end_bit + 1)) - 1);
if (first_word == last_word) {
data[first_word] &= start_mask | end_mask;
} else {
data[first_word] &= start_mask;
size_t i = first_word + 1;
#ifdef BIT_ARRAY_USE_AVX
const __m256i value = _mm256_setzero_si256();
for (; i + WORDS_PER_AVX <= last_word; i += WORDS_PER_AVX) {
_mm256_storeu_si256(reinterpret_cast<__m256i*>(&data[i]), value);
}
#endif
for (; i < last_word; ++i) {
data[i] = 0ULL;
}
data[last_word] &= end_mask;
}
}
inline constexpr void SetRange(const Range& range) {
SetRange(range.first, range.second);
}
inline constexpr void UnsetRange(const Range& range) {
UnsetRange(range.first, range.second);
}
inline constexpr void Clear() {
data.fill(0);
}
inline constexpr void Fill() {
data.fill(~0ULL);
}
inline constexpr bool None() const {
u64 result = 0;
for (const auto& word : data) {
result |= word;
}
return result == 0;
}
inline constexpr bool Any() const {
return !None();
}
Range FirstRangeFrom(size_t start) const {
if (start >= N) {
return {N, N};
}
const auto find_end_bit = [&](size_t word) {
#ifdef BIT_ARRAY_USE_AVX
const __m256i all_one = _mm256_set1_epi64x(-1);
for (; word + WORDS_PER_AVX <= WORD_COUNT; word += WORDS_PER_AVX) {
const __m256i current =
_mm256_loadu_si256(reinterpret_cast<const __m256i*>(&data[word]));
const __m256i cmp = _mm256_cmpeq_epi64(current, all_one);
if (_mm256_movemask_epi8(cmp) != 0xFFFFFFFF) {
break;
}
}
#endif
for (; word < WORD_COUNT; ++word) {
if (data[word] != ~0ULL) {
return (word * BITS_PER_WORD) + std::countr_one(data[word]);
}
}
return N;
};
const auto word_bits = [&](size_t index, u64 word) {
const int empty_bits = std::countr_zero(word);
const int ones_count = std::countr_one(word >> empty_bits);
const size_t start_bit = index * BITS_PER_WORD + empty_bits;
if (ones_count + empty_bits < BITS_PER_WORD) {
return Range{start_bit, start_bit + ones_count};
}
return Range{start_bit, find_end_bit(index + 1)};
};
const size_t start_word = start / BITS_PER_WORD;
const size_t start_bit = start % BITS_PER_WORD;
const u64 masked_first = data[start_word] & (~((1ULL << start_bit) - 1));
if (masked_first) {
return word_bits(start_word, masked_first);
}
size_t word = start_word + 1;
#ifdef BIT_ARRAY_USE_AVX
for (; word + WORDS_PER_AVX <= WORD_COUNT; word += WORDS_PER_AVX) {
const __m256i current =
_mm256_loadu_si256(reinterpret_cast<const __m256i*>(&data[word]));
if (!_mm256_testz_si256(current, current)) {
break;
}
}
#endif
for (; word < WORD_COUNT; ++word) {
if (data[word] != 0) {
return word_bits(word, data[word]);
}
}
return {N, N};
}
inline constexpr Range FirstRange() const {
return FirstRangeFrom(0);
}
Range LastRangeFrom(size_t end) const {
if (end == 0) {
return {0, 0};
}
if (end > N) {
end = N;
}
const auto find_start_bit = [&](size_t word) {
#ifdef BIT_ARRAY_USE_AVX
const __m256i all_zero = _mm256_setzero_si256();
for (; word >= WORDS_PER_AVX; word -= WORDS_PER_AVX) {
const __m256i current = _mm256_loadu_si256(
reinterpret_cast<const __m256i*>(&data[word - WORDS_PER_AVX]));
const __m256i cmp = _mm256_cmpeq_epi64(current, all_zero);
if (_mm256_movemask_epi8(cmp) != 0xFFFFFFFF) {
break;
}
}
#endif
for (; word > 0; --word) {
if (data[word - 1] != ~0ULL) {
return word * BITS_PER_WORD - std::countl_one(data[word - 1]);
}
}
return size_t(0);
};
const auto word_bits = [&](size_t index, u64 word) {
const int empty_bits = std::countl_zero(word);
const int ones_count = std::countl_one(word << empty_bits);
const size_t end_bit = index * BITS_PER_WORD - empty_bits;
if (empty_bits + ones_count < BITS_PER_WORD) {
return Range{end_bit - ones_count, end_bit};
}
return Range{find_start_bit(index - 1), end_bit};
};
const size_t end_word = ((end - 1) / BITS_PER_WORD) + 1;
const size_t end_bit = (end - 1) % BITS_PER_WORD;
u64 masked_last = data[end_word - 1];
if (end_bit < BITS_PER_WORD - 1) {
masked_last &= (1ULL << (end_bit + 1)) - 1;
}
if (masked_last) {
return word_bits(end_word, masked_last);
}
size_t word = end_word - 1;
#ifdef BIT_ARRAY_USE_AVX
for (; word >= WORDS_PER_AVX; word -= WORDS_PER_AVX) {
const __m256i current =
_mm256_loadu_si256(reinterpret_cast<const __m256i*>(&data[word - WORDS_PER_AVX]));
if (!_mm256_testz_si256(current, current)) {
break;
}
}
#endif
for (; word > 0; --word) {
if (data[word - 1] != 0) {
return word_bits(word, data[word - 1]);
}
}
return {0, 0};
}
inline constexpr Range LastRange() const {
return LastRangeFrom(N);
}
inline constexpr size_t Size() const {
return N;
}
inline constexpr BitArray& operator|=(const BitArray& other) {
for (size_t i = 0; i < WORD_COUNT; ++i) {
data[i] |= other.data[i];
}
return *this;
}
inline constexpr BitArray& operator&=(const BitArray& other) {
for (size_t i = 0; i < WORD_COUNT; ++i) {
data[i] &= other.data[i];
}
return *this;
}
inline constexpr BitArray& operator^=(const BitArray& other) {
for (size_t i = 0; i < WORD_COUNT; ++i) {
data[i] ^= other.data[i];
}
return *this;
}
inline constexpr BitArray operator|(const BitArray& other) const {
BitArray result = *this;
result |= other;
return result;
}
inline constexpr BitArray operator&(const BitArray& other) const {
BitArray result = *this;
result &= other;
return result;
}
inline constexpr BitArray operator^(const BitArray& other) const {
BitArray result = *this;
result ^= other;
return result;
}
inline constexpr BitArray operator~() const {
BitArray result = *this;
for (size_t i = 0; i < WORD_COUNT; ++i) {
result.data[i] = ~result.data[i];
}
return result;
}
inline constexpr bool operator==(const BitArray& other) const {
u64 result = 0;
for (size_t i = 0; i < WORD_COUNT; ++i) {
result |= data[i] ^ other.data[i];
}
return result == 0;
}
inline constexpr bool operator!=(const BitArray& other) const {
return !(*this == other);
}
private:
std::array<u64, WORD_COUNT> data{};
};
} // namespace Common

View File

@ -31,35 +31,56 @@ std::filesystem::path find_fs_path_or(const basic_value<TC>& v, const K& ky,
namespace Config { namespace Config {
// General
static int volumeSlider = 100;
static bool isNeo = false; static bool isNeo = false;
static bool isDevKit = false; static bool isDevKit = false;
static bool playBGM = false; static bool isPSNSignedIn = false;
static bool isTrophyPopupDisabled = false; static bool isTrophyPopupDisabled = false;
static int BGMvolume = 50; static double trophyNotificationDuration = 6.0;
static bool enableDiscordRPC = false; static bool enableDiscordRPC = false;
static u32 screenWidth = 1280; static std::string logFilter = "";
static u32 screenHeight = 720;
static s32 gpuId = -1; // Vulkan physical device index. Set to negative for auto select
static std::string logFilter;
static std::string logType = "sync"; static std::string logType = "sync";
static std::string userName = "shadPS4"; static std::string userName = "shadPS4";
static std::string updateChannel; static std::string chooseHomeTab = "General";
static std::string chooseHomeTab; static bool isShowSplash = false;
static std::string backButtonBehavior = "left"; static std::string isSideTrophy = "right";
static bool compatibilityData = false;
static bool checkCompatibilityOnStartup = false;
static bool isConnectedToNetwork = false;
// Input
static int cursorState = HideCursorState::Idle;
static int cursorHideTimeout = 5; // 5 seconds (default)
static bool useSpecialPad = false; static bool useSpecialPad = false;
static int specialPadClass = 1; static int specialPadClass = 1;
static bool isMotionControlsEnabled = true; static bool isMotionControlsEnabled = true;
static bool isDebugDump = false; static bool useUnifiedInputConfig = true;
static bool isShaderDebug = false; static std::string micDevice = "Default Device";
static bool isShowSplash = false;
static bool isAutoUpdate = false; // These two entries aren't stored in the config
static bool isAlwaysShowChangelog = false; static bool overrideControllerColor = false;
static std::string isSideTrophy = "right"; static int controllerCustomColorRGB[3] = {0, 0, 255};
// GPU
static u32 windowWidth = 1280;
static u32 windowHeight = 720;
static u32 internalScreenWidth = 1280;
static u32 internalScreenHeight = 720;
static bool isNullGpu = false; static bool isNullGpu = false;
static bool shouldCopyGPUBuffers = false; static bool shouldCopyGPUBuffers = false;
static bool readbacksEnabled = false;
static bool readbackLinearImagesEnabled = false;
static bool directMemoryAccessEnabled = false;
static bool shouldDumpShaders = false; static bool shouldDumpShaders = false;
static bool shouldPatchShaders = true; static bool shouldPatchShaders = false;
static u32 vblankDivider = 1; static u32 vblankDivider = 1;
static bool isFullscreen = false;
static std::string fullscreenMode = "Windowed";
static bool isHDRAllowed = false;
// Vulkan
static s32 gpuId = -1;
static bool vkValidation = false; static bool vkValidation = false;
static bool vkValidationSync = false; static bool vkValidationSync = false;
static bool vkValidationGpu = false; static bool vkValidationGpu = false;
@ -67,49 +88,32 @@ static bool vkCrashDiagnostic = false;
static bool vkHostMarkers = false; static bool vkHostMarkers = false;
static bool vkGuestMarkers = false; static bool vkGuestMarkers = false;
static bool rdocEnable = false; static bool rdocEnable = false;
static bool isFpsColor = true;
static bool isSeparateLogFilesEnabled = false;
static s16 cursorState = HideCursorState::Idle;
static int cursorHideTimeout = 5; // 5 seconds (default)
static double trophyNotificationDuration = 6.0;
static bool useUnifiedInputConfig = true;
static bool overrideControllerColor = false;
static int controllerCustomColorRGB[3] = {0, 0, 255};
static bool compatibilityData = false;
static bool checkCompatibilityOnStartup = false;
static std::string trophyKey;
// Gui // Debug
static bool isDebugDump = false;
static bool isShaderDebug = false;
static bool isSeparateLogFilesEnabled = false;
static bool isFpsColor = true;
// GUI
static bool load_game_size = true; static bool load_game_size = true;
static std::vector<GameInstallDir> settings_install_dirs = {}; static std::vector<GameInstallDir> settings_install_dirs = {};
std::vector<bool> install_dirs_enabled = {}; std::vector<bool> install_dirs_enabled = {};
std::filesystem::path settings_addon_install_dir = {}; std::filesystem::path settings_addon_install_dir = {};
std::filesystem::path save_data_path = {}; std::filesystem::path save_data_path = {};
u32 main_window_geometry_x = 400;
u32 main_window_geometry_y = 400;
u32 main_window_geometry_w = 1280;
u32 main_window_geometry_h = 720;
u32 mw_themes = 0;
u32 m_icon_size = 36;
u32 m_icon_size_grid = 69;
u32 m_slider_pos = 0;
u32 m_slider_pos_grid = 0;
u32 m_table_mode = 0;
u32 m_window_size_W = 1280;
u32 m_window_size_H = 720;
std::vector<std::string> m_elf_viewer;
std::vector<std::string> m_recent_files;
std::string emulator_language = "en_US";
static int backgroundImageOpacity = 50;
static bool showBackgroundImage = true;
static bool isFullscreen = false;
static std::string fullscreenMode = "Windowed";
static bool isHDRAllowed = false;
static bool showLabelsUnderIcons = true;
// Language // Settings
u32 m_language = 1; // english u32 m_language = 1; // english
// Keys
static std::string trophyKey = "";
// Config version, used to determine if a user's config file is outdated.
static std::string config_version = Common::g_scm_rev;
int getVolumeSlider() {
return volumeSlider;
}
bool allowHDR() { bool allowHDR() {
return isHDRAllowed; return isHDRAllowed;
} }
@ -154,11 +158,15 @@ bool GetLoadGameSizeEnabled() {
std::filesystem::path GetSaveDataPath() { std::filesystem::path GetSaveDataPath() {
if (save_data_path.empty()) { if (save_data_path.empty()) {
return Common::FS::GetUserPath(Common::FS::PathType::SaveDataDir); return Common::FS::GetUserPath(Common::FS::PathType::UserDir) / "savedata";
} }
return save_data_path; return save_data_path;
} }
void setVolumeSlider(int volumeValue) {
volumeSlider = volumeValue;
}
void setLoadGameSizeEnabled(bool enable) { void setLoadGameSizeEnabled(bool enable) {
load_game_size = enable; load_game_size = enable;
} }
@ -175,14 +183,6 @@ bool getIsFullscreen() {
return isFullscreen; return isFullscreen;
} }
bool getShowLabelsUnderIcons() {
return showLabelsUnderIcons;
}
bool setShowLabelsUnderIcons() {
return false;
}
std::string getFullscreenMode() { std::string getFullscreenMode() {
return fullscreenMode; return fullscreenMode;
} }
@ -191,14 +191,6 @@ bool getisTrophyPopupDisabled() {
return isTrophyPopupDisabled; return isTrophyPopupDisabled;
} }
bool getPlayBGM() {
return playBGM;
}
int getBGMvolume() {
return BGMvolume;
}
bool getEnableDiscordRPC() { bool getEnableDiscordRPC() {
return enableDiscordRPC; return enableDiscordRPC;
} }
@ -211,16 +203,28 @@ int getCursorHideTimeout() {
return cursorHideTimeout; return cursorHideTimeout;
} }
std::string getMicDevice() {
return micDevice;
}
double getTrophyNotificationDuration() { double getTrophyNotificationDuration() {
return trophyNotificationDuration; return trophyNotificationDuration;
} }
u32 getScreenWidth() { u32 getWindowWidth() {
return screenWidth; return windowWidth;
} }
u32 getScreenHeight() { u32 getWindowHeight() {
return screenHeight; return windowHeight;
}
u32 getInternalScreenWidth() {
return internalScreenHeight;
}
u32 getInternalScreenHeight() {
return internalScreenHeight;
} }
s32 getGpuId() { s32 getGpuId() {
@ -239,18 +243,10 @@ std::string getUserName() {
return userName; return userName;
} }
std::string getUpdateChannel() {
return updateChannel;
}
std::string getChooseHomeTab() { std::string getChooseHomeTab() {
return chooseHomeTab; return chooseHomeTab;
} }
std::string getBackButtonBehavior() {
return backButtonBehavior;
}
bool getUseSpecialPad() { bool getUseSpecialPad() {
return useSpecialPad; return useSpecialPad;
} }
@ -275,14 +271,6 @@ bool showSplash() {
return isShowSplash; return isShowSplash;
} }
bool autoUpdate() {
return isAutoUpdate;
}
bool alwaysShowChangelog() {
return isAlwaysShowChangelog;
}
std::string sideTrophy() { std::string sideTrophy() {
return isSideTrophy; return isSideTrophy;
} }
@ -295,6 +283,18 @@ bool copyGPUCmdBuffers() {
return shouldCopyGPUBuffers; return shouldCopyGPUBuffers;
} }
bool readbacks() {
return readbacksEnabled;
}
bool readbackLinearImages() {
return readbackLinearImagesEnabled;
}
bool directMemoryAccess() {
return directMemoryAccessEnabled;
}
bool dumpShaders() { bool dumpShaders() {
return shouldDumpShaders; return shouldDumpShaders;
} }
@ -359,16 +359,28 @@ bool getCheckCompatibilityOnStartup() {
return checkCompatibilityOnStartup; return checkCompatibilityOnStartup;
} }
bool getIsConnectedToNetwork() {
return isConnectedToNetwork;
}
void setGpuId(s32 selectedGpuId) { void setGpuId(s32 selectedGpuId) {
gpuId = selectedGpuId; gpuId = selectedGpuId;
} }
void setScreenWidth(u32 width) { void setWindowWidth(u32 width) {
screenWidth = width; windowWidth = width;
} }
void setScreenHeight(u32 height) { void setWindowHeight(u32 height) {
screenHeight = height; windowHeight = height;
}
void setInternalScreenWidth(u32 width) {
internalScreenWidth = width;
}
void setInternalScreenHeight(u32 height) {
internalScreenHeight = height;
} }
void setDebugDump(bool enable) { void setDebugDump(bool enable) {
@ -383,14 +395,6 @@ void setShowSplash(bool enable) {
isShowSplash = enable; isShowSplash = enable;
} }
void setAutoUpdate(bool enable) {
isAutoUpdate = enable;
}
void setAlwaysShowChangelog(bool enable) {
isAlwaysShowChangelog = enable;
}
void setSideTrophy(std::string side) { void setSideTrophy(std::string side) {
isSideTrophy = side; isSideTrophy = side;
} }
@ -407,6 +411,14 @@ void setCopyGPUCmdBuffers(bool enable) {
shouldCopyGPUBuffers = enable; shouldCopyGPUBuffers = enable;
} }
void setReadbacks(bool enable) {
readbacksEnabled = enable;
}
void setDirectMemoryAccess(bool enable) {
directMemoryAccessEnabled = enable;
}
void setDumpShaders(bool enable) { void setDumpShaders(bool enable) {
shouldDumpShaders = enable; shouldDumpShaders = enable;
} }
@ -430,9 +442,6 @@ void setVblankDiv(u32 value) {
void setIsFullscreen(bool enable) { void setIsFullscreen(bool enable) {
isFullscreen = enable; isFullscreen = enable;
} }
static void setShowLabelsUnderIcons(bool enable) {
showLabelsUnderIcons = enable;
}
void setFullscreenMode(std::string mode) { void setFullscreenMode(std::string mode) {
fullscreenMode = mode; fullscreenMode = mode;
@ -442,14 +451,6 @@ void setisTrophyPopupDisabled(bool disable) {
isTrophyPopupDisabled = disable; isTrophyPopupDisabled = disable;
} }
void setPlayBGM(bool enable) {
playBGM = enable;
}
void setBGMvolume(int volume) {
BGMvolume = volume;
}
void setEnableDiscordRPC(bool enable) { void setEnableDiscordRPC(bool enable) {
enableDiscordRPC = enable; enableDiscordRPC = enable;
} }
@ -461,6 +462,11 @@ void setCursorState(s16 newCursorState) {
void setCursorHideTimeout(int newcursorHideTimeout) { void setCursorHideTimeout(int newcursorHideTimeout) {
cursorHideTimeout = newcursorHideTimeout; cursorHideTimeout = newcursorHideTimeout;
} }
void setMicDevice(std::string device) {
micDevice = device;
}
void setTrophyNotificationDuration(double newTrophyNotificationDuration) { void setTrophyNotificationDuration(double newTrophyNotificationDuration) {
trophyNotificationDuration = newTrophyNotificationDuration; trophyNotificationDuration = newTrophyNotificationDuration;
} }
@ -489,17 +495,10 @@ void setUserName(const std::string& type) {
userName = type; userName = type;
} }
void setUpdateChannel(const std::string& type) {
updateChannel = type;
}
void setChooseHomeTab(const std::string& type) { void setChooseHomeTab(const std::string& type) {
chooseHomeTab = type; chooseHomeTab = type;
} }
void setBackButtonBehavior(const std::string& type) {
backButtonBehavior = type;
}
void setUseSpecialPad(bool use) { void setUseSpecialPad(bool use) {
useSpecialPad = use; useSpecialPad = use;
} }
@ -520,13 +519,6 @@ void setCheckCompatibilityOnStartup(bool use) {
checkCompatibilityOnStartup = use; checkCompatibilityOnStartup = use;
} }
void setMainWindowGeometry(u32 x, u32 y, u32 w, u32 h) {
main_window_geometry_x = x;
main_window_geometry_y = y;
main_window_geometry_w = w;
main_window_geometry_h = h;
}
bool addGameInstallDir(const std::filesystem::path& dir, bool enabled) { bool addGameInstallDir(const std::filesystem::path& dir, bool enabled) {
for (const auto& install_dir : settings_install_dirs) { for (const auto& install_dir : settings_install_dirs) {
if (install_dir.path == dir) { if (install_dir.path == dir) {
@ -559,52 +551,6 @@ void setAddonInstallDir(const std::filesystem::path& dir) {
settings_addon_install_dir = dir; settings_addon_install_dir = dir;
} }
void setMainWindowTheme(u32 theme) {
mw_themes = theme;
}
void setIconSize(u32 size) {
m_icon_size = size;
}
void setIconSizeGrid(u32 size) {
m_icon_size_grid = size;
}
void setSliderPosition(u32 pos) {
m_slider_pos = pos;
}
void setSliderPositionGrid(u32 pos) {
m_slider_pos_grid = pos;
}
void setTableMode(u32 mode) {
m_table_mode = mode;
}
void setMainWindowWidth(u32 width) {
m_window_size_W = width;
}
void setMainWindowHeight(u32 height) {
m_window_size_H = height;
}
void setElfViewer(const std::vector<std::string>& elfList) {
m_elf_viewer.resize(elfList.size());
m_elf_viewer = elfList;
}
void setRecentFiles(const std::vector<std::string>& recentFiles) {
m_recent_files.resize(recentFiles.size());
m_recent_files = recentFiles;
}
void setEmulatorLanguage(std::string language) {
emulator_language = language;
}
void setGameInstallDirs(const std::vector<std::filesystem::path>& dirs_config) { void setGameInstallDirs(const std::vector<std::filesystem::path>& dirs_config) {
settings_install_dirs.clear(); settings_install_dirs.clear();
for (const auto& dir : dirs_config) { for (const auto& dir : dirs_config) {
@ -620,22 +566,6 @@ void setSaveDataPath(const std::filesystem::path& path) {
save_data_path = path; save_data_path = path;
} }
u32 getMainWindowGeometryX() {
return main_window_geometry_x;
}
u32 getMainWindowGeometryY() {
return main_window_geometry_y;
}
u32 getMainWindowGeometryW() {
return main_window_geometry_w;
}
u32 getMainWindowGeometryH() {
return main_window_geometry_h;
}
const std::vector<std::filesystem::path> getGameInstallDirs() { const std::vector<std::filesystem::path> getGameInstallDirs() {
std::vector<std::filesystem::path> enabled_dirs; std::vector<std::filesystem::path> enabled_dirs;
for (const auto& dir : settings_install_dirs) { for (const auto& dir : settings_install_dirs) {
@ -662,50 +592,6 @@ std::filesystem::path getAddonInstallDir() {
return settings_addon_install_dir; return settings_addon_install_dir;
} }
u32 getMainWindowTheme() {
return mw_themes;
}
u32 getIconSize() {
return m_icon_size;
}
u32 getIconSizeGrid() {
return m_icon_size_grid;
}
u32 getSliderPosition() {
return m_slider_pos;
}
u32 getSliderPositionGrid() {
return m_slider_pos_grid;
}
u32 getTableMode() {
return m_table_mode;
}
u32 getMainWindowWidth() {
return m_window_size_W;
}
u32 getMainWindowHeight() {
return m_window_size_H;
}
std::vector<std::string> getElfViewer() {
return m_elf_viewer;
}
std::vector<std::string> getRecentFiles() {
return m_recent_files;
}
std::string getEmulatorLanguage() {
return emulator_language;
}
u32 GetLanguage() { u32 GetLanguage() {
return m_language; return m_language;
} }
@ -714,20 +600,12 @@ bool getSeparateLogFilesEnabled() {
return isSeparateLogFilesEnabled; return isSeparateLogFilesEnabled;
} }
int getBackgroundImageOpacity() { bool getPSNSignedIn() {
return backgroundImageOpacity; return isPSNSignedIn;
} }
void setBackgroundImageOpacity(int opacity) { void setPSNSignedIn(bool sign) {
backgroundImageOpacity = std::clamp(opacity, 0, 100); isPSNSignedIn = sign;
}
bool getShowBackgroundImage() {
return showBackgroundImage;
}
void setShowBackgroundImage(bool show) {
showBackgroundImage = show;
} }
void load(const std::filesystem::path& path) { void load(const std::filesystem::path& path) {
@ -749,95 +627,99 @@ void load(const std::filesystem::path& path) {
fmt::print("Got exception trying to load config file. Exception: {}\n", ex.what()); fmt::print("Got exception trying to load config file. Exception: {}\n", ex.what());
return; return;
} }
if (data.contains("General")) { if (data.contains("General")) {
const toml::value& general = data.at("General"); const toml::value& general = data.at("General");
isNeo = toml::find_or<bool>(general, "isPS4Pro", false); volumeSlider = toml::find_or<int>(general, "volumeSlider", volumeSlider);
isDevKit = toml::find_or<bool>(general, "isDevKit", false); isNeo = toml::find_or<bool>(general, "isPS4Pro", isNeo);
playBGM = toml::find_or<bool>(general, "playBGM", false); isDevKit = toml::find_or<bool>(general, "isDevKit", isDevKit);
isTrophyPopupDisabled = toml::find_or<bool>(general, "isTrophyPopupDisabled", false); isPSNSignedIn = toml::find_or<bool>(general, "isPSNSignedIn", isPSNSignedIn);
trophyNotificationDuration = isTrophyPopupDisabled =
toml::find_or<double>(general, "trophyNotificationDuration", 5.0); toml::find_or<bool>(general, "isTrophyPopupDisabled", isTrophyPopupDisabled);
BGMvolume = toml::find_or<int>(general, "BGMvolume", 50); trophyNotificationDuration = toml::find_or<double>(general, "trophyNotificationDuration",
enableDiscordRPC = toml::find_or<bool>(general, "enableDiscordRPC", true); trophyNotificationDuration);
logFilter = toml::find_or<std::string>(general, "logFilter", ""); enableDiscordRPC = toml::find_or<bool>(general, "enableDiscordRPC", enableDiscordRPC);
logType = toml::find_or<std::string>(general, "logType", "sync"); logFilter = toml::find_or<std::string>(general, "logFilter", logFilter);
userName = toml::find_or<std::string>(general, "userName", "shadPS4"); logType = toml::find_or<std::string>(general, "logType", logType);
if (Common::g_is_release) { userName = toml::find_or<std::string>(general, "userName", userName);
updateChannel = toml::find_or<std::string>(general, "updateChannel", "Release"); isShowSplash = toml::find_or<bool>(general, "showSplash", isShowSplash);
} else { isSideTrophy = toml::find_or<std::string>(general, "sideTrophy", isSideTrophy);
updateChannel = toml::find_or<std::string>(general, "updateChannel", "Nightly"); compatibilityData = toml::find_or<bool>(general, "compatibilityEnabled", compatibilityData);
} checkCompatibilityOnStartup = toml::find_or<bool>(general, "checkCompatibilityOnStartup",
isShowSplash = toml::find_or<bool>(general, "showSplash", true); checkCompatibilityOnStartup);
isAutoUpdate = toml::find_or<bool>(general, "autoUpdate", false);
isAlwaysShowChangelog = toml::find_or<bool>(general, "alwaysShowChangelog", false); isConnectedToNetwork =
isSideTrophy = toml::find_or<std::string>(general, "sideTrophy", "right"); toml::find_or<bool>(general, "isConnectedToNetwork", isConnectedToNetwork);
compatibilityData = toml::find_or<bool>(general, "compatibilityEnabled", false); chooseHomeTab = toml::find_or<std::string>(general, "chooseHomeTab", chooseHomeTab);
checkCompatibilityOnStartup =
toml::find_or<bool>(general, "checkCompatibilityOnStartup", false);
chooseHomeTab = toml::find_or<std::string>(general, "chooseHomeTab", "Release");
} }
if (data.contains("Input")) { if (data.contains("Input")) {
const toml::value& input = data.at("Input"); const toml::value& input = data.at("Input");
cursorState = toml::find_or<int>(input, "cursorState", HideCursorState::Idle); cursorState = toml::find_or<int>(input, "cursorState", cursorState);
cursorHideTimeout = toml::find_or<int>(input, "cursorHideTimeout", 5); cursorHideTimeout = toml::find_or<int>(input, "cursorHideTimeout", cursorHideTimeout);
backButtonBehavior = toml::find_or<std::string>(input, "backButtonBehavior", "left"); useSpecialPad = toml::find_or<bool>(input, "useSpecialPad", useSpecialPad);
useSpecialPad = toml::find_or<bool>(input, "useSpecialPad", false); specialPadClass = toml::find_or<int>(input, "specialPadClass", specialPadClass);
specialPadClass = toml::find_or<int>(input, "specialPadClass", 1); isMotionControlsEnabled =
isMotionControlsEnabled = toml::find_or<bool>(input, "isMotionControlsEnabled", true); toml::find_or<bool>(input, "isMotionControlsEnabled", isMotionControlsEnabled);
useUnifiedInputConfig = toml::find_or<bool>(input, "useUnifiedInputConfig", true); useUnifiedInputConfig =
toml::find_or<bool>(input, "useUnifiedInputConfig", useUnifiedInputConfig);
micDevice = toml::find_or<std::string>(input, "micDevice", micDevice);
} }
if (data.contains("GPU")) { if (data.contains("GPU")) {
const toml::value& gpu = data.at("GPU"); const toml::value& gpu = data.at("GPU");
screenWidth = toml::find_or<int>(gpu, "screenWidth", screenWidth); windowWidth = toml::find_or<int>(gpu, "screenWidth", windowWidth);
screenHeight = toml::find_or<int>(gpu, "screenHeight", screenHeight); windowHeight = toml::find_or<int>(gpu, "screenHeight", windowHeight);
isNullGpu = toml::find_or<bool>(gpu, "nullGpu", false); internalScreenWidth = toml::find_or<int>(gpu, "internalScreenWidth", internalScreenWidth);
shouldCopyGPUBuffers = toml::find_or<bool>(gpu, "copyGPUBuffers", false); internalScreenHeight =
shouldDumpShaders = toml::find_or<bool>(gpu, "dumpShaders", false); toml::find_or<int>(gpu, "internalScreenHeight", internalScreenHeight);
shouldPatchShaders = toml::find_or<bool>(gpu, "patchShaders", true); isNullGpu = toml::find_or<bool>(gpu, "nullGpu", isNullGpu);
vblankDivider = toml::find_or<int>(gpu, "vblankDivider", 1); shouldCopyGPUBuffers = toml::find_or<bool>(gpu, "copyGPUBuffers", shouldCopyGPUBuffers);
isFullscreen = toml::find_or<bool>(gpu, "Fullscreen", false); readbacksEnabled = toml::find_or<bool>(gpu, "readbacks", readbacksEnabled);
fullscreenMode = toml::find_or<std::string>(gpu, "FullscreenMode", "Windowed"); readbackLinearImagesEnabled =
isHDRAllowed = toml::find_or<bool>(gpu, "allowHDR", false); toml::find_or<bool>(gpu, "readbackLinearImages", readbackLinearImagesEnabled);
directMemoryAccessEnabled =
toml::find_or<bool>(gpu, "directMemoryAccess", directMemoryAccessEnabled);
shouldDumpShaders = toml::find_or<bool>(gpu, "dumpShaders", shouldDumpShaders);
shouldPatchShaders = toml::find_or<bool>(gpu, "patchShaders", shouldPatchShaders);
vblankDivider = toml::find_or<int>(gpu, "vblankDivider", vblankDivider);
isFullscreen = toml::find_or<bool>(gpu, "Fullscreen", isFullscreen);
fullscreenMode = toml::find_or<std::string>(gpu, "FullscreenMode", fullscreenMode);
isHDRAllowed = toml::find_or<bool>(gpu, "allowHDR", isHDRAllowed);
} }
if (data.contains("Vulkan")) { if (data.contains("Vulkan")) {
const toml::value& vk = data.at("Vulkan"); const toml::value& vk = data.at("Vulkan");
gpuId = toml::find_or<int>(vk, "gpuId", -1); gpuId = toml::find_or<int>(vk, "gpuId", gpuId);
vkValidation = toml::find_or<bool>(vk, "validation", false); vkValidation = toml::find_or<bool>(vk, "validation", vkValidation);
vkValidationSync = toml::find_or<bool>(vk, "validation_sync", false); vkValidationSync = toml::find_or<bool>(vk, "validation_sync", vkValidationSync);
vkValidationGpu = toml::find_or<bool>(vk, "validation_gpu", true); vkValidationGpu = toml::find_or<bool>(vk, "validation_gpu", vkValidationGpu);
vkCrashDiagnostic = toml::find_or<bool>(vk, "crashDiagnostic", false); vkCrashDiagnostic = toml::find_or<bool>(vk, "crashDiagnostic", vkCrashDiagnostic);
vkHostMarkers = toml::find_or<bool>(vk, "hostMarkers", false); vkHostMarkers = toml::find_or<bool>(vk, "hostMarkers", vkHostMarkers);
vkGuestMarkers = toml::find_or<bool>(vk, "guestMarkers", false); vkGuestMarkers = toml::find_or<bool>(vk, "guestMarkers", vkGuestMarkers);
rdocEnable = toml::find_or<bool>(vk, "rdocEnable", false); rdocEnable = toml::find_or<bool>(vk, "rdocEnable", rdocEnable);
} }
std::string current_version = {};
if (data.contains("Debug")) { if (data.contains("Debug")) {
const toml::value& debug = data.at("Debug"); const toml::value& debug = data.at("Debug");
isDebugDump = toml::find_or<bool>(debug, "DebugDump", false); isDebugDump = toml::find_or<bool>(debug, "DebugDump", isDebugDump);
isSeparateLogFilesEnabled = toml::find_or<bool>(debug, "isSeparateLogFilesEnabled", false); isSeparateLogFilesEnabled =
isShaderDebug = toml::find_or<bool>(debug, "CollectShader", false); toml::find_or<bool>(debug, "isSeparateLogFilesEnabled", isSeparateLogFilesEnabled);
isFpsColor = toml::find_or<bool>(debug, "FPSColor", true); isShaderDebug = toml::find_or<bool>(debug, "CollectShader", isShaderDebug);
isFpsColor = toml::find_or<bool>(debug, "FPSColor", isFpsColor);
current_version = toml::find_or<std::string>(debug, "ConfigVersion", current_version);
} }
if (data.contains("GUI")) { if (data.contains("GUI")) {
const toml::value& gui = data.at("GUI"); const toml::value& gui = data.at("GUI");
load_game_size = toml::find_or<bool>(gui, "loadGameSizeEnabled", true); load_game_size = toml::find_or<bool>(gui, "loadGameSizeEnabled", load_game_size);
m_icon_size = toml::find_or<int>(gui, "iconSize", 0);
m_icon_size_grid = toml::find_or<int>(gui, "iconSizeGrid", 0);
m_slider_pos = toml::find_or<int>(gui, "sliderPos", 0);
m_slider_pos_grid = toml::find_or<int>(gui, "sliderPosGrid", 0);
mw_themes = toml::find_or<int>(gui, "theme", 0);
m_window_size_W = toml::find_or<int>(gui, "mw_width", 0);
m_window_size_H = toml::find_or<int>(gui, "mw_height", 0);
const auto install_dir_array = const auto install_dir_array =
toml::find_or<std::vector<std::u8string>>(gui, "installDirs", {}); toml::find_or<std::vector<std::u8string>>(gui, "installDirs", {});
@ -859,41 +741,25 @@ void load(const std::filesystem::path& path) {
{std::filesystem::path{install_dir_array[i]}, install_dirs_enabled[i]}); {std::filesystem::path{install_dir_array[i]}, install_dirs_enabled[i]});
} }
save_data_path = toml::find_fs_path_or(gui, "saveDataPath", {}); save_data_path = toml::find_fs_path_or(gui, "saveDataPath", save_data_path);
settings_addon_install_dir = toml::find_fs_path_or(gui, "addonInstallDir", {}); settings_addon_install_dir =
main_window_geometry_x = toml::find_or<int>(gui, "geometry_x", 0); toml::find_fs_path_or(gui, "addonInstallDir", settings_addon_install_dir);
main_window_geometry_y = toml::find_or<int>(gui, "geometry_y", 0);
main_window_geometry_w = toml::find_or<int>(gui, "geometry_w", 0);
main_window_geometry_h = toml::find_or<int>(gui, "geometry_h", 0);
m_elf_viewer = toml::find_or<std::vector<std::string>>(gui, "elfDirs", {});
m_recent_files = toml::find_or<std::vector<std::string>>(gui, "recentFiles", {});
m_table_mode = toml::find_or<int>(gui, "gameTableMode", 0);
emulator_language = toml::find_or<std::string>(gui, "emulatorLanguage", "en_US");
backgroundImageOpacity = toml::find_or<int>(gui, "backgroundImageOpacity", 50);
showBackgroundImage = toml::find_or<bool>(gui, "showBackgroundImage", true);
} }
if (data.contains("Settings")) { if (data.contains("Settings")) {
const toml::value& settings = data.at("Settings"); const toml::value& settings = data.at("Settings");
m_language = toml::find_or<int>(settings, "consoleLanguage", m_language);
m_language = toml::find_or<int>(settings, "consoleLanguage", 1);
} }
if (data.contains("Keys")) { if (data.contains("Keys")) {
const toml::value& keys = data.at("Keys"); const toml::value& keys = data.at("Keys");
trophyKey = toml::find_or<std::string>(keys, "TrophyKey", ""); trophyKey = toml::find_or<std::string>(keys, "TrophyKey", trophyKey);
} }
// Check if the loaded language is in the allowed list // Run save after loading to generate any missing fields with default values.
const std::vector<std::string> allowed_languages = { if (config_version != current_version) {
"ar_SA", "da_DK", "de_DE", "el_GR", "en_US", "es_ES", "fa_IR", "fi_FI", "fr_FR", "hu_HU", fmt::print("Outdated config detected, updating config file.\n");
"id_ID", "it_IT", "ja_JP", "ko_KR", "lt_LT", "nb_NO", "nl_NL", "pl_PL", "pt_BR", "pt_PT",
"ro_RO", "ru_RU", "sq_AL", "sv_SE", "tr_TR", "uk_UA", "vi_VN", "zh_CN", "zh_TW"};
if (std::find(allowed_languages.begin(), allowed_languages.end(), emulator_language) ==
allowed_languages.end()) {
emulator_language = "en_US"; // Default to en_US if not in the list
save(path); save(path);
} }
} }
@ -951,35 +817,38 @@ void save(const std::filesystem::path& path) {
fmt::print("Saving new configuration file {}\n", fmt::UTF(path.u8string())); fmt::print("Saving new configuration file {}\n", fmt::UTF(path.u8string()));
} }
data["General"]["volumeSlider"] = volumeSlider;
data["General"]["isPS4Pro"] = isNeo; data["General"]["isPS4Pro"] = isNeo;
data["General"]["isDevKit"] = isDevKit; data["General"]["isDevKit"] = isDevKit;
data["General"]["isPSNSignedIn"] = isPSNSignedIn;
data["General"]["isTrophyPopupDisabled"] = isTrophyPopupDisabled; data["General"]["isTrophyPopupDisabled"] = isTrophyPopupDisabled;
data["General"]["trophyNotificationDuration"] = trophyNotificationDuration; data["General"]["trophyNotificationDuration"] = trophyNotificationDuration;
data["General"]["playBGM"] = playBGM;
data["General"]["BGMvolume"] = BGMvolume;
data["General"]["enableDiscordRPC"] = enableDiscordRPC; data["General"]["enableDiscordRPC"] = enableDiscordRPC;
data["General"]["logFilter"] = logFilter; data["General"]["logFilter"] = logFilter;
data["General"]["logType"] = logType; data["General"]["logType"] = logType;
data["General"]["userName"] = userName; data["General"]["userName"] = userName;
data["General"]["updateChannel"] = updateChannel;
data["General"]["chooseHomeTab"] = chooseHomeTab; data["General"]["chooseHomeTab"] = chooseHomeTab;
data["General"]["showSplash"] = isShowSplash; data["General"]["showSplash"] = isShowSplash;
data["General"]["autoUpdate"] = isAutoUpdate;
data["General"]["alwaysShowChangelog"] = isAlwaysShowChangelog;
data["General"]["sideTrophy"] = isSideTrophy; data["General"]["sideTrophy"] = isSideTrophy;
data["General"]["compatibilityEnabled"] = compatibilityData; data["General"]["compatibilityEnabled"] = compatibilityData;
data["General"]["checkCompatibilityOnStartup"] = checkCompatibilityOnStartup; data["General"]["checkCompatibilityOnStartup"] = checkCompatibilityOnStartup;
data["General"]["isConnectedToNetwork"] = isConnectedToNetwork;
data["Input"]["cursorState"] = cursorState; data["Input"]["cursorState"] = cursorState;
data["Input"]["cursorHideTimeout"] = cursorHideTimeout; data["Input"]["cursorHideTimeout"] = cursorHideTimeout;
data["Input"]["backButtonBehavior"] = backButtonBehavior;
data["Input"]["useSpecialPad"] = useSpecialPad; data["Input"]["useSpecialPad"] = useSpecialPad;
data["Input"]["specialPadClass"] = specialPadClass; data["Input"]["specialPadClass"] = specialPadClass;
data["Input"]["isMotionControlsEnabled"] = isMotionControlsEnabled; data["Input"]["isMotionControlsEnabled"] = isMotionControlsEnabled;
data["Input"]["useUnifiedInputConfig"] = useUnifiedInputConfig; data["Input"]["useUnifiedInputConfig"] = useUnifiedInputConfig;
data["GPU"]["screenWidth"] = screenWidth; data["Input"]["micDevice"] = micDevice;
data["GPU"]["screenHeight"] = screenHeight; data["GPU"]["screenWidth"] = windowWidth;
data["GPU"]["screenHeight"] = windowHeight;
data["GPU"]["internalScreenWidth"] = internalScreenWidth;
data["GPU"]["internalScreenHeight"] = internalScreenHeight;
data["GPU"]["nullGpu"] = isNullGpu; data["GPU"]["nullGpu"] = isNullGpu;
data["GPU"]["copyGPUBuffers"] = shouldCopyGPUBuffers; data["GPU"]["copyGPUBuffers"] = shouldCopyGPUBuffers;
data["GPU"]["readbacks"] = readbacksEnabled;
data["GPU"]["readbackLinearImages"] = readbackLinearImagesEnabled;
data["GPU"]["directMemoryAccess"] = directMemoryAccessEnabled;
data["GPU"]["dumpShaders"] = shouldDumpShaders; data["GPU"]["dumpShaders"] = shouldDumpShaders;
data["GPU"]["patchShaders"] = shouldPatchShaders; data["GPU"]["patchShaders"] = shouldPatchShaders;
data["GPU"]["vblankDivider"] = vblankDivider; data["GPU"]["vblankDivider"] = vblankDivider;
@ -998,6 +867,7 @@ void save(const std::filesystem::path& path) {
data["Debug"]["CollectShader"] = isShaderDebug; data["Debug"]["CollectShader"] = isShaderDebug;
data["Debug"]["isSeparateLogFilesEnabled"] = isSeparateLogFilesEnabled; data["Debug"]["isSeparateLogFilesEnabled"] = isSeparateLogFilesEnabled;
data["Debug"]["FPSColor"] = isFpsColor; data["Debug"]["FPSColor"] = isFpsColor;
data["Debug"]["ConfigVersion"] = config_version;
data["Keys"]["TrophyKey"] = trophyKey; data["Keys"]["TrophyKey"] = trophyKey;
std::vector<std::string> install_dirs; std::vector<std::string> install_dirs;
@ -1034,9 +904,6 @@ void save(const std::filesystem::path& path) {
data["GUI"]["addonInstallDir"] = data["GUI"]["addonInstallDir"] =
std::string{fmt::UTF(settings_addon_install_dir.u8string()).data}; std::string{fmt::UTF(settings_addon_install_dir.u8string()).data};
data["GUI"]["emulatorLanguage"] = emulator_language;
data["GUI"]["backgroundImageOpacity"] = backgroundImageOpacity;
data["GUI"]["showBackgroundImage"] = showBackgroundImage;
data["Settings"]["consoleLanguage"] = m_language; data["Settings"]["consoleLanguage"] = m_language;
// Sorting of TOML sections // Sorting of TOML sections
@ -1045,90 +912,59 @@ void save(const std::filesystem::path& path) {
std::ofstream file(path, std::ios::binary); std::ofstream file(path, std::ios::binary);
file << data; file << data;
file.close(); file.close();
saveMainWindow(path);
}
void saveMainWindow(const std::filesystem::path& path) {
toml::ordered_value data;
std::error_code error;
if (std::filesystem::exists(path, error)) {
try {
std::ifstream ifs;
ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit);
ifs.open(path, std::ios_base::binary);
data = toml::parse<toml::ordered_type_config>(
ifs, std::string{fmt::UTF(path.filename().u8string()).data});
} catch (const std::exception& ex) {
fmt::print("Exception trying to parse config file. Exception: {}\n", ex.what());
return;
}
} else {
if (error) {
fmt::print("Filesystem error: {}\n", error.message());
}
fmt::print("Saving new configuration file {}\n", fmt::UTF(path.u8string()));
}
data["GUI"]["mw_width"] = m_window_size_W;
data["GUI"]["mw_height"] = m_window_size_H;
data["GUI"]["theme"] = mw_themes;
data["GUI"]["iconSize"] = m_icon_size;
data["GUI"]["sliderPos"] = m_slider_pos;
data["GUI"]["iconSizeGrid"] = m_icon_size_grid;
data["GUI"]["sliderPosGrid"] = m_slider_pos_grid;
data["GUI"]["gameTableMode"] = m_table_mode;
data["GUI"]["geometry_x"] = main_window_geometry_x;
data["GUI"]["geometry_y"] = main_window_geometry_y;
data["GUI"]["geometry_w"] = main_window_geometry_w;
data["GUI"]["geometry_h"] = main_window_geometry_h;
data["GUI"]["elfDirs"] = m_elf_viewer;
data["GUI"]["recentFiles"] = m_recent_files;
// Sorting of TOML sections
sortTomlSections(data);
std::ofstream file(path, std::ios::binary);
file << data;
file.close();
} }
void setDefaultValues() { void setDefaultValues() {
isHDRAllowed = false; // General
volumeSlider = 100;
isNeo = false; isNeo = false;
isDevKit = false; isDevKit = false;
isFullscreen = false; isPSNSignedIn = false;
isTrophyPopupDisabled = false; isTrophyPopupDisabled = false;
playBGM = false; trophyNotificationDuration = 6.0;
BGMvolume = 50; enableDiscordRPC = false;
enableDiscordRPC = true;
screenWidth = 1280;
screenHeight = 720;
logFilter = ""; logFilter = "";
logType = "sync"; logType = "sync";
userName = "shadPS4"; userName = "shadPS4";
if (Common::g_is_release) {
updateChannel = "Release";
} else {
updateChannel = "Nightly";
}
chooseHomeTab = "General"; chooseHomeTab = "General";
isShowSplash = false;
isSideTrophy = "right";
compatibilityData = false;
checkCompatibilityOnStartup = false;
isConnectedToNetwork = false;
// Input
cursorState = HideCursorState::Idle; cursorState = HideCursorState::Idle;
cursorHideTimeout = 5; cursorHideTimeout = 5;
trophyNotificationDuration = 6.0;
backButtonBehavior = "left";
useSpecialPad = false; useSpecialPad = false;
specialPadClass = 1; specialPadClass = 1;
isDebugDump = false; isMotionControlsEnabled = true;
isShaderDebug = false; useUnifiedInputConfig = true;
isShowSplash = false; overrideControllerColor = false;
isAutoUpdate = false; controllerCustomColorRGB[0] = 0;
isAlwaysShowChangelog = false; controllerCustomColorRGB[1] = 0;
isSideTrophy = "right"; controllerCustomColorRGB[2] = 255;
micDevice = "Default Device";
// GPU
windowWidth = 1280;
windowHeight = 720;
internalScreenWidth = 1280;
internalScreenHeight = 720;
isNullGpu = false; isNullGpu = false;
shouldCopyGPUBuffers = false;
readbacksEnabled = false;
readbackLinearImagesEnabled = false;
directMemoryAccessEnabled = false;
shouldDumpShaders = false; shouldDumpShaders = false;
shouldPatchShaders = false;
vblankDivider = 1; vblankDivider = 1;
isFullscreen = false;
fullscreenMode = "Windowed";
isHDRAllowed = false;
// Vulkan
gpuId = -1;
vkValidation = false; vkValidation = false;
vkValidationSync = false; vkValidationSync = false;
vkValidationGpu = false; vkValidationGpu = false;
@ -1136,13 +972,18 @@ void setDefaultValues() {
vkHostMarkers = false; vkHostMarkers = false;
vkGuestMarkers = false; vkGuestMarkers = false;
rdocEnable = false; rdocEnable = false;
emulator_language = "en_US";
// Debug
isDebugDump = false;
isShaderDebug = false;
isSeparateLogFilesEnabled = false;
isFpsColor = true;
// GUI
load_game_size = true;
// Settings
m_language = 1; m_language = 1;
gpuId = -1;
compatibilityData = false;
checkCompatibilityOnStartup = false;
backgroundImageOpacity = 50;
showBackgroundImage = true;
} }
constexpr std::string_view GetDefaultKeyboardConfig() { constexpr std::string_view GetDefaultKeyboardConfig() {
@ -1168,7 +1009,7 @@ l3 = x
r3 = m r3 = m
options = enter options = enter
touchpad = space touchpad_center = space
pad_up = up pad_up = up
pad_down = down pad_down = down
@ -1200,7 +1041,7 @@ r2 = r2
r3 = r3 r3 = r3
options = options options = options
touchpad = back touchpad_center = back
pad_up = pad_up pad_up = pad_up
pad_down = pad_down pad_down = pad_down

View File

@ -14,172 +14,134 @@ struct GameInstallDir {
bool enabled; bool enabled;
}; };
enum HideCursorState : s16 { Never, Idle, Always }; enum HideCursorState : int { Never, Idle, Always };
void load(const std::filesystem::path& path); void load(const std::filesystem::path& path);
void save(const std::filesystem::path& path); void save(const std::filesystem::path& path);
void saveMainWindow(const std::filesystem::path& path);
int getVolumeSlider();
void setVolumeSlider(int volumeValue);
std::string getTrophyKey(); std::string getTrophyKey();
void setTrophyKey(std::string key); void setTrophyKey(std::string key);
bool getIsFullscreen();
void setIsFullscreen(bool enable);
std::string getFullscreenMode();
void setFullscreenMode(std::string mode);
u32 getWindowWidth();
u32 getWindowHeight();
void setWindowWidth(u32 width);
void setWindowHeight(u32 height);
u32 getInternalScreenWidth();
u32 getInternalScreenHeight();
void setInternalScreenWidth(u32 width);
void setInternalScreenHeight(u32 height);
bool debugDump();
void setDebugDump(bool enable);
s32 getGpuId();
void setGpuId(s32 selectedGpuId);
bool allowHDR();
void setAllowHDR(bool enable);
bool collectShadersForDebug();
void setCollectShaderForDebug(bool enable);
bool showSplash();
void setShowSplash(bool enable);
std::string sideTrophy();
void setSideTrophy(std::string side);
bool nullGpu();
void setNullGpu(bool enable);
bool copyGPUCmdBuffers();
void setCopyGPUCmdBuffers(bool enable);
bool readbacks();
void setReadbacks(bool enable);
bool readbackLinearImages();
bool directMemoryAccess();
void setDirectMemoryAccess(bool enable);
bool dumpShaders();
void setDumpShaders(bool enable);
u32 vblankDiv();
void setVblankDiv(u32 value);
bool getisTrophyPopupDisabled();
void setisTrophyPopupDisabled(bool disable);
s16 getCursorState();
void setCursorState(s16 cursorState);
bool vkValidationEnabled();
void setVkValidation(bool enable);
bool vkValidationSyncEnabled();
void setVkSyncValidation(bool enable);
bool getVkCrashDiagnosticEnabled();
void setVkCrashDiagnosticEnabled(bool enable);
bool getVkHostMarkersEnabled();
void setVkHostMarkersEnabled(bool enable);
bool getVkGuestMarkersEnabled();
void setVkGuestMarkersEnabled(bool enable);
bool getEnableDiscordRPC();
void setEnableDiscordRPC(bool enable);
bool isRdocEnabled();
void setRdocEnabled(bool enable);
std::string getLogType();
void setLogType(const std::string& type);
std::string getLogFilter();
void setLogFilter(const std::string& type);
double getTrophyNotificationDuration();
void setTrophyNotificationDuration(double newTrophyNotificationDuration);
int getCursorHideTimeout();
std::string getMicDevice();
void setCursorHideTimeout(int newcursorHideTimeout);
void setMicDevice(std::string device);
void setSeparateLogFilesEnabled(bool enabled);
bool getSeparateLogFilesEnabled();
u32 GetLanguage();
void setLanguage(u32 language);
void setUseSpecialPad(bool use);
bool getUseSpecialPad();
void setSpecialPadClass(int type);
int getSpecialPadClass();
bool getPSNSignedIn();
void setPSNSignedIn(bool sign); // no ui setting
bool patchShaders(); // no set
bool fpsColor(); // no set
bool isNeoModeConsole();
void setNeoMode(bool enable); // no ui setting
bool isDevKitConsole(); // no set
bool vkValidationGpuEnabled(); // no set
bool getIsMotionControlsEnabled();
void setIsMotionControlsEnabled(bool use);
// TODO
bool GetLoadGameSizeEnabled(); bool GetLoadGameSizeEnabled();
std::filesystem::path GetSaveDataPath(); std::filesystem::path GetSaveDataPath();
void setLoadGameSizeEnabled(bool enable); void setLoadGameSizeEnabled(bool enable);
bool getIsFullscreen();
bool getShowLabelsUnderIcons();
bool setShowLabelsUnderIcons();
std::string getFullscreenMode();
bool isNeoModeConsole();
bool isDevKitConsole();
bool getPlayBGM();
int getBGMvolume();
bool getisTrophyPopupDisabled();
bool getEnableDiscordRPC();
bool getCompatibilityEnabled(); bool getCompatibilityEnabled();
bool getCheckCompatibilityOnStartup(); bool getCheckCompatibilityOnStartup();
int getBackgroundImageOpacity(); bool getIsConnectedToNetwork();
bool getShowBackgroundImage();
std::string getLogFilter();
std::string getLogType();
std::string getUserName(); std::string getUserName();
std::string getUpdateChannel();
std::string getChooseHomeTab(); std::string getChooseHomeTab();
s16 getCursorState();
int getCursorHideTimeout();
double getTrophyNotificationDuration();
std::string getBackButtonBehavior();
bool getUseSpecialPad();
int getSpecialPadClass();
bool getIsMotionControlsEnabled();
bool GetUseUnifiedInputConfig(); bool GetUseUnifiedInputConfig();
void SetUseUnifiedInputConfig(bool use); void SetUseUnifiedInputConfig(bool use);
bool GetOverrideControllerColor(); bool GetOverrideControllerColor();
void SetOverrideControllerColor(bool enable); void SetOverrideControllerColor(bool enable);
int* GetControllerCustomColor(); int* GetControllerCustomColor();
void SetControllerCustomColor(int r, int b, int g); void SetControllerCustomColor(int r, int b, int g);
u32 getScreenWidth();
u32 getScreenHeight();
s32 getGpuId();
bool allowHDR();
bool debugDump();
bool collectShadersForDebug();
bool showSplash();
bool autoUpdate();
bool alwaysShowChangelog();
std::string sideTrophy();
bool nullGpu();
bool copyGPUCmdBuffers();
bool dumpShaders();
bool patchShaders();
bool isRdocEnabled();
bool fpsColor();
u32 vblankDiv();
void setDebugDump(bool enable);
void setCollectShaderForDebug(bool enable);
void setShowSplash(bool enable);
void setAutoUpdate(bool enable);
void setAlwaysShowChangelog(bool enable);
void setSideTrophy(std::string side);
void setNullGpu(bool enable);
void setAllowHDR(bool enable);
void setCopyGPUCmdBuffers(bool enable);
void setDumpShaders(bool enable);
void setVblankDiv(u32 value);
void setGpuId(s32 selectedGpuId);
void setScreenWidth(u32 width);
void setScreenHeight(u32 height);
void setIsFullscreen(bool enable);
void setFullscreenMode(std::string mode);
void setisTrophyPopupDisabled(bool disable);
void setPlayBGM(bool enable);
void setBGMvolume(int volume);
void setEnableDiscordRPC(bool enable);
void setLanguage(u32 language);
void setNeoMode(bool enable);
void setUserName(const std::string& type); void setUserName(const std::string& type);
void setUpdateChannel(const std::string& type);
void setChooseHomeTab(const std::string& type); void setChooseHomeTab(const std::string& type);
void setGameInstallDirs(const std::vector<std::filesystem::path>& dirs_config); void setGameInstallDirs(const std::vector<std::filesystem::path>& dirs_config);
void setAllGameInstallDirs(const std::vector<GameInstallDir>& dirs_config); void setAllGameInstallDirs(const std::vector<GameInstallDir>& dirs_config);
void setSaveDataPath(const std::filesystem::path& path); void setSaveDataPath(const std::filesystem::path& path);
void setCompatibilityEnabled(bool use); void setCompatibilityEnabled(bool use);
void setCheckCompatibilityOnStartup(bool use); void setCheckCompatibilityOnStartup(bool use);
void setBackgroundImageOpacity(int opacity);
void setShowBackgroundImage(bool show);
void setCursorState(s16 cursorState);
void setCursorHideTimeout(int newcursorHideTimeout);
void setTrophyNotificationDuration(double newTrophyNotificationDuration);
void setBackButtonBehavior(const std::string& type);
void setUseSpecialPad(bool use);
void setSpecialPadClass(int type);
void setIsMotionControlsEnabled(bool use);
void setLogType(const std::string& type);
void setLogFilter(const std::string& type);
void setSeparateLogFilesEnabled(bool enabled);
bool getSeparateLogFilesEnabled();
void setVkValidation(bool enable);
void setVkSyncValidation(bool enable);
void setRdocEnabled(bool enable);
bool vkValidationEnabled();
bool vkValidationSyncEnabled();
bool vkValidationGpuEnabled();
bool getVkCrashDiagnosticEnabled();
bool getVkHostMarkersEnabled();
bool getVkGuestMarkersEnabled();
void setVkCrashDiagnosticEnabled(bool enable);
void setVkHostMarkersEnabled(bool enable);
void setVkGuestMarkersEnabled(bool enable);
// Gui // Gui
void setMainWindowGeometry(u32 x, u32 y, u32 w, u32 h);
bool addGameInstallDir(const std::filesystem::path& dir, bool enabled = true); bool addGameInstallDir(const std::filesystem::path& dir, bool enabled = true);
void removeGameInstallDir(const std::filesystem::path& dir); void removeGameInstallDir(const std::filesystem::path& dir);
void setGameInstallDirEnabled(const std::filesystem::path& dir, bool enabled); void setGameInstallDirEnabled(const std::filesystem::path& dir, bool enabled);
void setAddonInstallDir(const std::filesystem::path& dir); void setAddonInstallDir(const std::filesystem::path& dir);
void setMainWindowTheme(u32 theme);
void setIconSize(u32 size);
void setIconSizeGrid(u32 size);
void setSliderPosition(u32 pos);
void setSliderPositionGrid(u32 pos);
void setTableMode(u32 mode);
void setMainWindowWidth(u32 width);
void setMainWindowHeight(u32 height);
void setElfViewer(const std::vector<std::string>& elfList);
void setRecentFiles(const std::vector<std::string>& recentFiles);
void setEmulatorLanguage(std::string language);
u32 getMainWindowGeometryX();
u32 getMainWindowGeometryY();
u32 getMainWindowGeometryW();
u32 getMainWindowGeometryH();
const std::vector<std::filesystem::path> getGameInstallDirs(); const std::vector<std::filesystem::path> getGameInstallDirs();
const std::vector<bool> getGameInstallDirsEnabled(); const std::vector<bool> getGameInstallDirsEnabled();
std::filesystem::path getAddonInstallDir(); std::filesystem::path getAddonInstallDir();
u32 getMainWindowTheme();
u32 getIconSize();
u32 getIconSizeGrid();
u32 getSliderPosition();
u32 getSliderPositionGrid();
u32 getTableMode();
u32 getMainWindowWidth();
u32 getMainWindowHeight();
std::vector<std::string> getElfViewer();
std::vector<std::string> getRecentFiles();
std::string getEmulatorLanguage();
void setDefaultValues(); void setDefaultValues();
// todo: name and function location pending // todo: name and function location pending
std::filesystem::path GetFoolproofKbmConfigFile(const std::string& game_id = ""); std::filesystem::path GetFoolproofKbmConfigFile(const std::string& game_id = "");
// settings
u32 GetLanguage();
}; // namespace Config }; // namespace Config

View File

@ -71,6 +71,7 @@ class ElfInfo {
PSFAttributes psf_attributes{}; PSFAttributes psf_attributes{};
std::filesystem::path splash_path{}; std::filesystem::path splash_path{};
std::filesystem::path game_folder{};
public: public:
static constexpr u32 FW_15 = 0x1500000; static constexpr u32 FW_15 = 0x1500000;
@ -123,6 +124,10 @@ public:
[[nodiscard]] const std::filesystem::path& GetSplashPath() const { [[nodiscard]] const std::filesystem::path& GetSplashPath() const {
return splash_path; return splash_path;
} }
[[nodiscard]] const std::filesystem::path& GetGameFolder() const {
return game_folder;
}
}; };
} // namespace Common } // namespace Common

View File

@ -131,9 +131,7 @@ namespace {
case SeekOrigin::End: case SeekOrigin::End:
return SEEK_END; return SEEK_END;
default: default:
LOG_ERROR(Common_Filesystem, "Unsupported origin {}, defaulting to SEEK_SET", UNREACHABLE_MSG("Impossible SeekOrigin {}", static_cast<u32>(origin));
static_cast<u32>(origin));
return SEEK_SET;
} }
} }

View File

@ -61,8 +61,6 @@ enum class SeekOrigin : u32 {
SetOrigin, // Seeks from the start of the file. SetOrigin, // Seeks from the start of the file.
CurrentPosition, // Seeks from the current file pointer position. CurrentPosition, // Seeks from the current file pointer position.
End, // Seeks from the end of the file. End, // Seeks from the end of the file.
SeekHole, // Seeks from the start of the next hole in the file.
SeekData, // Seeks from the start of the next non-hole region in the file.
}; };
class IOFile final { class IOFile final {
@ -188,7 +186,9 @@ public:
template <typename T> template <typename T>
size_t WriteRaw(const void* data, size_t size) const { size_t WriteRaw(const void* data, size_t size) const {
return std::fwrite(data, sizeof(T), size, file); auto bytes = std::fwrite(data, sizeof(T), size, file);
std::fflush(file);
return bytes;
} }
template <typename T> template <typename T>

View File

@ -137,6 +137,11 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
SUB(Lib, NpParty) \ SUB(Lib, NpParty) \
SUB(Lib, Zlib) \ SUB(Lib, Zlib) \
SUB(Lib, Hmd) \ SUB(Lib, Hmd) \
SUB(Lib, SigninDialog) \
SUB(Lib, Camera) \
SUB(Lib, CompanionHttpd) \
SUB(Lib, CompanionUtil) \
SUB(Lib, Voice) \
CLS(Frontend) \ CLS(Frontend) \
CLS(Render) \ CLS(Render) \
SUB(Render, Vulkan) \ SUB(Render, Vulkan) \

View File

@ -98,12 +98,17 @@ enum class Class : u8 {
Lib_Fiber, ///< The LibSceFiber implementation. Lib_Fiber, ///< The LibSceFiber implementation.
Lib_Vdec2, ///< The LibSceVideodec2 implementation. Lib_Vdec2, ///< The LibSceVideodec2 implementation.
Lib_Videodec, ///< The LibSceVideodec implementation. Lib_Videodec, ///< The LibSceVideodec implementation.
Lib_Voice, ///< The LibSceVoice implementation.
Lib_RazorCpu, ///< The LibRazorCpu implementation. Lib_RazorCpu, ///< The LibRazorCpu implementation.
Lib_Mouse, ///< The LibSceMouse implementation Lib_Mouse, ///< The LibSceMouse implementation
Lib_WebBrowserDialog, ///< The LibSceWebBrowserDialog implementation Lib_WebBrowserDialog, ///< The LibSceWebBrowserDialog implementation
Lib_NpParty, ///< The LibSceNpParty implementation Lib_NpParty, ///< The LibSceNpParty implementation
Lib_Zlib, ///< The LibSceZlib implementation. Lib_Zlib, ///< The LibSceZlib implementation.
Lib_Hmd, ///< The LibSceHmd implementation. Lib_Hmd, ///< The LibSceHmd implementation.
Lib_SigninDialog, ///< The LibSigninDialog implementation.
Lib_Camera, ///< The LibCamera implementation.
Lib_CompanionHttpd, ///< The LibCompanionHttpd implementation.
Lib_CompanionUtil, ///< The LibCompanionUtil implementation.
Frontend, ///< Emulator UI Frontend, ///< Emulator UI
Render, ///< Video Core Render, ///< Video Core
Render_Vulkan, ///< Vulkan backend Render_Vulkan, ///< Vulkan backend

View File

@ -23,7 +23,7 @@
namespace MemoryPatcher { namespace MemoryPatcher {
uintptr_t g_eboot_address; EXPORT uintptr_t g_eboot_address;
uint64_t g_eboot_image_size; uint64_t g_eboot_image_size;
std::string g_game_serial; std::string g_game_serial;
std::string patchFile; std::string patchFile;
@ -169,7 +169,8 @@ void OnGameLoaded() {
if (type == "mask_jump32") if (type == "mask_jump32")
patchMask = MemoryPatcher::PatchMask::Mask_Jump32; patchMask = MemoryPatcher::PatchMask::Mask_Jump32;
if (type == "mask" || type == "mask_jump32" && !maskOffsetStr.empty()) { if ((type == "mask" || type == "mask_jump32") &&
!maskOffsetStr.empty()) {
maskOffsetValue = std::stoi(maskOffsetStr, 0, 10); maskOffsetValue = std::stoi(maskOffsetStr, 0, 10);
} }

View File

@ -6,9 +6,15 @@
#include <string> #include <string>
#include <vector> #include <vector>
#if defined(WIN32)
#define EXPORT __declspec(dllexport)
#else
#define EXPORT __attribute__((visibility("default")))
#endif
namespace MemoryPatcher { namespace MemoryPatcher {
extern uintptr_t g_eboot_address; extern EXPORT uintptr_t g_eboot_address;
extern uint64_t g_eboot_image_size; extern uint64_t g_eboot_image_size;
extern std::string g_game_serial; extern std::string g_game_serial;
extern std::string patchFile; extern std::string patchFile;

View File

@ -128,7 +128,6 @@ static auto UserPaths = [] {
create_path(PathType::LogDir, user_dir / LOG_DIR); create_path(PathType::LogDir, user_dir / LOG_DIR);
create_path(PathType::ScreenshotsDir, user_dir / SCREENSHOTS_DIR); create_path(PathType::ScreenshotsDir, user_dir / SCREENSHOTS_DIR);
create_path(PathType::ShaderDir, user_dir / SHADER_DIR); create_path(PathType::ShaderDir, user_dir / SHADER_DIR);
create_path(PathType::SaveDataDir, user_dir / SAVEDATA_DIR);
create_path(PathType::GameDataDir, user_dir / GAMEDATA_DIR); create_path(PathType::GameDataDir, user_dir / GAMEDATA_DIR);
create_path(PathType::TempDataDir, user_dir / TEMPDATA_DIR); create_path(PathType::TempDataDir, user_dir / TEMPDATA_DIR);
create_path(PathType::SysModuleDir, user_dir / SYSMODULES_DIR); create_path(PathType::SysModuleDir, user_dir / SYSMODULES_DIR);

View File

@ -18,7 +18,6 @@ enum class PathType {
LogDir, // Where log files are stored. LogDir, // Where log files are stored.
ScreenshotsDir, // Where screenshots are stored. ScreenshotsDir, // Where screenshots are stored.
ShaderDir, // Where shaders are stored. ShaderDir, // Where shaders are stored.
SaveDataDir, // Where guest save data is stored.
TempDataDir, // Where game temp data is stored. TempDataDir, // Where game temp data is stored.
GameDataDir, // Where game data is stored. GameDataDir, // Where game data is stored.
SysModuleDir, // Where system modules are stored. SysModuleDir, // Where system modules are stored.
@ -36,7 +35,6 @@ constexpr auto PORTABLE_DIR = "user";
constexpr auto LOG_DIR = "log"; constexpr auto LOG_DIR = "log";
constexpr auto SCREENSHOTS_DIR = "screenshots"; constexpr auto SCREENSHOTS_DIR = "screenshots";
constexpr auto SHADER_DIR = "shader"; constexpr auto SHADER_DIR = "shader";
constexpr auto SAVEDATA_DIR = "savedata";
constexpr auto GAMEDATA_DIR = "data"; constexpr auto GAMEDATA_DIR = "data";
constexpr auto TEMPDATA_DIR = "temp"; constexpr auto TEMPDATA_DIR = "temp";
constexpr auto SYSMODULES_DIR = "sys_modules"; constexpr auto SYSMODULES_DIR = "sys_modules";

101
src/common/range_lock.h Normal file
View File

@ -0,0 +1,101 @@
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <iterator>
#include <mutex>
namespace Common {
// From boost thread locking
template <typename Iterator>
struct RangeLockGuard {
Iterator begin;
Iterator end;
RangeLockGuard(Iterator begin_, Iterator end_) : begin(begin_), end(end_) {
LockRange(begin, end);
}
void release() {
begin = end;
}
~RangeLockGuard() {
for (; begin != end; ++begin) {
begin->unlock();
}
}
};
template <typename Iterator>
Iterator TryLockRange(Iterator begin, Iterator end) {
using LockType = typename std::iterator_traits<Iterator>::value_type;
if (begin == end) {
return end;
}
std::unique_lock<LockType> guard(*begin, std::try_to_lock);
if (!guard.owns_lock()) {
return begin;
}
Iterator failed = TryLockRange(++begin, end);
if (failed == end) {
guard.release();
}
return failed;
}
template <typename Iterator>
void LockRange(Iterator begin, Iterator end) {
using LockType = typename std::iterator_traits<Iterator>::value_type;
if (begin == end) {
return;
}
bool start_with_begin = true;
Iterator second = begin;
++second;
Iterator next = second;
while (true) {
std::unique_lock<LockType> begin_lock(*begin, std::defer_lock);
if (start_with_begin) {
begin_lock.lock();
const Iterator failed_lock = TryLockRange(next, end);
if (failed_lock == end) {
begin_lock.release();
return;
}
start_with_begin = false;
next = failed_lock;
} else {
RangeLockGuard<Iterator> guard(next, end);
if (begin_lock.try_lock()) {
const Iterator failed_lock = TryLockRange(second, next);
if (failed_lock == next) {
begin_lock.release();
guard.release();
return;
}
start_with_begin = false;
next = failed_lock;
} else {
start_with_begin = true;
next = second;
}
}
}
}
} // namespace Common

View File

@ -0,0 +1,37 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <unordered_map>
#include "common/assert.h"
#include "common/recursive_lock.h"
namespace Common::Detail {
struct RecursiveLockState {
RecursiveLockType type;
int count;
};
thread_local std::unordered_map<void*, RecursiveLockState> g_recursive_locks;
bool IncrementRecursiveLock(void* mutex, RecursiveLockType type) {
auto& state = g_recursive_locks[mutex];
if (state.count == 0) {
ASSERT(state.type == RecursiveLockType::None);
state.type = type;
}
ASSERT(state.type == type);
return state.count++ == 0;
}
bool DecrementRecursiveLock(void* mutex, RecursiveLockType type) {
auto& state = g_recursive_locks[mutex];
ASSERT(state.type == type && state.count > 0);
if (--state.count == 0) {
g_recursive_locks.erase(mutex);
return true;
}
return false;
}
} // namespace Common::Detail

View File

@ -0,0 +1,67 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <mutex>
#include <optional>
#include <shared_mutex>
namespace Common {
namespace Detail {
enum class RecursiveLockType { None, Shared, Exclusive };
bool IncrementRecursiveLock(void* mutex, RecursiveLockType type);
bool DecrementRecursiveLock(void* mutex, RecursiveLockType type);
} // namespace Detail
template <typename MutexType>
class RecursiveScopedLock {
public:
explicit RecursiveScopedLock(MutexType& mutex) : m_mutex(mutex), m_locked(false) {
if (Detail::IncrementRecursiveLock(&m_mutex, Detail::RecursiveLockType::Exclusive)) {
m_locked = true;
m_lock.emplace(m_mutex);
}
}
~RecursiveScopedLock() {
Detail::DecrementRecursiveLock(&m_mutex, Detail::RecursiveLockType::Exclusive);
if (m_locked) {
m_lock.reset();
}
}
private:
MutexType& m_mutex;
std::optional<std::unique_lock<MutexType>> m_lock;
bool m_locked = false;
};
template <typename MutexType>
class RecursiveSharedLock {
public:
explicit RecursiveSharedLock(MutexType& mutex) : m_mutex(mutex), m_locked(false) {
if (Detail::IncrementRecursiveLock(&m_mutex, Detail::RecursiveLockType::Shared)) {
m_locked = true;
m_lock.emplace(m_mutex);
}
}
~RecursiveSharedLock() {
Detail::DecrementRecursiveLock(&m_mutex, Detail::RecursiveLockType::Shared);
if (m_locked) {
m_lock.reset();
}
}
private:
MutexType& m_mutex;
std::optional<std::shared_lock<MutexType>> m_lock;
bool m_locked = false;
};
} // namespace Common

View File

@ -1,6 +1,8 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <string>
#include "common/scm_rev.h" #include "common/scm_rev.h"
namespace Common { namespace Common {
@ -15,5 +17,26 @@ constexpr char g_scm_remote_name[] = "@GIT_REMOTE_NAME@";
constexpr char g_scm_remote_url[] = "@GIT_REMOTE_URL@"; constexpr char g_scm_remote_url[] = "@GIT_REMOTE_URL@";
constexpr char g_scm_date[] = "@BUILD_DATE@"; constexpr char g_scm_date[] = "@BUILD_DATE@";
const std::string GetRemoteNameFromLink() {
std::string remote_url(Common::g_scm_remote_url);
std::string remote_host;
try {
if (remote_url.starts_with("http")) {
if (*remote_url.rbegin() == '/') {
remote_url.pop_back();
}
remote_host = remote_url.substr(19, remote_url.rfind('/') - 19);
} else if (remote_url.starts_with("git@")) {
auto after_comma_pos = remote_url.find(':') + 1, slash_pos = remote_url.find('/');
remote_host = remote_url.substr(after_comma_pos, slash_pos - after_comma_pos);
} else {
remote_host = "unknown";
}
} catch (...) {
remote_host = "unknown";
}
return remote_host;
}
} // namespace } // namespace

View File

@ -3,6 +3,8 @@
#pragma once #pragma once
#include <string>
namespace Common { namespace Common {
extern const char g_version[]; extern const char g_version[];
@ -15,4 +17,6 @@ extern const char g_scm_remote_name[];
extern const char g_scm_remote_url[]; extern const char g_scm_remote_url[];
extern const char g_scm_date[]; extern const char g_scm_date[];
const std::string GetRemoteNameFromLink();
} // namespace Common } // namespace Common

View File

@ -0,0 +1,46 @@
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <condition_variable>
#include <mutex>
namespace Common {
// Like std::shared_mutex, but reader has priority over writer.
class SharedFirstMutex {
public:
void lock() {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, [this]() { return !writer_active && readers == 0; });
writer_active = true;
}
void unlock() {
std::lock_guard<std::mutex> lock(mtx);
writer_active = false;
cv.notify_all();
}
void lock_shared() {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, [this]() { return !writer_active; });
++readers;
}
void unlock_shared() {
std::lock_guard<std::mutex> lock(mtx);
if (--readers == 0) {
cv.notify_all();
}
}
private:
std::mutex mtx;
std::condition_variable cv;
int readers = 0;
bool writer_active = false;
};
} // namespace Common

View File

@ -14,6 +14,9 @@ namespace Common {
struct SlotId { struct SlotId {
static constexpr u32 INVALID_INDEX = std::numeric_limits<u32>::max(); static constexpr u32 INVALID_INDEX = std::numeric_limits<u32>::max();
SlotId() noexcept = default;
constexpr SlotId(u32 index) noexcept : index(index) {}
constexpr auto operator<=>(const SlotId&) const noexcept = default; constexpr auto operator<=>(const SlotId&) const noexcept = default;
constexpr explicit operator bool() const noexcept { constexpr explicit operator bool() const noexcept {
@ -28,6 +31,63 @@ class SlotVector {
constexpr static std::size_t InitialCapacity = 2048; constexpr static std::size_t InitialCapacity = 2048;
public: public:
template <typename ValueType, typename Pointer, typename Reference>
class Iterator {
public:
using iterator_category = std::forward_iterator_tag;
using value_type = ValueType;
using difference_type = std::ptrdiff_t;
using pointer = Pointer;
using reference = Reference;
Iterator(SlotVector& vector_, SlotId index_) : vector(vector_), slot(index_) {
AdvanceToValid();
}
reference operator*() const {
return vector[slot];
}
pointer operator->() const {
return &vector[slot];
}
Iterator& operator++() {
++slot.index;
AdvanceToValid();
return *this;
}
Iterator operator++(int) {
Iterator temp = *this;
++(*this);
return temp;
}
bool operator==(const Iterator& other) const {
return slot == other.slot;
}
bool operator!=(const Iterator& other) const {
return !(*this == other);
}
private:
void AdvanceToValid() {
while (slot < vector.values_capacity && !vector.ReadStorageBit(slot.index)) {
++slot.index;
}
}
SlotVector& vector;
SlotId slot;
};
using iterator = Iterator<T, T*, T&>;
using const_iterator = Iterator<const T, const T*, const T&>;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
SlotVector() { SlotVector() {
Reserve(InitialCapacity); Reserve(InitialCapacity);
} }
@ -60,7 +120,7 @@ public:
} }
template <typename... Args> template <typename... Args>
[[nodiscard]] SlotId insert(Args&&... args) noexcept { SlotId insert(Args&&... args) noexcept {
const u32 index = FreeValueIndex(); const u32 index = FreeValueIndex();
new (&values[index].object) T(std::forward<Args>(args)...); new (&values[index].object) T(std::forward<Args>(args)...);
SetStorageBit(index); SetStorageBit(index);
@ -78,6 +138,54 @@ public:
return values_capacity - free_list.size(); return values_capacity - free_list.size();
} }
iterator begin() noexcept {
return iterator(*this, 0);
}
const_iterator begin() const noexcept {
return const_iterator(*this, 0);
}
const_iterator cbegin() const noexcept {
return begin();
}
iterator end() noexcept {
return iterator(*this, values_capacity);
}
const_iterator end() const noexcept {
return const_iterator(*this, values_capacity);
}
const_iterator cend() const noexcept {
return end();
}
reverse_iterator rbegin() noexcept {
return reverse_iterator(end());
}
const_reverse_iterator rbegin() const noexcept {
return const_reverse_iterator(end());
}
const_reverse_iterator crbegin() const noexcept {
return rbegin();
}
reverse_iterator rend() noexcept {
return reverse_iterator(begin());
}
const_reverse_iterator rend() const noexcept {
return const_reverse_iterator(begin());
}
const_reverse_iterator crend() const noexcept {
return rend();
}
private: private:
struct NonTrivialDummy { struct NonTrivialDummy {
NonTrivialDummy() noexcept {} NonTrivialDummy() noexcept {}

View File

@ -2,6 +2,7 @@
// SPDX-FileCopyrightText: 2014 Citra Emulator Project // SPDX-FileCopyrightText: 2014 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <ctime>
#include <string> #include <string>
#include <thread> #include <thread>
@ -104,14 +105,24 @@ void SetCurrentThreadPriority(ThreadPriority new_priority) {
SetThreadPriority(handle, windows_priority); SetThreadPriority(handle, windows_priority);
} }
static void AccurateSleep(std::chrono::nanoseconds duration) { bool AccurateSleep(const std::chrono::nanoseconds duration, std::chrono::nanoseconds* remaining,
const bool interruptible) {
const auto begin_sleep = std::chrono::high_resolution_clock::now();
LARGE_INTEGER interval{ LARGE_INTEGER interval{
.QuadPart = -1 * (duration.count() / 100u), .QuadPart = -1 * (duration.count() / 100u),
}; };
HANDLE timer = ::CreateWaitableTimer(NULL, TRUE, NULL); HANDLE timer = ::CreateWaitableTimer(NULL, TRUE, NULL);
SetWaitableTimer(timer, &interval, 0, NULL, NULL, 0); SetWaitableTimer(timer, &interval, 0, NULL, NULL, 0);
WaitForSingleObject(timer, INFINITE); const auto ret = WaitForSingleObjectEx(timer, INFINITE, interruptible);
::CloseHandle(timer); ::CloseHandle(timer);
if (remaining) {
const auto end_sleep = std::chrono::high_resolution_clock::now();
const auto sleep_time = end_sleep - begin_sleep;
*remaining = duration > sleep_time ? duration - sleep_time : std::chrono::nanoseconds(0);
}
return ret == WAIT_OBJECT_0;
} }
#else #else
@ -134,8 +145,24 @@ void SetCurrentThreadPriority(ThreadPriority new_priority) {
pthread_setschedparam(this_thread, scheduling_type, &params); pthread_setschedparam(this_thread, scheduling_type, &params);
} }
static void AccurateSleep(std::chrono::nanoseconds duration) { bool AccurateSleep(const std::chrono::nanoseconds duration, std::chrono::nanoseconds* remaining,
std::this_thread::sleep_for(duration); const bool interruptible) {
timespec request = {
.tv_sec = duration.count() / 1'000'000'000,
.tv_nsec = duration.count() % 1'000'000'000,
};
timespec remain;
int ret;
while ((ret = nanosleep(&request, &remain)) < 0 && errno == EINTR) {
if (interruptible) {
break;
}
request = remain;
}
if (remaining) {
*remaining = std::chrono::nanoseconds(remain.tv_sec * 1'000'000'000 + remain.tv_nsec);
}
return ret == 0 || errno != EINTR;
} }
#endif #endif
@ -196,9 +223,9 @@ AccurateTimer::AccurateTimer(std::chrono::nanoseconds target_interval)
: target_interval(target_interval) {} : target_interval(target_interval) {}
void AccurateTimer::Start() { void AccurateTimer::Start() {
auto begin_sleep = std::chrono::high_resolution_clock::now(); const auto begin_sleep = std::chrono::high_resolution_clock::now();
if (total_wait.count() > 0) { if (total_wait.count() > 0) {
AccurateSleep(total_wait); AccurateSleep(total_wait, nullptr, false);
} }
start_time = std::chrono::high_resolution_clock::now(); start_time = std::chrono::high_resolution_clock::now();
total_wait -= std::chrono::duration_cast<std::chrono::nanoseconds>(start_time - begin_sleep); total_wait -= std::chrono::duration_cast<std::chrono::nanoseconds>(start_time - begin_sleep);

View File

@ -25,6 +25,9 @@ void SetCurrentThreadName(const char* name);
void SetThreadName(void* thread, const char* name); void SetThreadName(void* thread, const char* name);
bool AccurateSleep(std::chrono::nanoseconds duration, std::chrono::nanoseconds* remaining,
bool interruptible);
class AccurateTimer { class AccurateTimer {
std::chrono::nanoseconds target_interval{}; std::chrono::nanoseconds target_interval{};
std::chrono::nanoseconds total_wait{}; std::chrono::nanoseconds total_wait{};

View File

@ -8,7 +8,7 @@
#define VA_ARGS \ #define VA_ARGS \
uint64_t rdi, uint64_t rsi, uint64_t rdx, uint64_t rcx, uint64_t r8, uint64_t r9, \ uint64_t rdi, uint64_t rsi, uint64_t rdx, uint64_t rcx, uint64_t r8, uint64_t r9, \
uint64_t overflow_arg_area, __m128 xmm0, __m128 xmm1, __m128 xmm2, __m128 xmm3, \ uint64_t overflow_arg_area, __m128 xmm0, __m128 xmm1, __m128 xmm2, __m128 xmm3, \
__m128 xmm4, __m128 xmm5, __m128 xmm6, __m128 xmm7, ... __m128 xmm4, __m128 xmm5, __m128 xmm6, __m128 xmm7
#define VA_CTX(ctx) \ #define VA_CTX(ctx) \
alignas(16)::Common::VaCtx ctx{}; \ alignas(16)::Common::VaCtx ctx{}; \

View File

@ -302,14 +302,15 @@ struct AddressSpace::Impl {
new_flags = PAGE_READWRITE; new_flags = PAGE_READWRITE;
} else if (read && !write) { } else if (read && !write) {
new_flags = PAGE_READONLY; new_flags = PAGE_READONLY;
} else if (execute && !read && not write) { } else if (execute && !read && !write) {
new_flags = PAGE_EXECUTE; new_flags = PAGE_EXECUTE;
} else if (!read && !write && !execute) { } else if (!read && !write && !execute) {
new_flags = PAGE_NOACCESS; new_flags = PAGE_NOACCESS;
} else { } else {
LOG_CRITICAL(Common_Memory, LOG_CRITICAL(Common_Memory,
"Unsupported protection flag combination for address {:#x}, size {}", "Unsupported protection flag combination for address {:#x}, size {}, "
virtual_addr, size); "read={}, write={}, execute={}",
virtual_addr, size, read, write, execute);
return; return;
} }
@ -357,9 +358,17 @@ enum PosixPageProtection {
[[nodiscard]] constexpr PosixPageProtection ToPosixProt(Core::MemoryProt prot) { [[nodiscard]] constexpr PosixPageProtection ToPosixProt(Core::MemoryProt prot) {
if (True(prot & Core::MemoryProt::CpuReadWrite) || if (True(prot & Core::MemoryProt::CpuReadWrite) ||
True(prot & Core::MemoryProt::GpuReadWrite)) { True(prot & Core::MemoryProt::GpuReadWrite)) {
return PAGE_READWRITE; if (True(prot & Core::MemoryProt::CpuExec)) {
return PAGE_EXECUTE_READWRITE;
} else {
return PAGE_READWRITE;
}
} else if (True(prot & Core::MemoryProt::CpuRead) || True(prot & Core::MemoryProt::GpuRead)) { } else if (True(prot & Core::MemoryProt::CpuRead) || True(prot & Core::MemoryProt::GpuRead)) {
return PAGE_READONLY; if (True(prot & Core::MemoryProt::CpuExec)) {
return PAGE_EXECUTE_READ;
} else {
return PAGE_READONLY;
}
} else { } else {
return PAGE_NOACCESS; return PAGE_NOACCESS;
} }

View File

@ -11,6 +11,7 @@
namespace Core { namespace Core {
enum class MemoryPermission : u32 { enum class MemoryPermission : u32 {
None = 0,
Read = 1 << 0, Read = 1 << 0,
Write = 1 << 1, Write = 1 << 1,
ReadWrite = Read | Write, ReadWrite = Read | Write,
@ -19,8 +20,6 @@ enum class MemoryPermission : u32 {
}; };
DECLARE_ENUM_FLAG_OPERATORS(MemoryPermission) DECLARE_ENUM_FLAG_OPERATORS(MemoryPermission)
constexpr VAddr CODE_BASE_OFFSET = 0x100000000ULL;
constexpr VAddr SYSTEM_MANAGED_MIN = 0x00000400000ULL; constexpr VAddr SYSTEM_MANAGED_MIN = 0x00000400000ULL;
constexpr VAddr SYSTEM_MANAGED_MAX = 0x07FFFFBFFFULL; constexpr VAddr SYSTEM_MANAGED_MAX = 0x07FFFFBFFFULL;
constexpr VAddr SYSTEM_RESERVED_MIN = 0x07FFFFC000ULL; constexpr VAddr SYSTEM_RESERVED_MIN = 0x07FFFFC000ULL;

View File

@ -88,7 +88,8 @@ static bool FilterTcbAccess(const ZydisDecodedOperand* operands) {
dst_op.reg.value <= ZYDIS_REGISTER_R15; dst_op.reg.value <= ZYDIS_REGISTER_R15;
} }
static void GenerateTcbAccess(const ZydisDecodedOperand* operands, Xbyak::CodeGenerator& c) { static void GenerateTcbAccess(void* /* address */, const ZydisDecodedOperand* operands,
Xbyak::CodeGenerator& c) {
const auto dst = ZydisToXbyakRegisterOperand(operands[0]); const auto dst = ZydisToXbyakRegisterOperand(operands[0]);
#if defined(_WIN32) #if defined(_WIN32)
@ -126,7 +127,8 @@ static bool FilterNoSSE4a(const ZydisDecodedOperand*) {
return !cpu.has(Cpu::tSSE4a); return !cpu.has(Cpu::tSSE4a);
} }
static void GenerateEXTRQ(const ZydisDecodedOperand* operands, Xbyak::CodeGenerator& c) { static void GenerateEXTRQ(void* /* address */, const ZydisDecodedOperand* operands,
Xbyak::CodeGenerator& c) {
bool immediateForm = operands[1].type == ZYDIS_OPERAND_TYPE_IMMEDIATE && bool immediateForm = operands[1].type == ZYDIS_OPERAND_TYPE_IMMEDIATE &&
operands[2].type == ZYDIS_OPERAND_TYPE_IMMEDIATE; operands[2].type == ZYDIS_OPERAND_TYPE_IMMEDIATE;
@ -161,7 +163,9 @@ static void GenerateEXTRQ(const ZydisDecodedOperand* operands, Xbyak::CodeGenera
mask = (1ULL << length) - 1; mask = (1ULL << length) - 1;
} }
ASSERT_MSG(length + index <= 64, "length + index must be less than or equal to 64."); if (length + index > 64) {
mask = 0xFFFF'FFFF'FFFF'FFFF;
}
// Get lower qword from xmm register // Get lower qword from xmm register
c.vmovq(scratch1, xmm_dst); c.vmovq(scratch1, xmm_dst);
@ -175,8 +179,8 @@ static void GenerateEXTRQ(const ZydisDecodedOperand* operands, Xbyak::CodeGenera
c.mov(scratch2, mask); c.mov(scratch2, mask);
c.and_(scratch1, scratch2); c.and_(scratch1, scratch2);
// Writeback to xmm register, extrq instruction says top 64-bits are undefined so we don't // Writeback to xmm register, extrq instruction says top 64-bits are undefined but zeroed on
// care to preserve them // AMD CPUs
c.vmovq(xmm_dst, scratch1); c.vmovq(xmm_dst, scratch1);
c.pop(scratch2); c.pop(scratch2);
@ -245,7 +249,8 @@ static void GenerateEXTRQ(const ZydisDecodedOperand* operands, Xbyak::CodeGenera
} }
} }
static void GenerateINSERTQ(const ZydisDecodedOperand* operands, Xbyak::CodeGenerator& c) { static void GenerateINSERTQ(void* /* address */, const ZydisDecodedOperand* operands,
Xbyak::CodeGenerator& c) {
bool immediateForm = operands[2].type == ZYDIS_OPERAND_TYPE_IMMEDIATE && bool immediateForm = operands[2].type == ZYDIS_OPERAND_TYPE_IMMEDIATE &&
operands[3].type == ZYDIS_OPERAND_TYPE_IMMEDIATE; operands[3].type == ZYDIS_OPERAND_TYPE_IMMEDIATE;
@ -284,7 +289,9 @@ static void GenerateINSERTQ(const ZydisDecodedOperand* operands, Xbyak::CodeGene
mask_value = (1ULL << length) - 1; mask_value = (1ULL << length) - 1;
} }
ASSERT_MSG(length + index <= 64, "length + index must be less than or equal to 64."); if (length + index > 64) {
mask_value = 0xFFFF'FFFF'FFFF'FFFF;
}
c.vmovq(scratch1, xmm_src); c.vmovq(scratch1, xmm_src);
c.vmovq(scratch2, xmm_dst); c.vmovq(scratch2, xmm_dst);
@ -304,8 +311,9 @@ static void GenerateINSERTQ(const ZydisDecodedOperand* operands, Xbyak::CodeGene
// dst |= src // dst |= src
c.or_(scratch2, scratch1); c.or_(scratch2, scratch1);
// Insert scratch2 into low 64 bits of dst, upper 64 bits are unaffected // Insert scratch2 into low 64 bits of dst, upper 64 bits are undefined but zeroed on AMD
c.vpinsrq(xmm_dst, xmm_dst, scratch2, 0); // CPUs
c.vmovq(xmm_dst, scratch2);
c.pop(mask); c.pop(mask);
c.pop(scratch2); c.pop(scratch2);
@ -371,7 +379,7 @@ static void GenerateINSERTQ(const ZydisDecodedOperand* operands, Xbyak::CodeGene
c.and_(scratch2, mask); c.and_(scratch2, mask);
c.or_(scratch2, scratch1); c.or_(scratch2, scratch1);
// Upper 64 bits are undefined in insertq // Upper 64 bits are undefined in insertq but AMD CPUs zero them
c.vmovq(xmm_dst, scratch2); c.vmovq(xmm_dst, scratch2);
c.pop(mask); c.pop(mask);
@ -383,8 +391,44 @@ static void GenerateINSERTQ(const ZydisDecodedOperand* operands, Xbyak::CodeGene
} }
} }
static void ReplaceMOVNT(void* address, u8 rep_prefix) {
// Find the opcode byte
// There can be any amount of prefixes but the instruction can't be more than 15 bytes
// And we know for sure this is a MOVNTSS/MOVNTSD
bool found = false;
bool rep_prefix_found = false;
int index = 0;
u8* ptr = reinterpret_cast<u8*>(address);
for (int i = 0; i < 15; i++) {
if (ptr[i] == rep_prefix) {
rep_prefix_found = true;
} else if (ptr[i] == 0x2B) {
index = i;
found = true;
break;
}
}
// Some sanity checks
ASSERT(found);
ASSERT(index >= 2);
ASSERT(ptr[index - 1] == 0x0F);
ASSERT(rep_prefix_found);
// This turns the MOVNTSS/MOVNTSD to a MOVSS/MOVSD m, xmm
ptr[index] = 0x11;
}
static void ReplaceMOVNTSS(void* address, const ZydisDecodedOperand*, Xbyak::CodeGenerator&) {
ReplaceMOVNT(address, 0xF3);
}
static void ReplaceMOVNTSD(void* address, const ZydisDecodedOperand*, Xbyak::CodeGenerator&) {
ReplaceMOVNT(address, 0xF2);
}
using PatchFilter = bool (*)(const ZydisDecodedOperand*); using PatchFilter = bool (*)(const ZydisDecodedOperand*);
using InstructionGenerator = void (*)(const ZydisDecodedOperand*, Xbyak::CodeGenerator&); using InstructionGenerator = void (*)(void*, const ZydisDecodedOperand*, Xbyak::CodeGenerator&);
struct PatchInfo { struct PatchInfo {
/// Filter for more granular patch conditions past just the instruction mnemonic. /// Filter for more granular patch conditions past just the instruction mnemonic.
PatchFilter filter; PatchFilter filter;
@ -400,6 +444,8 @@ static const std::unordered_map<ZydisMnemonic, PatchInfo> Patches = {
// SSE4a // SSE4a
{ZYDIS_MNEMONIC_EXTRQ, {FilterNoSSE4a, GenerateEXTRQ, true}}, {ZYDIS_MNEMONIC_EXTRQ, {FilterNoSSE4a, GenerateEXTRQ, true}},
{ZYDIS_MNEMONIC_INSERTQ, {FilterNoSSE4a, GenerateINSERTQ, true}}, {ZYDIS_MNEMONIC_INSERTQ, {FilterNoSSE4a, GenerateINSERTQ, true}},
{ZYDIS_MNEMONIC_MOVNTSS, {FilterNoSSE4a, ReplaceMOVNTSS, false}},
{ZYDIS_MNEMONIC_MOVNTSD, {FilterNoSSE4a, ReplaceMOVNTSD, false}},
#if defined(_WIN32) #if defined(_WIN32)
// Windows needs a trampoline. // Windows needs a trampoline.
@ -464,9 +510,8 @@ static std::pair<bool, u64> TryPatch(u8* code, PatchModule* module) {
if (needs_trampoline && instruction.length < 5) { if (needs_trampoline && instruction.length < 5) {
// Trampoline is needed but instruction is too short to patch. // Trampoline is needed but instruction is too short to patch.
// Return false and length to fall back to the illegal instruction handler, // Return false and length to signal to AOT compilation that this instruction
// or to signal to AOT compilation that this instruction should be skipped and // should be skipped and handled at runtime.
// handled at runtime.
return std::make_pair(false, instruction.length); return std::make_pair(false, instruction.length);
} }
@ -478,7 +523,7 @@ static std::pair<bool, u64> TryPatch(u8* code, PatchModule* module) {
auto& trampoline_gen = module->trampoline_gen; auto& trampoline_gen = module->trampoline_gen;
const auto trampoline_ptr = trampoline_gen.getCurr(); const auto trampoline_ptr = trampoline_gen.getCurr();
patch_info.generator(operands, trampoline_gen); patch_info.generator(code, operands, trampoline_gen);
// Return to the following instruction at the end of the trampoline. // Return to the following instruction at the end of the trampoline.
trampoline_gen.jmp(code + instruction.length); trampoline_gen.jmp(code + instruction.length);
@ -486,7 +531,7 @@ static std::pair<bool, u64> TryPatch(u8* code, PatchModule* module) {
// Replace instruction with near jump to the trampoline. // Replace instruction with near jump to the trampoline.
patch_gen.jmp(trampoline_ptr, Xbyak::CodeGenerator::LabelType::T_NEAR); patch_gen.jmp(trampoline_ptr, Xbyak::CodeGenerator::LabelType::T_NEAR);
} else { } else {
patch_info.generator(operands, patch_gen); patch_info.generator(code, operands, patch_gen);
} }
const auto patch_size = patch_gen.getCurr() - code; const auto patch_size = patch_gen.getCurr() - code;
@ -512,136 +557,139 @@ static std::pair<bool, u64> TryPatch(u8* code, PatchModule* module) {
#if defined(ARCH_X86_64) #if defined(ARCH_X86_64)
static bool Is4ByteExtrqOrInsertq(void* code_address) {
u8* bytes = (u8*)code_address;
if (bytes[0] == 0x66 && bytes[1] == 0x0F && bytes[2] == 0x79) {
return true; // extrq
} else if (bytes[0] == 0xF2 && bytes[1] == 0x0F && bytes[2] == 0x79) {
return true; // insertq
} else {
return false;
}
}
static bool TryExecuteIllegalInstruction(void* ctx, void* code_address) { static bool TryExecuteIllegalInstruction(void* ctx, void* code_address) {
ZydisDecodedInstruction instruction; // We need to decode the instruction to find out what it is. Normally we'd use a fully fleshed
ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT]; // out decoder like Zydis, however Zydis does a bunch of stuff that impact performance that we
const auto status = // don't care about. We can get information about the instruction a lot faster by writing a mini
Common::Decoder::Instance()->decodeInstruction(instruction, operands, code_address); // decoder here, since we know it is definitely an extrq or an insertq. If for some reason we
// need to interpret more instructions in the future (I don't see why we would), we can revert
// to using Zydis.
ZydisMnemonic mnemonic;
u8* bytes = (u8*)code_address;
if (bytes[0] == 0x66) {
mnemonic = ZYDIS_MNEMONIC_EXTRQ;
} else if (bytes[0] == 0xF2) {
mnemonic = ZYDIS_MNEMONIC_INSERTQ;
} else {
ZydisDecodedInstruction instruction;
ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT];
const auto status =
Common::Decoder::Instance()->decodeInstruction(instruction, operands, code_address);
LOG_ERROR(Core, "Unhandled illegal instruction at code address {}: {}",
fmt::ptr(code_address),
ZYAN_SUCCESS(status) ? ZydisMnemonicGetString(instruction.mnemonic)
: "Failed to decode");
return false;
}
switch (instruction.mnemonic) { ASSERT(bytes[1] == 0x0F && bytes[2] == 0x79);
// Note: It's guaranteed that there's no REX prefix in these instructions checked by
// Is4ByteExtrqOrInsertq
u8 modrm = bytes[3];
u8 rm = modrm & 0b111;
u8 reg = (modrm >> 3) & 0b111;
u8 mod = (modrm >> 6) & 0b11;
ASSERT(mod == 0b11); // Any instruction we interpret here uses reg/reg addressing only
int dstIndex = reg;
int srcIndex = rm;
switch (mnemonic) {
case ZYDIS_MNEMONIC_EXTRQ: { case ZYDIS_MNEMONIC_EXTRQ: {
bool immediateForm = operands[1].type == ZYDIS_OPERAND_TYPE_IMMEDIATE && const auto dst = Common::GetXmmPointer(ctx, dstIndex);
operands[2].type == ZYDIS_OPERAND_TYPE_IMMEDIATE; const auto src = Common::GetXmmPointer(ctx, srcIndex);
if (immediateForm) {
LOG_CRITICAL(Core, "EXTRQ immediate form should have been patched at code address: {}", u64 lowQWordSrc;
fmt::ptr(code_address)); memcpy(&lowQWordSrc, src, sizeof(lowQWordSrc));
return false;
u64 lowQWordDst;
memcpy(&lowQWordDst, dst, sizeof(lowQWordDst));
u64 length = lowQWordSrc & 0x3F;
u64 mask;
if (length == 0) {
length = 64; // for the check below
mask = 0xFFFF'FFFF'FFFF'FFFF;
} else { } else {
ASSERT_MSG(operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER && mask = (1ULL << length) - 1;
operands[1].type == ZYDIS_OPERAND_TYPE_REGISTER &&
operands[0].reg.value >= ZYDIS_REGISTER_XMM0 &&
operands[0].reg.value <= ZYDIS_REGISTER_XMM15 &&
operands[1].reg.value >= ZYDIS_REGISTER_XMM0 &&
operands[1].reg.value <= ZYDIS_REGISTER_XMM15,
"Unexpected operand types for EXTRQ instruction");
const auto dstIndex = operands[0].reg.value - ZYDIS_REGISTER_XMM0;
const auto srcIndex = operands[1].reg.value - ZYDIS_REGISTER_XMM0;
const auto dst = Common::GetXmmPointer(ctx, dstIndex);
const auto src = Common::GetXmmPointer(ctx, srcIndex);
u64 lowQWordSrc;
memcpy(&lowQWordSrc, src, sizeof(lowQWordSrc));
u64 lowQWordDst;
memcpy(&lowQWordDst, dst, sizeof(lowQWordDst));
u64 length = lowQWordSrc & 0x3F;
u64 mask;
if (length == 0) {
length = 64; // for the check below
mask = 0xFFFF'FFFF'FFFF'FFFF;
} else {
mask = (1ULL << length) - 1;
}
u64 index = (lowQWordSrc >> 8) & 0x3F;
if (length + index > 64) {
// Undefined behavior if length + index is bigger than 64 according to the spec,
// we'll warn and continue execution.
LOG_TRACE(Core,
"extrq at {} with length {} and index {} is bigger than 64, "
"undefined behavior",
fmt::ptr(code_address), length, index);
}
lowQWordDst >>= index;
lowQWordDst &= mask;
memcpy(dst, &lowQWordDst, sizeof(lowQWordDst));
Common::IncrementRip(ctx, instruction.length);
return true;
} }
break;
u64 index = (lowQWordSrc >> 8) & 0x3F;
if (length + index > 64) {
// Undefined behavior if length + index is bigger than 64 according to the spec,
// we'll warn and continue execution.
LOG_TRACE(Core,
"extrq at {} with length {} and index {} is bigger than 64, "
"undefined behavior",
fmt::ptr(code_address), length, index);
}
lowQWordDst >>= index;
lowQWordDst &= mask;
memset((u8*)dst + sizeof(u64), 0, sizeof(u64));
memcpy(dst, &lowQWordDst, sizeof(lowQWordDst));
Common::IncrementRip(ctx, 4);
return true;
} }
case ZYDIS_MNEMONIC_INSERTQ: { case ZYDIS_MNEMONIC_INSERTQ: {
bool immediateForm = operands[2].type == ZYDIS_OPERAND_TYPE_IMMEDIATE && const auto dst = Common::GetXmmPointer(ctx, dstIndex);
operands[3].type == ZYDIS_OPERAND_TYPE_IMMEDIATE; const auto src = Common::GetXmmPointer(ctx, srcIndex);
if (immediateForm) {
LOG_CRITICAL(Core, u64 lowQWordSrc, highQWordSrc;
"INSERTQ immediate form should have been patched at code address: {}", memcpy(&lowQWordSrc, src, sizeof(lowQWordSrc));
fmt::ptr(code_address)); memcpy(&highQWordSrc, (u8*)src + 8, sizeof(highQWordSrc));
return false;
u64 lowQWordDst;
memcpy(&lowQWordDst, dst, sizeof(lowQWordDst));
u64 length = highQWordSrc & 0x3F;
u64 mask;
if (length == 0) {
length = 64; // for the check below
mask = 0xFFFF'FFFF'FFFF'FFFF;
} else { } else {
ASSERT_MSG(operands[2].type == ZYDIS_OPERAND_TYPE_UNUSED && mask = (1ULL << length) - 1;
operands[3].type == ZYDIS_OPERAND_TYPE_UNUSED,
"operands 2 and 3 must be unused for register form.");
ASSERT_MSG(operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER &&
operands[1].type == ZYDIS_OPERAND_TYPE_REGISTER,
"operands 0 and 1 must be registers.");
const auto dstIndex = operands[0].reg.value - ZYDIS_REGISTER_XMM0;
const auto srcIndex = operands[1].reg.value - ZYDIS_REGISTER_XMM0;
const auto dst = Common::GetXmmPointer(ctx, dstIndex);
const auto src = Common::GetXmmPointer(ctx, srcIndex);
u64 lowQWordSrc, highQWordSrc;
memcpy(&lowQWordSrc, src, sizeof(lowQWordSrc));
memcpy(&highQWordSrc, (u8*)src + 8, sizeof(highQWordSrc));
u64 lowQWordDst;
memcpy(&lowQWordDst, dst, sizeof(lowQWordDst));
u64 length = highQWordSrc & 0x3F;
u64 mask;
if (length == 0) {
length = 64; // for the check below
mask = 0xFFFF'FFFF'FFFF'FFFF;
} else {
mask = (1ULL << length) - 1;
}
u64 index = (highQWordSrc >> 8) & 0x3F;
if (length + index > 64) {
// Undefined behavior if length + index is bigger than 64 according to the spec,
// we'll warn and continue execution.
LOG_TRACE(Core,
"insertq at {} with length {} and index {} is bigger than 64, "
"undefined behavior",
fmt::ptr(code_address), length, index);
}
lowQWordSrc &= mask;
lowQWordDst &= ~(mask << index);
lowQWordDst |= lowQWordSrc << index;
memcpy(dst, &lowQWordDst, sizeof(lowQWordDst));
Common::IncrementRip(ctx, instruction.length);
return true;
} }
break;
u64 index = (highQWordSrc >> 8) & 0x3F;
if (length + index > 64) {
// Undefined behavior if length + index is bigger than 64 according to the spec,
// we'll warn and continue execution.
LOG_TRACE(Core,
"insertq at {} with length {} and index {} is bigger than 64, "
"undefined behavior",
fmt::ptr(code_address), length, index);
}
lowQWordSrc &= mask;
lowQWordDst &= ~(mask << index);
lowQWordDst |= lowQWordSrc << index;
memset((u8*)dst + sizeof(u64), 0, sizeof(u64));
memcpy(dst, &lowQWordDst, sizeof(lowQWordDst));
Common::IncrementRip(ctx, 4);
return true;
} }
default: { default: {
LOG_ERROR(Core, "Unhandled illegal instruction at code address {}: {}", UNREACHABLE();
fmt::ptr(code_address), ZydisMnemonicGetString(instruction.mnemonic));
return false;
} }
} }
@ -695,9 +743,26 @@ static bool PatchesAccessViolationHandler(void* context, void* /* fault_address
static bool PatchesIllegalInstructionHandler(void* context) { static bool PatchesIllegalInstructionHandler(void* context) {
void* code_address = Common::GetRip(context); void* code_address = Common::GetRip(context);
if (!TryPatchJit(code_address)) { if (Is4ByteExtrqOrInsertq(code_address)) {
// The instruction is not big enough for a relative jump, don't try to patch it and pass it
// to our illegal instruction interpreter directly
return TryExecuteIllegalInstruction(context, code_address); return TryExecuteIllegalInstruction(context, code_address);
} else {
if (!TryPatchJit(code_address)) {
ZydisDecodedInstruction instruction;
ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT];
const auto status =
Common::Decoder::Instance()->decodeInstruction(instruction, operands, code_address);
if (ZYAN_SUCCESS(status) && instruction.mnemonic == ZydisMnemonic::ZYDIS_MNEMONIC_UD2)
[[unlikely]] {
UNREACHABLE_MSG("ud2 at code address {:#x}", (u64)code_address);
}
LOG_ERROR(Core, "Failed to patch address {:x} -- mnemonic: {}", (u64)code_address,
ZYAN_SUCCESS(status) ? ZydisMnemonicGetString(instruction.mnemonic)
: "Failed to decode");
}
} }
return true; return true;
} }

View File

@ -40,6 +40,10 @@ public:
return ORBIS_KERNEL_ERROR_EBADF; return ORBIS_KERNEL_ERROR_EBADF;
} }
virtual size_t pwritev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt, u64 offset) {
return ORBIS_KERNEL_ERROR_EBADF;
}
virtual s64 lseek(s64 offset, int whence) { virtual s64 lseek(s64 offset, int whence) {
return ORBIS_KERNEL_ERROR_EBADF; return ORBIS_KERNEL_ERROR_EBADF;
} }

View File

@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <cstdlib> #include <cstdlib>
#include <ctime>
#include "common/logging/log.h" #include "common/logging/log.h"
#include "random_device.h" #include "random_device.h"

View File

@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <cstdlib> #include <cstdlib>
#include <ctime>
#include "common/logging/log.h" #include "common/logging/log.h"
#include "srandom_device.h" #include "srandom_device.h"

View File

@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <cstdlib> #include <cstdlib>
#include <ctime>
#include "common/logging/log.h" #include "common/logging/log.h"
#include "urandom_device.h" #include "urandom_device.h"

View File

@ -1,11 +1,11 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "SDL3/SDL_log.h"
#include "layer.h" #include "layer.h"
#include <imgui.h> #include <imgui.h>
#include "SDL3/SDL_log.h"
#include "common/config.h" #include "common/config.h"
#include "common/singleton.h" #include "common/singleton.h"
#include "common/types.h" #include "common/types.h"
@ -17,6 +17,7 @@
#include "widget/frame_dump.h" #include "widget/frame_dump.h"
#include "widget/frame_graph.h" #include "widget/frame_graph.h"
#include "widget/memory_map.h" #include "widget/memory_map.h"
#include "widget/module_list.h"
#include "widget/shader_list.h" #include "widget/shader_list.h"
extern std::unique_ptr<Vulkan::Presenter> presenter; extern std::unique_ptr<Vulkan::Presenter> presenter;
@ -40,6 +41,7 @@ static bool just_opened_options = false;
static Widget::MemoryMapViewer memory_map; static Widget::MemoryMapViewer memory_map;
static Widget::ShaderList shader_list; static Widget::ShaderList shader_list;
static Widget::ModuleList module_list;
// clang-format off // clang-format off
static std::string help_text = static std::string help_text =
@ -108,6 +110,9 @@ void L::DrawMenuBar() {
if (MenuItem("Memory map")) { if (MenuItem("Memory map")) {
memory_map.open = true; memory_map.open = true;
} }
if (MenuItem("Module list")) {
module_list.open = true;
}
ImGui::EndMenu(); ImGui::EndMenu();
} }
@ -256,6 +261,9 @@ void L::DrawAdvanced() {
if (shader_list.open) { if (shader_list.open) {
shader_list.Draw(); shader_list.Draw();
} }
if (module_list.open) {
module_list.Draw();
}
} }
void L::DrawSimple() { void L::DrawSimple() {

View File

@ -1,9 +1,14 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "options.h"
#include <memory>
#include <imgui.h> #include <imgui.h>
#include "options.h" #include "video_core/renderer_vulkan/vk_presenter.h"
extern std::unique_ptr<Vulkan::Presenter> presenter;
namespace Core::Devtools { namespace Core::Devtools {
@ -12,6 +17,7 @@ TOptions Options;
void LoadOptionsConfig(const char* line) { void LoadOptionsConfig(const char* line) {
char str[512]; char str[512];
int i; int i;
float f;
if (sscanf(line, "disassembler_cli_isa=%511[^\n]", str) == 1) { if (sscanf(line, "disassembler_cli_isa=%511[^\n]", str) == 1) {
Options.disassembler_cli_isa = str; Options.disassembler_cli_isa = str;
return; return;
@ -24,12 +30,26 @@ void LoadOptionsConfig(const char* line) {
Options.frame_dump_render_on_collapse = i != 0; Options.frame_dump_render_on_collapse = i != 0;
return; return;
} }
if (sscanf(line, "fsr_enabled=%d", &i) == 1) {
presenter->GetFsrSettingsRef().enable = i != 0;
return;
}
if (sscanf(line, "fsr_rcas_enabled=%d", &i) == 1) {
presenter->GetFsrSettingsRef().use_rcas = i != 0;
return;
}
if (sscanf(line, "fsr_rcas_attenuation=%f", &f) == 1) {
presenter->GetFsrSettingsRef().rcas_attenuation = f;
}
} }
void SerializeOptionsConfig(ImGuiTextBuffer* buf) { void SerializeOptionsConfig(ImGuiTextBuffer* buf) {
buf->appendf("disassembler_cli_isa=%s\n", Options.disassembler_cli_isa.c_str()); buf->appendf("disassembler_cli_isa=%s\n", Options.disassembler_cli_isa.c_str());
buf->appendf("disassembler_cli_spv=%s\n", Options.disassembler_cli_spv.c_str()); buf->appendf("disassembler_cli_spv=%s\n", Options.disassembler_cli_spv.c_str());
buf->appendf("frame_dump_render_on_collapse=%d\n", Options.frame_dump_render_on_collapse); buf->appendf("frame_dump_render_on_collapse=%d\n", Options.frame_dump_render_on_collapse);
buf->appendf("fsr_enabled=%d\n", presenter->GetFsrSettingsRef().enable);
buf->appendf("fsr_rcas_enabled=%d\n", presenter->GetFsrSettingsRef().use_rcas);
buf->appendf("fsr_rcas_attenuation=%f\n", presenter->GetFsrSettingsRef().rcas_attenuation);
} }
} // namespace Core::Devtools } // namespace Core::Devtools

View File

@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <cstdio> #include <cstdio>
#include <ctime>
#include <fmt/chrono.h> #include <fmt/chrono.h>
#include <imgui.h> #include <imgui.h>
#include <magic_enum/magic_enum.hpp> #include <magic_enum/magic_enum.hpp>

View File

@ -0,0 +1,55 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "module_list.h"
#include <imgui.h>
#include "common.h"
#include "core/debug_state.h"
#include "imgui/imgui_std.h"
using namespace ImGui;
namespace Core::Devtools::Widget {
void ModuleList::Draw() {
SetNextWindowSize({550.0f, 600.0f}, ImGuiCond_FirstUseEver);
if (!Begin("Module List", &open)) {
End();
return;
}
if (BeginTable("ModuleTable", 3,
ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Sortable |
ImGuiTableFlags_RowBg)) {
TableSetupColumn("Modulname", ImGuiTableColumnFlags_WidthStretch);
TableHeadersRow();
std::scoped_lock lock(modules_mutex);
for (const auto& module : modules) {
TableNextRow();
TableSetColumnIndex(0);
TextUnformatted(module.name.c_str());
TableSetColumnIndex(1);
if (module.is_sys_module) {
TextColored({0.2f, 0.6f, 0.8f, 1.0f}, "System Module");
} else {
TextColored({0.8f, 0.4f, 0.2f, 1.0f}, "Game Module");
}
TableSetColumnIndex(2);
if (module.is_lle) {
TextColored({0.4f, 0.7f, 0.4f, 1.0f}, "LLE");
} else {
TextColored({0.7f, 0.4f, 0.5f, 1.0f}, "HLE");
}
}
EndTable();
}
End();
}
} // namespace Core::Devtools::Widget

View File

@ -0,0 +1,82 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <algorithm>
#include <filesystem>
#include <mutex>
#include <string>
#include <vector>
#include "common/elf_info.h"
#include "common/path_util.h"
namespace Core::Devtools::Widget {
class ModuleList {
public:
ModuleList() = default;
~ModuleList() = default;
void Draw();
bool open = false;
static bool IsSystemModule(const std::filesystem::path& path) {
const auto sys_modules_path = Common::FS::GetUserPath(Common::FS::PathType::SysModuleDir);
const auto abs_path = std::filesystem::absolute(path).lexically_normal();
const auto abs_sys_path = std::filesystem::absolute(sys_modules_path).lexically_normal();
const auto path_str = abs_path.string();
const auto sys_path_str = abs_sys_path.string();
return path_str.starts_with(sys_path_str);
}
static bool IsSystemModule(const std::string& name) {
const auto game_modules_path = Common::ElfInfo::Instance().GetGameFolder() / "sce_module";
const auto prx_path = game_modules_path / name;
if (!std::filesystem::exists(prx_path)) {
return true;
}
return false;
}
static void AddModule(const std::string& name, std::filesystem::path path) {
if (name == "eboot.bin") {
return;
}
std::scoped_lock lock(modules_mutex);
modules.push_back({name, IsSystemModule(path), true});
}
static void AddModule(std::string name) {
name = name + ".prx";
std::scoped_lock lock(modules_mutex);
bool is_sys_module = IsSystemModule(name);
bool is_lle = false;
auto it = std::find_if(modules.begin(), modules.end(),
[&name, is_sys_module, is_lle](const ModuleInfo& entry) {
return entry.name == name && !entry.is_lle;
});
if (it == modules.end()) {
modules.push_back({name, is_sys_module, is_lle});
}
}
private:
struct ModuleInfo {
std::string name;
bool is_sys_module;
bool is_lle;
};
static inline std::mutex modules_mutex;
static inline std::vector<ModuleInfo> modules;
};
} // namespace Core::Devtools::Widget

View File

@ -10,6 +10,8 @@
namespace Core::FileSys { namespace Core::FileSys {
bool MntPoints::ignore_game_patches = false;
std::string RemoveTrailingSlashes(const std::string& path) { std::string RemoveTrailingSlashes(const std::string& path) {
// Remove trailing slashes to make comparisons simpler. // Remove trailing slashes to make comparisons simpler.
std::string path_sanitized = path; std::string path_sanitized = path;
@ -77,7 +79,7 @@ std::filesystem::path MntPoints::GetHostPath(std::string_view path, bool* is_rea
patch_path /= rel_path; patch_path /= rel_path;
if ((corrected_path.starts_with("/app0") || corrected_path.starts_with("/hostapp")) && if ((corrected_path.starts_with("/app0") || corrected_path.starts_with("/hostapp")) &&
!force_base_path && std::filesystem::exists(patch_path)) { !force_base_path && !ignore_game_patches && std::filesystem::exists(patch_path)) {
return patch_path; return patch_path;
} }
@ -137,7 +139,7 @@ std::filesystem::path MntPoints::GetHostPath(std::string_view path, bool* is_rea
return std::optional<std::filesystem::path>(current_path); return std::optional<std::filesystem::path>(current_path);
}; };
if (!force_base_path) { if (!force_base_path && !ignore_game_patches) {
if (const auto path = search(patch_path)) { if (const auto path = search(patch_path)) {
return *path; return *path;
} }

View File

@ -21,6 +21,7 @@ class MntPoints {
static constexpr bool NeedsCaseInsensitiveSearch = true; static constexpr bool NeedsCaseInsensitiveSearch = true;
#endif #endif
public: public:
static bool ignore_game_patches;
struct MntPair { struct MntPair {
std::filesystem::path host_path; std::filesystem::path host_path;
std::string mount; // e.g /app0 std::string mount; // e.g /app0

View File

@ -219,7 +219,7 @@ int PS4_SYSV_ABI sceAjmStrError() {
return ORBIS_OK; return ORBIS_OK;
} }
void RegisterlibSceAjm(Core::Loader::SymbolsResolver* sym) { void RegisterLib(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("NVDXiUesSbA", "libSceAjm", 1, "libSceAjm", 1, 1, sceAjmBatchCancel); LIB_FUNCTION("NVDXiUesSbA", "libSceAjm", 1, "libSceAjm", 1, 1, sceAjmBatchCancel);
LIB_FUNCTION("WfAiBW8Wcek", "libSceAjm", 1, "libSceAjm", 1, 1, sceAjmBatchErrorDump); LIB_FUNCTION("WfAiBW8Wcek", "libSceAjm", 1, "libSceAjm", 1, 1, sceAjmBatchErrorDump);
LIB_FUNCTION("dmDybN--Fn8", "libSceAjm", 1, "libSceAjm", 1, 1, sceAjmBatchJobControlBufferRa); LIB_FUNCTION("dmDybN--Fn8", "libSceAjm", 1, "libSceAjm", 1, 1, sceAjmBatchJobControlBufferRa);

View File

@ -229,5 +229,5 @@ int PS4_SYSV_ABI sceAjmModuleRegister(u32 context, AjmCodecType codec_type, s64
int PS4_SYSV_ABI sceAjmModuleUnregister(); int PS4_SYSV_ABI sceAjmModuleUnregister();
int PS4_SYSV_ABI sceAjmStrError(); int PS4_SYSV_ABI sceAjmStrError();
void RegisterlibSceAjm(Core::Loader::SymbolsResolver* sym); void RegisterLib(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::Ajm } // namespace Libraries::Ajm

View File

@ -369,7 +369,7 @@ int PS4_SYSV_ABI sceAppContentGetDownloadedStoreCountry() {
return ORBIS_OK; return ORBIS_OK;
} }
void RegisterlibSceAppContent(Core::Loader::SymbolsResolver* sym) { void RegisterLib(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("AS45QoYHjc4", "libSceAppContent", 1, "libSceAppContentUtil", 1, 1, _Z5dummyv); LIB_FUNCTION("AS45QoYHjc4", "libSceAppContent", 1, "libSceAppContentUtil", 1, 1, _Z5dummyv);
LIB_FUNCTION("ZiATpP9gEkA", "libSceAppContent", 1, "libSceAppContentUtil", 1, 1, LIB_FUNCTION("ZiATpP9gEkA", "libSceAppContent", 1, "libSceAppContentUtil", 1, 1,
sceAppContentAddcontDelete); sceAppContentAddcontDelete);

View File

@ -119,5 +119,5 @@ int PS4_SYSV_ABI sceAppContentGetAddcontInfoByEntitlementId();
int PS4_SYSV_ABI sceAppContentGetAddcontInfoListByIroTag(); int PS4_SYSV_ABI sceAppContentGetAddcontInfoListByIroTag();
int PS4_SYSV_ABI sceAppContentGetDownloadedStoreCountry(); int PS4_SYSV_ABI sceAppContentGetDownloadedStoreCountry();
void RegisterlibSceAppContent(Core::Loader::SymbolsResolver* sym); void RegisterLib(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::AppContent } // namespace Libraries::AppContent

View File

@ -3,18 +3,21 @@
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/libraries/audio/audioin.h" #include "core/libraries/audio/audioin.h"
#include "core/libraries/audio/sdl_in.h"
#include "core/libraries/error_codes.h" #include "core/libraries/error_codes.h"
#include "core/libraries/libs.h" #include "core/libraries/libs.h"
namespace Libraries::AudioIn { namespace Libraries::AudioIn {
static std::unique_ptr<SDLAudioIn> audio = std::make_unique<SDLAudioIn>();
int PS4_SYSV_ABI sceAudioInChangeAppModuleState() { int PS4_SYSV_ABI sceAudioInChangeAppModuleState() {
LOG_ERROR(Lib_AudioIn, "(STUBBED) called"); LOG_ERROR(Lib_AudioIn, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceAudioInClose() { int PS4_SYSV_ABI sceAudioInClose(s32 handle) {
LOG_ERROR(Lib_AudioIn, "(STUBBED) called"); audio->AudioInClose(handle);
return ORBIS_OK; return ORBIS_OK;
} }
@ -93,9 +96,13 @@ int PS4_SYSV_ABI sceAudioInGetSilentState() {
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceAudioInHqOpen() { int PS4_SYSV_ABI sceAudioInHqOpen(Libraries::UserService::OrbisUserServiceUserId userId, u32 type,
LOG_ERROR(Lib_AudioIn, "(STUBBED) called"); u32 index, u32 len, u32 freq, u32 param) {
return ORBIS_OK; int result = audio->AudioInOpen(type, len, freq, param);
if (result < 0) {
LOG_ERROR(Lib_AudioIn, "Error returned {:#x}", result);
}
return result;
} }
int PS4_SYSV_ABI sceAudioInHqOpenEx() { int PS4_SYSV_ABI sceAudioInHqOpenEx() {
@ -108,9 +115,8 @@ int PS4_SYSV_ABI sceAudioInInit() {
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceAudioInInput() { int PS4_SYSV_ABI sceAudioInInput(s32 handle, void* dest) {
LOG_ERROR(Lib_AudioIn, "(STUBBED) called"); return audio->AudioInInput(handle, dest);
return ORBIS_OK;
} }
int PS4_SYSV_ABI sceAudioInInputs() { int PS4_SYSV_ABI sceAudioInInputs() {
@ -123,9 +129,13 @@ int PS4_SYSV_ABI sceAudioInIsSharedDevice() {
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceAudioInOpen() { int PS4_SYSV_ABI sceAudioInOpen(Libraries::UserService::OrbisUserServiceUserId userId, u32 type,
LOG_ERROR(Lib_AudioIn, "(DUMMY) called"); u32 index, u32 len, u32 freq, u32 param) {
return 0x80260005; // ports are full return int result = audio->AudioInOpen(type, len, freq, param);
if (result < 0) {
LOG_ERROR(Lib_AudioIn, "Error returned {:#x}", result);
}
return result;
} }
int PS4_SYSV_ABI sceAudioInOpenEx() { int PS4_SYSV_ABI sceAudioInOpenEx() {
@ -218,7 +228,7 @@ int PS4_SYSV_ABI sceAudioInVmicWrite() {
return ORBIS_OK; return ORBIS_OK;
} }
void RegisterlibSceAudioIn(Core::Loader::SymbolsResolver* sym) { void RegisterLib(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("IQtWgnrw6v8", "libSceAudioIn", 1, "libSceAudioIn", 1, 1, LIB_FUNCTION("IQtWgnrw6v8", "libSceAudioIn", 1, "libSceAudioIn", 1, 1,
sceAudioInChangeAppModuleState); sceAudioInChangeAppModuleState);
LIB_FUNCTION("Jh6WbHhnI68", "libSceAudioIn", 1, "libSceAudioIn", 1, 1, sceAudioInClose); LIB_FUNCTION("Jh6WbHhnI68", "libSceAudioIn", 1, "libSceAudioIn", 1, 1, sceAudioInClose);

View File

@ -3,6 +3,7 @@
#pragma once #pragma once
#include <core/libraries/system/userservice.h>
#include "common/types.h" #include "common/types.h"
namespace Core::Loader { namespace Core::Loader {
@ -11,8 +12,12 @@ class SymbolsResolver;
namespace Libraries::AudioIn { namespace Libraries::AudioIn {
enum class OrbisAudioInParamFormat : u32 { S16Mono = 0, S16Stereo = 2 };
enum class OrbisAudioInType : u32 { VoiceChat = 0, General = 1, VoiceRecognition = 5 };
int PS4_SYSV_ABI sceAudioInChangeAppModuleState(); int PS4_SYSV_ABI sceAudioInChangeAppModuleState();
int PS4_SYSV_ABI sceAudioInClose(); int PS4_SYSV_ABI sceAudioInClose(s32 handle);
int PS4_SYSV_ABI sceAudioInCountPorts(); int PS4_SYSV_ABI sceAudioInCountPorts();
int PS4_SYSV_ABI sceAudioInDeviceHqOpen(); int PS4_SYSV_ABI sceAudioInDeviceHqOpen();
int PS4_SYSV_ABI sceAudioInDeviceIdHqOpen(); int PS4_SYSV_ABI sceAudioInDeviceIdHqOpen();
@ -28,13 +33,15 @@ int PS4_SYSV_ABI sceAudioInGetGain();
int PS4_SYSV_ABI sceAudioInGetHandleStatusInfo(); int PS4_SYSV_ABI sceAudioInGetHandleStatusInfo();
int PS4_SYSV_ABI sceAudioInGetRerouteCount(); int PS4_SYSV_ABI sceAudioInGetRerouteCount();
int PS4_SYSV_ABI sceAudioInGetSilentState(); int PS4_SYSV_ABI sceAudioInGetSilentState();
int PS4_SYSV_ABI sceAudioInHqOpen(); int PS4_SYSV_ABI sceAudioInHqOpen(Libraries::UserService::OrbisUserServiceUserId userId, u32 type,
u32 index, u32 len, u32 freq, u32 param);
int PS4_SYSV_ABI sceAudioInHqOpenEx(); int PS4_SYSV_ABI sceAudioInHqOpenEx();
int PS4_SYSV_ABI sceAudioInInit(); int PS4_SYSV_ABI sceAudioInInit();
int PS4_SYSV_ABI sceAudioInInput(); int PS4_SYSV_ABI sceAudioInInput(s32 handle, void* dest);
int PS4_SYSV_ABI sceAudioInInputs(); int PS4_SYSV_ABI sceAudioInInputs();
int PS4_SYSV_ABI sceAudioInIsSharedDevice(); int PS4_SYSV_ABI sceAudioInIsSharedDevice();
int PS4_SYSV_ABI sceAudioInOpen(); int PS4_SYSV_ABI sceAudioInOpen(Libraries::UserService::OrbisUserServiceUserId userId, u32 type,
u32 index, u32 len, u32 freq, u32 param);
int PS4_SYSV_ABI sceAudioInOpenEx(); int PS4_SYSV_ABI sceAudioInOpenEx();
int PS4_SYSV_ABI sceAudioInSetAllMute(); int PS4_SYSV_ABI sceAudioInSetAllMute();
int PS4_SYSV_ABI sceAudioInSetCompressorPreGain(); int PS4_SYSV_ABI sceAudioInSetCompressorPreGain();
@ -54,5 +61,5 @@ int PS4_SYSV_ABI sceAudioInVmicCreate();
int PS4_SYSV_ABI sceAudioInVmicDestroy(); int PS4_SYSV_ABI sceAudioInVmicDestroy();
int PS4_SYSV_ABI sceAudioInVmicWrite(); int PS4_SYSV_ABI sceAudioInVmicWrite();
void RegisterlibSceAudioIn(Core::Loader::SymbolsResolver* sym); void RegisterLib(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::AudioIn } // namespace Libraries::AudioIn

View File

@ -14,6 +14,7 @@
#include "core/libraries/audio/audioout.h" #include "core/libraries/audio/audioout.h"
#include "core/libraries/audio/audioout_backend.h" #include "core/libraries/audio/audioout_backend.h"
#include "core/libraries/audio/audioout_error.h" #include "core/libraries/audio/audioout_error.h"
#include "core/libraries/kernel/time.h"
#include "core/libraries/libs.h" #include "core/libraries/libs.h"
namespace Libraries::AudioOut { namespace Libraries::AudioOut {
@ -168,8 +169,19 @@ int PS4_SYSV_ABI sceAudioOutGetInfoOpenNum() {
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceAudioOutGetLastOutputTime() { int PS4_SYSV_ABI sceAudioOutGetLastOutputTime(s32 handle, u64* output_time) {
LOG_ERROR(Lib_AudioOut, "(STUBBED) called"); LOG_DEBUG(Lib_AudioOut, "called, handle: {}, output time: {}", handle, fmt::ptr(output_time));
if (!output_time) {
return ORBIS_AUDIO_OUT_ERROR_INVALID_POINTER;
}
if (handle >= ports_out.size()) {
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
}
auto& port = ports_out.at(handle - 1);
if (!port.IsOpen()) {
return ORBIS_AUDIO_OUT_ERROR_NOT_OPENED;
}
*output_time = port.last_output_time;
return ORBIS_OK; return ORBIS_OK;
} }
@ -396,6 +408,7 @@ s32 PS4_SYSV_ABI sceAudioOutOutput(s32 handle, void* ptr) {
if (ptr != nullptr && port.IsOpen()) { if (ptr != nullptr && port.IsOpen()) {
std::memcpy(port.output_buffer, ptr, port.BufferSize()); std::memcpy(port.output_buffer, ptr, port.BufferSize());
port.output_ready = true; port.output_ready = true;
port.last_output_time = Kernel::sceKernelGetProcessTime();
} }
} }
port.output_cv.notify_one(); port.output_cv.notify_one();
@ -523,9 +536,24 @@ s32 PS4_SYSV_ABI sceAudioOutSetVolume(s32 handle, s32 flag, s32* vol) {
} }
port.impl->SetVolume(port.volume); port.impl->SetVolume(port.volume);
} }
AdjustVol();
return ORBIS_OK; return ORBIS_OK;
} }
void AdjustVol() {
if (audio == nullptr) {
return;
}
for (int i = 0; i < ports_out.size(); i++) {
std::unique_lock lock{ports_out[i].mutex};
if (!ports_out[i].IsOpen()) {
continue;
}
ports_out[i].impl->SetVolume(ports_out[i].volume);
}
}
int PS4_SYSV_ABI sceAudioOutSetVolumeDown() { int PS4_SYSV_ABI sceAudioOutSetVolumeDown() {
LOG_ERROR(Lib_AudioOut, "(STUBBED) called"); LOG_ERROR(Lib_AudioOut, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
@ -596,7 +624,7 @@ int PS4_SYSV_ABI sceAudioOutSetSystemDebugState() {
return ORBIS_OK; return ORBIS_OK;
} }
void RegisterlibSceAudioOut(Core::Loader::SymbolsResolver* sym) { void RegisterLib(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("cx2dYFbzIAg", "libSceAudioOutDeviceService", 1, "libSceAudioOut", 1, 1, LIB_FUNCTION("cx2dYFbzIAg", "libSceAudioOutDeviceService", 1, "libSceAudioOut", 1, 1,
sceAudioOutDeviceIdOpen); sceAudioOutDeviceIdOpen);
LIB_FUNCTION("tKumjQSzhys", "libSceAudioDeviceControl", 1, "libSceAudioOut", 1, 1, LIB_FUNCTION("tKumjQSzhys", "libSceAudioDeviceControl", 1, "libSceAudioOut", 1, 1,

View File

@ -96,6 +96,7 @@ struct PortOut {
AudioFormatInfo format_info; AudioFormatInfo format_info;
u32 sample_rate; u32 sample_rate;
u32 buffer_frames; u32 buffer_frames;
u64 last_output_time;
std::array<s32, 8> volume; std::array<s32, 8> volume;
[[nodiscard]] bool IsOpen() const { [[nodiscard]] bool IsOpen() const {
@ -127,7 +128,7 @@ int PS4_SYSV_ABI sceAudioOutGetFocusEnablePid();
int PS4_SYSV_ABI sceAudioOutGetHandleStatusInfo(); int PS4_SYSV_ABI sceAudioOutGetHandleStatusInfo();
int PS4_SYSV_ABI sceAudioOutGetInfo(); int PS4_SYSV_ABI sceAudioOutGetInfo();
int PS4_SYSV_ABI sceAudioOutGetInfoOpenNum(); int PS4_SYSV_ABI sceAudioOutGetInfoOpenNum();
int PS4_SYSV_ABI sceAudioOutGetLastOutputTime(); int PS4_SYSV_ABI sceAudioOutGetLastOutputTime(s32 handle, u64* output_time);
int PS4_SYSV_ABI sceAudioOutGetPortState(s32 handle, OrbisAudioOutPortState* state); int PS4_SYSV_ABI sceAudioOutGetPortState(s32 handle, OrbisAudioOutPortState* state);
int PS4_SYSV_ABI sceAudioOutGetSimulatedBusUsableStatusByBusType(); int PS4_SYSV_ABI sceAudioOutGetSimulatedBusUsableStatusByBusType();
int PS4_SYSV_ABI sceAudioOutGetSimulatedHandleStatusInfo(); int PS4_SYSV_ABI sceAudioOutGetSimulatedHandleStatusInfo();
@ -181,5 +182,6 @@ int PS4_SYSV_ABI sceAudioOutSystemControlSet();
int PS4_SYSV_ABI sceAudioOutSparkControlSetEqCoef(); int PS4_SYSV_ABI sceAudioOutSparkControlSetEqCoef();
int PS4_SYSV_ABI sceAudioOutSetSystemDebugState(); int PS4_SYSV_ABI sceAudioOutSetSystemDebugState();
void RegisterlibSceAudioOut(Core::Loader::SymbolsResolver* sym); void AdjustVol();
void RegisterLib(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::AudioOut } // namespace Libraries::AudioOut

View File

@ -4,6 +4,7 @@
#include <thread> #include <thread>
#include <SDL3/SDL_audio.h> #include <SDL3/SDL_audio.h>
#include <SDL3/SDL_hints.h> #include <SDL3/SDL_hints.h>
#include <common/config.h>
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/libraries/audio/audioout.h" #include "core/libraries/audio/audioout.h"
@ -41,6 +42,7 @@ public:
stream = nullptr; stream = nullptr;
return; return;
} }
SDL_SetAudioStreamGain(stream, Config::getVolumeSlider() / 100.0f);
} }
~SDLPortBackend() override { ~SDLPortBackend() override {
@ -77,7 +79,8 @@ public:
} }
// SDL does not have per-channel volumes, for now just take the maximum of the channels. // SDL does not have per-channel volumes, for now just take the maximum of the channels.
const auto vol = *std::ranges::max_element(ch_volumes); const auto vol = *std::ranges::max_element(ch_volumes);
if (!SDL_SetAudioStreamGain(stream, static_cast<float>(vol) / SCE_AUDIO_OUT_VOLUME_0DB)) { if (!SDL_SetAudioStreamGain(stream, static_cast<float>(vol) / SCE_AUDIO_OUT_VOLUME_0DB *
Config::getVolumeSlider() / 100.0f)) {
LOG_WARNING(Lib_AudioOut, "Failed to change SDL audio stream volume: {}", LOG_WARNING(Lib_AudioOut, "Failed to change SDL audio stream volume: {}",
SDL_GetError()); SDL_GetError());
} }

View File

@ -0,0 +1,135 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <cstring>
#include <common/config.h>
#include <common/logging/log.h>
#include "sdl_in.h"
int SDLAudioIn::AudioInit() {
return SDL_InitSubSystem(SDL_INIT_AUDIO);
}
int SDLAudioIn::AudioInOpen(int type, uint32_t samples_num, uint32_t freq, uint32_t format) {
std::scoped_lock lock{m_mutex};
for (int id = 0; id < static_cast<int>(portsIn.size()); ++id) {
auto& port = portsIn[id];
if (!port.isOpen) {
port.isOpen = true;
port.type = type;
port.samples_num = samples_num;
port.freq = freq;
port.format = format;
SDL_AudioFormat sampleFormat;
switch (format) {
case Libraries::AudioIn::ORBIS_AUDIO_IN_PARAM_FORMAT_S16_MONO:
sampleFormat = SDL_AUDIO_S16;
port.channels_num = 1;
port.sample_size = 2;
break;
case Libraries::AudioIn::ORBIS_AUDIO_IN_PARAM_FORMAT_S16_STEREO:
sampleFormat = SDL_AUDIO_S16;
port.channels_num = 2;
port.sample_size = 2;
break;
default:
port.isOpen = false;
return ORBIS_AUDIO_IN_ERROR_INVALID_PORT;
}
SDL_AudioSpec fmt;
SDL_zero(fmt);
fmt.format = sampleFormat;
fmt.channels = port.channels_num;
fmt.freq = port.freq;
std::string micDevStr = Config::getMicDevice();
uint32_t devId;
if (micDevStr == "None") {
return ORBIS_AUDIO_IN_ERROR_INVALID_PORT;
} else if (micDevStr == "Default Device") {
devId = SDL_AUDIO_DEVICE_DEFAULT_RECORDING;
} else {
try {
devId = static_cast<uint32_t>(std::stoul(micDevStr));
} catch (const std::exception& e) {
return ORBIS_AUDIO_IN_ERROR_INVALID_PORT;
}
}
port.stream = SDL_OpenAudioDeviceStream(devId, &fmt, nullptr, nullptr);
if (!port.stream) {
port.isOpen = false;
return ORBIS_AUDIO_IN_ERROR_INVALID_PORT;
}
if (SDL_ResumeAudioStreamDevice(port.stream) == false) {
SDL_DestroyAudioStream(port.stream);
port = {};
return ORBIS_AUDIO_IN_ERROR_STREAM_FAIL;
}
return id + 1;
}
}
return ORBIS_AUDIO_IN_ERROR_INVALID_PORT;
}
int SDLAudioIn::AudioInInput(int handle, void* out_buffer) {
std::scoped_lock lock{m_mutex};
if (handle < 1 || handle > static_cast<int>(portsIn.size()) || !out_buffer)
return ORBIS_AUDIO_IN_ERROR_INVALID_PORT;
auto& port = portsIn[handle - 1];
if (!port.isOpen)
return ORBIS_AUDIO_IN_ERROR_INVALID_PORT;
const int bytesToRead = port.samples_num * port.sample_size * port.channels_num;
if (out_buffer == nullptr) {
int attempts = 0;
while (SDL_GetAudioStreamAvailable(port.stream) > 0) {
SDL_Delay(1);
if (++attempts > 1000) {
return ORBIS_AUDIO_IN_ERROR_TIMEOUT;
}
}
return 0; // done
}
int attempts = 0;
while (SDL_GetAudioStreamAvailable(port.stream) < bytesToRead) {
SDL_Delay(1);
if (++attempts > 1000) {
return ORBIS_AUDIO_IN_ERROR_TIMEOUT;
}
}
const int bytesRead = SDL_GetAudioStreamData(port.stream, out_buffer, bytesToRead);
if (bytesRead < 0) {
// SDL_GetAudioStreamData failed
LOG_ERROR(Lib_AudioIn, "AudioInInput error: {}", SDL_GetError());
return ORBIS_AUDIO_IN_ERROR_STREAM_FAIL;
}
const int framesRead = bytesRead / (port.sample_size * port.channels_num);
return framesRead;
}
void SDLAudioIn::AudioInClose(int handle) {
std::scoped_lock lock{m_mutex};
if (handle < 1 || handle > (int)portsIn.size())
return;
auto& port = portsIn[handle - 1];
if (!port.isOpen)
return;
SDL_DestroyAudioStream(port.stream);
port = {};
}

View File

@ -0,0 +1,42 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <array>
#include <mutex>
#include <SDL3/SDL.h>
namespace Libraries::AudioIn {
enum OrbisAudioInParam {
ORBIS_AUDIO_IN_PARAM_FORMAT_S16_MONO = 0,
ORBIS_AUDIO_IN_PARAM_FORMAT_S16_STEREO = 2
};
}
#define ORBIS_AUDIO_IN_ERROR_INVALID_PORT -1
#define ORBIS_AUDIO_IN_ERROR_TIMEOUT -2
#define ORBIS_AUDIO_IN_ERROR_STREAM_FAIL -3
class SDLAudioIn {
public:
int AudioInit();
int AudioInOpen(int type, uint32_t samples_num, uint32_t freq, uint32_t format);
int AudioInInput(int handle, void* out_buffer);
void AudioInClose(int handle);
private:
struct AudioInPort {
bool isOpen = false;
int type = 0;
uint32_t samples_num = 0;
uint32_t freq = 0;
int channels_num = 0;
int sample_size = 0;
uint32_t format = 0;
SDL_AudioStream* stream = nullptr;
};
std::array<AudioInPort, 8> portsIn;
std::mutex m_mutex;
};

View File

@ -526,11 +526,18 @@ s32 PS4_SYSV_ABI sceAudio3dStrError() {
} }
s32 PS4_SYSV_ABI sceAudio3dTerminate() { s32 PS4_SYSV_ABI sceAudio3dTerminate() {
LOG_ERROR(Lib_Audio3d, "(STUBBED) called"); LOG_INFO(Lib_Audio3d, "called");
if (!state) {
return ORBIS_AUDIO3D_ERROR_NOT_READY;
}
AudioOut::sceAudioOutOutput(state->audio_out_handle, nullptr);
AudioOut::sceAudioOutClose(state->audio_out_handle);
state.release();
return ORBIS_OK; return ORBIS_OK;
} }
void RegisterlibSceAudio3d(Core::Loader::SymbolsResolver* sym) { void RegisterLib(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("pZlOm1aF3aA", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dAudioOutClose); LIB_FUNCTION("pZlOm1aF3aA", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dAudioOutClose);
LIB_FUNCTION("ucEsi62soTo", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dAudioOutOpen); LIB_FUNCTION("ucEsi62soTo", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dAudioOutOpen);
LIB_FUNCTION("7NYEzJ9SJbM", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, LIB_FUNCTION("7NYEzJ9SJbM", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,

View File

@ -141,5 +141,5 @@ s32 PS4_SYSV_ABI sceAudio3dSetGpuRenderer();
s32 PS4_SYSV_ABI sceAudio3dStrError(); s32 PS4_SYSV_ABI sceAudio3dStrError();
s32 PS4_SYSV_ABI sceAudio3dTerminate(); s32 PS4_SYSV_ABI sceAudio3dTerminate();
void RegisterlibSceAudio3d(Core::Loader::SymbolsResolver* sym); void RegisterLib(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::Audio3d } // namespace Libraries::Audio3d

View File

@ -278,7 +278,7 @@ s32 PS4_SYSV_ABI sceAvPlayerVprintf(const char* format, va_list args) {
return ORBIS_OK; return ORBIS_OK;
} }
void RegisterlibSceAvPlayer(Core::Loader::SymbolsResolver* sym) { void RegisterLib(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("KMcEa+rHsIo", "libSceAvPlayer", 1, "libSceAvPlayer", 1, 0, sceAvPlayerAddSource); LIB_FUNCTION("KMcEa+rHsIo", "libSceAvPlayer", 1, "libSceAvPlayer", 1, 0, sceAvPlayerAddSource);
LIB_FUNCTION("x8uvuFOPZhU", "libSceAvPlayer", 1, "libSceAvPlayer", 1, 0, LIB_FUNCTION("x8uvuFOPZhU", "libSceAvPlayer", 1, "libSceAvPlayer", 1, 0,
sceAvPlayerAddSourceEx); sceAvPlayerAddSourceEx);

View File

@ -290,6 +290,6 @@ enum class SceAvPlayerAvSyncMode {
using SceAvPlayerLogCallback = int PS4_SYSV_ABI (*)(void* p, const char* format, va_list args); using SceAvPlayerLogCallback = int PS4_SYSV_ABI (*)(void* p, const char* format, va_list args);
void RegisterlibSceAvPlayer(Core::Loader::SymbolsResolver* sym); void RegisterLib(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::AvPlayer } // namespace Libraries::AvPlayer

View File

@ -40,7 +40,7 @@ public:
FrameBuffer(const SceAvPlayerMemAllocator& memory_replacement, u32 align, u32 size) noexcept FrameBuffer(const SceAvPlayerMemAllocator& memory_replacement, u32 align, u32 size) noexcept
: m_memory_replacement(memory_replacement), : m_memory_replacement(memory_replacement),
m_data(Allocate(memory_replacement, align, size)) { m_data(Allocate(memory_replacement, align, size)) {
ASSERT_MSG(m_data, "Could not allocated frame buffer."); ASSERT_MSG(m_data, "Could not allocate frame buffer.");
} }
~FrameBuffer() { ~FrameBuffer() {

View File

@ -0,0 +1,517 @@
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
#include "core/libraries/camera/camera.h"
#include "core/libraries/camera/camera_error.h"
#include "core/libraries/error_codes.h"
#include "core/libraries/libs.h"
namespace Libraries::Camera {
s32 PS4_SYSV_ABI sceCameraAccGetData() {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraAudioClose() {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraAudioGetData() {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraAudioGetData2() {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraAudioOpen() {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraAudioReset() {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraChangeAppModuleState() {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraClose(s32 handle) {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraCloseByHandle() {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraDeviceOpen() {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraGetAttribute(s32 handle, OrbisCameraAttribute* pAttribute) {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraGetAutoExposureGain(s32 handle, OrbisCameraChannel channel, u32* pEnable,
void* pOption) {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraGetAutoWhiteBalance(s32 handle, OrbisCameraChannel channel, u32* pEnable,
void* pOption) {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraGetCalibData() {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraGetCalibDataFromDevice() {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraGetCalibrationData() {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraGetConfig(s32 handle, OrbisCameraConfig* pConfig) {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraGetContrast(s32 handle, OrbisCameraChannel channel, u32* pContrast,
void* pOption) {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraGetDefectivePixelCancellation(s32 handle, OrbisCameraChannel channel,
u32* pEnable, void* pOption) {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraGetDeviceConfig() {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraGetDeviceConfigWithoutHandle() {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraGetDeviceID() {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraGetDeviceIDWithoutOpen() {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraGetDeviceInfo(s32 reserved, OrbisCameraDeviceInfo* pDeviceInfo) {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraGetExposureGain(s32 handle, OrbisCameraChannel channel,
OrbisCameraExposureGain* pExposureGain, void* pOption) {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraGetFrameData(int handle, OrbisCameraFrameData* pFrameData) {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraGetGamma(s32 handle, OrbisCameraChannel channel, OrbisCameraGamma* pGamma,
void* pOption) {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraGetHue(s32 handle, OrbisCameraChannel channel, s32* pHue, void* pOption) {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraGetLensCorrection(s32 handle, OrbisCameraChannel channel, u32* pEnable,
void* pOption) {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraGetMmapConnectedCount() {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraGetProductInfo() {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraGetRegister() {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraGetRegistryInfo() {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraGetSaturation(s32 handle, OrbisCameraChannel channel, u32* pSaturation,
void* pOption) {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraGetSharpness(s32 handle, OrbisCameraChannel channel, u32* pSharpness,
void* pOption) {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraGetVrCaptureInfo() {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraGetWhiteBalance(s32 handle, OrbisCameraChannel channel,
OrbisCameraWhiteBalance* pWhiteBalance, void* pOption) {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraInitializeRegistryCalibData() {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraIsAttached(s32 index) {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraIsConfigChangeDone() {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraIsValidFrameData(int handle, OrbisCameraFrameData* pFrameData) {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraOpen(Libraries::UserService::OrbisUserServiceUserId userId, s32 type,
s32 index, OrbisCameraOpenParameter* pParam) {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraOpenByModuleId() {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraRemoveAppModuleFocus() {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraSetAppModuleFocus() {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraSetAttribute(s32 handle, OrbisCameraAttribute* pAttribute) {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraSetAttributeInternal() {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraSetAutoExposureGain(s32 handle, OrbisCameraChannel channel, u32 enable,
void* pOption) {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraSetAutoWhiteBalance(s32 handle, OrbisCameraChannel channel, u32 enable,
void* pOption) {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraSetCalibData() {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraSetConfig(s32 handle, OrbisCameraConfig* pConfig) {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraSetConfigInternal() {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraSetContrast(s32 handle, OrbisCameraChannel channel, u32 contrast,
void* pOption) {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraSetDebugStop() {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraSetDefectivePixelCancellation(s32 handle, OrbisCameraChannel channel,
u32 enable, void* pOption) {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraSetDefectivePixelCancellationInternal() {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraSetExposureGain(s32 handle, OrbisCameraChannel channel,
OrbisCameraExposureGain* pExposureGain, void* pOption) {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraSetForceActivate() {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraSetGamma(s32 handle, OrbisCameraChannel channel, OrbisCameraGamma* pGamma,
void* pOption) {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraSetHue(s32 handle, OrbisCameraChannel channel, s32 hue, void* pOption) {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraSetLensCorrection(s32 handle, OrbisCameraChannel channel, u32 enable,
void* pOption) {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraSetLensCorrectionInternal() {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraSetProcessFocus() {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraSetProcessFocusByHandle() {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraSetRegister() {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraSetSaturation(s32 handle, OrbisCameraChannel channel, u32 saturation,
void* pOption) {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraSetSharpness(s32 handle, OrbisCameraChannel channel, u32 sharpness,
void* pOption) {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraSetTrackerMode() {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraSetUacModeInternal() {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraSetVideoSync(s32 handle, OrbisCameraVideoSyncParameter* pVideoSync) {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraSetVideoSyncInternal() {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraSetWhiteBalance(s32 handle, OrbisCameraChannel channel,
OrbisCameraWhiteBalance* pWhiteBalance, void* pOption) {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraStart(s32 handle, OrbisCameraStartParameter* pParam) {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraStartByHandle() {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraStop(s32 handle) {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCameraStopByHandle() {
LOG_ERROR(Lib_Camera, "(STUBBED) called");
return ORBIS_OK;
}
void RegisterLib(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("QhjrPkRPUZQ", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraAccGetData);
LIB_FUNCTION("UFonL7xopFM", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraAudioClose);
LIB_FUNCTION("fkZE7Hup2ro", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraAudioGetData);
LIB_FUNCTION("hftC5A1C8OQ", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraAudioGetData2);
LIB_FUNCTION("DhqqFiBU+6g", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraAudioOpen);
LIB_FUNCTION("wyU98EXAYxU", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraAudioReset);
LIB_FUNCTION("Y0pCDajzkVQ", "libSceCamera", 1, "libSceCamera", 1, 1,
sceCameraChangeAppModuleState);
LIB_FUNCTION("OMS9LlcrvBo", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraClose);
LIB_FUNCTION("ztqH5qNTpTk", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraCloseByHandle);
LIB_FUNCTION("nBH6i2s4Glc", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraDeviceOpen);
LIB_FUNCTION("0btIPD5hg5A", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetAttribute);
LIB_FUNCTION("oEi6vM-3E2c", "libSceCamera", 1, "libSceCamera", 1, 1,
sceCameraGetAutoExposureGain);
LIB_FUNCTION("qTPRMh4eY60", "libSceCamera", 1, "libSceCamera", 1, 1,
sceCameraGetAutoWhiteBalance);
LIB_FUNCTION("hHA1frlMxYE", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetCalibData);
LIB_FUNCTION("5Oie5RArfWs", "libSceCamera", 1, "libSceCamera", 1, 1,
sceCameraGetCalibDataFromDevice);
LIB_FUNCTION("RHYJ7GKOSMg", "libSceCamera", 1, "libSceCamera", 1, 1,
sceCameraGetCalibrationData);
LIB_FUNCTION("ZaqmGEtYuL0", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetConfig);
LIB_FUNCTION("a5xFueMZIMs", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetContrast);
LIB_FUNCTION("tslCukqFE+E", "libSceCamera", 1, "libSceCamera", 1, 1,
sceCameraGetDefectivePixelCancellation);
LIB_FUNCTION("DSOLCrc3Kh8", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetDeviceConfig);
LIB_FUNCTION("n+rFeP1XXyM", "libSceCamera", 1, "libSceCamera", 1, 1,
sceCameraGetDeviceConfigWithoutHandle);
LIB_FUNCTION("jTJCdyv9GLU", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetDeviceID);
LIB_FUNCTION("-H3UwGQvNZI", "libSceCamera", 1, "libSceCamera", 1, 1,
sceCameraGetDeviceIDWithoutOpen);
LIB_FUNCTION("WZpxnSAM-ds", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetDeviceInfo);
LIB_FUNCTION("ObIste7hqdk", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetExposureGain);
LIB_FUNCTION("mxgMmR+1Kr0", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetFrameData);
LIB_FUNCTION("WVox2rwGuSc", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetGamma);
LIB_FUNCTION("zrIUDKZx0iE", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetHue);
LIB_FUNCTION("XqYRHc4aw3w", "libSceCamera", 1, "libSceCamera", 1, 1,
sceCameraGetLensCorrection);
LIB_FUNCTION("B260o9pSzM8", "libSceCamera", 1, "libSceCamera", 1, 1,
sceCameraGetMmapConnectedCount);
LIB_FUNCTION("ULxbwqiYYuU", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetProductInfo);
LIB_FUNCTION("olojYZKYiYs", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetRegister);
LIB_FUNCTION("hawKak+Auw4", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetRegistryInfo);
LIB_FUNCTION("RTDOsWWqdME", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetSaturation);
LIB_FUNCTION("c6Fp9M1EXXc", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetSharpness);
LIB_FUNCTION("IAz2HgZQWzE", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetVrCaptureInfo);
LIB_FUNCTION("HX5524E5tMY", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraGetWhiteBalance);
LIB_FUNCTION("0wnf2a60FqI", "libSceCamera", 1, "libSceCamera", 1, 1,
sceCameraInitializeRegistryCalibData);
LIB_FUNCTION("p6n3Npi3YY4", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraIsAttached);
LIB_FUNCTION("wQfd7kfRZvo", "libSceCamera", 1, "libSceCamera", 1, 1,
sceCameraIsConfigChangeDone);
LIB_FUNCTION("U3BVwQl2R5Q", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraIsValidFrameData);
LIB_FUNCTION("BHn83xrF92E", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraOpen);
LIB_FUNCTION("eTywOSWsEiI", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraOpenByModuleId);
LIB_FUNCTION("py8p6kZcHmA", "libSceCamera", 1, "libSceCamera", 1, 1,
sceCameraRemoveAppModuleFocus);
LIB_FUNCTION("j5isFVIlZLk", "libSceCamera", 1, "libSceCamera", 1, 1,
sceCameraSetAppModuleFocus);
LIB_FUNCTION("doPlf33ab-U", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraSetAttribute);
LIB_FUNCTION("96F7zp1Xo+k", "libSceCamera", 1, "libSceCamera", 1, 1,
sceCameraSetAttributeInternal);
LIB_FUNCTION("yfSdswDaElo", "libSceCamera", 1, "libSceCamera", 1, 1,
sceCameraSetAutoExposureGain);
LIB_FUNCTION("zIKL4kZleuc", "libSceCamera", 1, "libSceCamera", 1, 1,
sceCameraSetAutoWhiteBalance);
LIB_FUNCTION("LEMk5cTHKEA", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraSetCalibData);
LIB_FUNCTION("VQ+5kAqsE2Q", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraSetConfig);
LIB_FUNCTION("9+SNhbctk64", "libSceCamera", 1, "libSceCamera", 1, 1,
sceCameraSetConfigInternal);
LIB_FUNCTION("3i5MEzrC1pg", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraSetContrast);
LIB_FUNCTION("vejouEusC7g", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraSetDebugStop);
LIB_FUNCTION("jMv40y2A23g", "libSceCamera", 1, "libSceCamera", 1, 1,
sceCameraSetDefectivePixelCancellation);
LIB_FUNCTION("vER3cIMBHqI", "libSceCamera", 1, "libSceCamera", 1, 1,
sceCameraSetDefectivePixelCancellationInternal);
LIB_FUNCTION("wgBMXJJA6K4", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraSetExposureGain);
LIB_FUNCTION("jeTpU0MqKU0", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraSetForceActivate);
LIB_FUNCTION("lhEIsHzB8r4", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraSetGamma);
LIB_FUNCTION("QI8GVJUy2ZY", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraSetHue);
LIB_FUNCTION("K7W7H4ZRwbc", "libSceCamera", 1, "libSceCamera", 1, 1,
sceCameraSetLensCorrection);
LIB_FUNCTION("eHa3vhGu2rQ", "libSceCamera", 1, "libSceCamera", 1, 1,
sceCameraSetLensCorrectionInternal);
LIB_FUNCTION("lS0tM6n+Q5E", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraSetProcessFocus);
LIB_FUNCTION("NVITuK83Z7o", "libSceCamera", 1, "libSceCamera", 1, 1,
sceCameraSetProcessFocusByHandle);
LIB_FUNCTION("8MjO05qk5hA", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraSetRegister);
LIB_FUNCTION("bSKEi2PzzXI", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraSetSaturation);
LIB_FUNCTION("P-7MVfzvpsM", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraSetSharpness);
LIB_FUNCTION("3VJOpzKoIeM", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraSetTrackerMode);
LIB_FUNCTION("nnR7KAIDPv8", "libSceCamera", 1, "libSceCamera", 1, 1,
sceCameraSetUacModeInternal);
LIB_FUNCTION("wpeyFwJ+UEI", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraSetVideoSync);
LIB_FUNCTION("8WtmqmE4edw", "libSceCamera", 1, "libSceCamera", 1, 1,
sceCameraSetVideoSyncInternal);
LIB_FUNCTION("k3zPIcgFNv0", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraSetWhiteBalance);
LIB_FUNCTION("9EpRYMy7rHU", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraStart);
LIB_FUNCTION("cLxF1QtHch0", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraStartByHandle);
LIB_FUNCTION("2G2C0nmd++M", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraStop);
LIB_FUNCTION("+X1Kgnn3bzg", "libSceCamera", 1, "libSceCamera", 1, 1, sceCameraStopByHandle);
};
} // namespace Libraries::Camera

View File

@ -0,0 +1,308 @@
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <core/libraries/system/userservice.h>
#include "common/types.h"
namespace Core::Loader {
class SymbolsResolver;
}
namespace Libraries::Camera {
constexpr int ORBIS_CAMERA_MAX_DEVICE_NUM = 2;
constexpr int ORBIS_CAMERA_MAX_FORMAT_LEVEL_NUM = 4;
enum OrbisCameraChannel {
ORBIS_CAMERA_CHANNEL_0 = 1,
ORBIS_CAMERA_CHANNEL_1 = 2,
ORBIS_CAMERA_CHANNEL_BOTH = 3,
};
struct OrbisCameraOpenParameter {
u32 sizeThis;
u32 reserved1;
u32 reserved2;
u32 reserved3;
};
enum OrbisCameraConfigType {
ORBIS_CAMERA_CONFIG_TYPE1 = 0x01,
ORBIS_CAMERA_CONFIG_TYPE2 = 0x02,
ORBIS_CAMERA_CONFIG_TYPE3 = 0x03,
ORBIS_CAMERA_CONFIG_TYPE4 = 0x04,
ORBIS_CAMERA_CONFIG_TYPE5 = 0x05,
ORBIS_CAMERA_CONFIG_EXTENTION = 0x10,
};
enum OrbisCameraResolution {
ORBIS_CAMERA_RESOLUTION_1280X800 = 0x0,
ORBIS_CAMERA_RESOLUTION_640X400 = 0x1,
ORBIS_CAMERA_RESOLUTION_320X200 = 0x2,
ORBIS_CAMERA_RESOLUTION_160X100 = 0x3,
ORBIS_CAMERA_RESOLUTION_320X192 = 0x4,
ORBIS_CAMERA_RESOLUTION_SPECIFIED_WIDTH_HEIGHT,
ORBIS_CAMERA_RESOLUTION_UNKNOWN = 0xFF,
};
enum OrbisCameraFramerate {
ORBIS_CAMERA_FRAMERATE_UNKNOWN = 0,
ORBIS_CAMERA_FRAMERATE_7_5 = 7,
ORBIS_CAMERA_FRAMERATE_15 = 15,
ORBIS_CAMERA_FRAMERATE_30 = 30,
ORBIS_CAMERA_FRAMERATE_60 = 60,
ORBIS_CAMERA_FRAMERATE_120 = 120,
ORBIS_CAMERA_FRAMERATE_240 = 240,
};
enum OrbisCameraBaseFormat {
ORBIS_CAMERA_FORMAT_YUV422 = 0x0,
ORBIS_CAMERA_FORMAT_RAW16,
ORBIS_CAMERA_FORMAT_RAW8,
ORBIS_CAMERA_FORMAT_NO_USE = 0x10,
ORBIS_CAMERA_FORMAT_UNKNOWN = 0xFF,
};
enum OrbisCameraScaleFormat {
ORBIS_CAMERA_SCALE_FORMAT_YUV422 = 0x0,
ORBIS_CAMERA_SCALE_FORMAT_Y16 = 0x3,
ORBIS_CAMERA_SCALE_FORMAT_Y8,
ORBIS_CAMERA_SCALE_FORMAT_NO_USE = 0x10,
ORBIS_CAMERA_SCALE_FORMAT_UNKNOWN = 0xFF,
};
struct OrbisCameraFormat {
OrbisCameraBaseFormat formatLevel0;
OrbisCameraScaleFormat formatLevel1;
OrbisCameraScaleFormat formatLevel2;
OrbisCameraScaleFormat formatLevel3;
};
struct OrbisCameraConfigExtention {
OrbisCameraFormat format;
OrbisCameraResolution resolution;
OrbisCameraFramerate framerate;
u32 width;
u32 height;
u32 reserved1;
void* pBaseOption;
};
struct OrbisCameraConfig {
u32 sizeThis;
OrbisCameraConfigType configType;
OrbisCameraConfigExtention configExtention[ORBIS_CAMERA_MAX_DEVICE_NUM];
};
enum OrbisCameraAecAgcTarget {
ORBIS_CAMERA_ATTRIBUTE_AECAGC_TARGET_DEF = 0x00,
ORBIS_CAMERA_ATTRIBUTE_AECAGC_TARGET_2_0 = 0x20,
ORBIS_CAMERA_ATTRIBUTE_AECAGC_TARGET_1_6 = 0x16,
ORBIS_CAMERA_ATTRIBUTE_AECAGC_TARGET_1_4 = 0x14,
ORBIS_CAMERA_ATTRIBUTE_AECAGC_TARGET_1_2 = 0x12,
ORBIS_CAMERA_ATTRIBUTE_AECAGC_TARGET_1_0 = 0x10,
ORBIS_CAMERA_ATTRIBUTE_AECAGC_TARGET_0_8 = 0x08,
ORBIS_CAMERA_ATTRIBUTE_AECAGC_TARGET_0_6 = 0x06,
ORBIS_CAMERA_ATTRIBUTE_AECAGC_TARGET_0_4 = 0x04,
ORBIS_CAMERA_ATTRIBUTE_AECAGC_TARGET_0_2 = 0x02,
};
struct OrbisCameraDeviceInfo {
u32 sizeThis;
u32 infoRevision;
u32 deviceRevision;
u32 padding;
};
struct OrbisCameraStartParameter {
u32 sizeThis;
u32 formatLevel[ORBIS_CAMERA_MAX_DEVICE_NUM];
void* pStartOption;
};
struct OrbisCameraVideoSyncParameter {
u32 sizeThis;
u32 videoSyncMode;
void* pModeOption;
};
struct OrbisCameraFramePosition {
u32 x;
u32 y;
u32 xSize;
u32 ySize;
};
struct OrbisCameraAutoExposureGainTarget {
u32 sizeThis;
OrbisCameraAecAgcTarget target;
};
struct OrbisCameraExposureGain {
u32 exposureControl;
u32 exposure;
u32 gain;
u32 mode;
};
struct OrbisCameraWhiteBalance {
u32 whiteBalanceControl;
u32 gainRed;
u32 gainBlue;
u32 gainGreen;
};
struct OrbisCameraGamma {
u32 gammaControl;
u32 value;
u8 reserved[16];
};
struct OrbisCameraMeta {
u32 metaMode;
u32 format[ORBIS_CAMERA_MAX_DEVICE_NUM][ORBIS_CAMERA_MAX_FORMAT_LEVEL_NUM];
u64 frame[ORBIS_CAMERA_MAX_DEVICE_NUM];
u64 timestamp[ORBIS_CAMERA_MAX_DEVICE_NUM];
u32 deviceTimestamp[ORBIS_CAMERA_MAX_DEVICE_NUM];
OrbisCameraExposureGain exposureGain[ORBIS_CAMERA_MAX_DEVICE_NUM];
OrbisCameraWhiteBalance whiteBalance[ORBIS_CAMERA_MAX_DEVICE_NUM];
OrbisCameraGamma gamma[ORBIS_CAMERA_MAX_DEVICE_NUM];
u32 luminance[ORBIS_CAMERA_MAX_DEVICE_NUM];
float acceleration_x;
float acceleration_y;
float acceleration_z;
u64 vcounter;
u32 reserved[14];
};
struct OrbisCameraFrameData {
u32 sizeThis;
u32 readMode;
OrbisCameraFramePosition framePosition[ORBIS_CAMERA_MAX_DEVICE_NUM]
[ORBIS_CAMERA_MAX_FORMAT_LEVEL_NUM];
void* pFramePointerList[ORBIS_CAMERA_MAX_DEVICE_NUM][ORBIS_CAMERA_MAX_FORMAT_LEVEL_NUM];
u32 frameSize[ORBIS_CAMERA_MAX_DEVICE_NUM][ORBIS_CAMERA_MAX_FORMAT_LEVEL_NUM];
u32 status[ORBIS_CAMERA_MAX_DEVICE_NUM];
OrbisCameraMeta meta;
void* pFramePointerListGarlic[ORBIS_CAMERA_MAX_DEVICE_NUM][ORBIS_CAMERA_MAX_FORMAT_LEVEL_NUM];
};
struct OrbisCameraAttribute {
u32 sizeThis;
OrbisCameraChannel channel;
OrbisCameraFramePosition framePosition;
OrbisCameraExposureGain exposureGain;
OrbisCameraWhiteBalance whiteBalance;
OrbisCameraGamma gamma;
u32 saturation;
u32 contrast;
u32 sharpness;
s32 hue;
u32 reserved1;
u32 reserved2;
u32 reserved3;
u32 reserved4;
};
s32 PS4_SYSV_ABI sceCameraAccGetData();
s32 PS4_SYSV_ABI sceCameraAudioClose();
s32 PS4_SYSV_ABI sceCameraAudioGetData();
s32 PS4_SYSV_ABI sceCameraAudioGetData2();
s32 PS4_SYSV_ABI sceCameraAudioOpen();
s32 PS4_SYSV_ABI sceCameraAudioReset();
s32 PS4_SYSV_ABI sceCameraChangeAppModuleState();
s32 PS4_SYSV_ABI sceCameraClose(s32 handle);
s32 PS4_SYSV_ABI sceCameraCloseByHandle();
s32 PS4_SYSV_ABI sceCameraDeviceOpen();
s32 PS4_SYSV_ABI sceCameraGetAttribute(s32 handle, OrbisCameraAttribute* pAttribute);
s32 PS4_SYSV_ABI sceCameraGetAutoExposureGain(s32 handle, OrbisCameraChannel channel, u32* pEnable,
void* pOption);
s32 PS4_SYSV_ABI sceCameraGetAutoWhiteBalance(s32 handle, OrbisCameraChannel channel, u32* pEnable,
void* pOption);
s32 PS4_SYSV_ABI sceCameraGetCalibData();
s32 PS4_SYSV_ABI sceCameraGetCalibDataFromDevice();
s32 PS4_SYSV_ABI sceCameraGetCalibrationData();
s32 PS4_SYSV_ABI sceCameraGetConfig(s32 handle, OrbisCameraConfig* pConfig);
s32 PS4_SYSV_ABI sceCameraGetContrast(s32 handle, OrbisCameraChannel channel, u32* pContrast,
void* pOption);
s32 PS4_SYSV_ABI sceCameraGetDefectivePixelCancellation(s32 handle, OrbisCameraChannel channel,
u32* pEnable, void* pOption);
s32 PS4_SYSV_ABI sceCameraGetDeviceConfig();
s32 PS4_SYSV_ABI sceCameraGetDeviceConfigWithoutHandle();
s32 PS4_SYSV_ABI sceCameraGetDeviceID();
s32 PS4_SYSV_ABI sceCameraGetDeviceIDWithoutOpen();
s32 PS4_SYSV_ABI sceCameraGetDeviceInfo(s32 reserved, OrbisCameraDeviceInfo* pDeviceInfo);
s32 PS4_SYSV_ABI sceCameraGetExposureGain(s32 handle, OrbisCameraChannel channel,
OrbisCameraExposureGain* pExposureGain, void* pOption);
s32 PS4_SYSV_ABI sceCameraGetFrameData(int handle, OrbisCameraFrameData* pFrameData);
s32 PS4_SYSV_ABI sceCameraGetGamma(s32 handle, OrbisCameraChannel channel, OrbisCameraGamma* pGamma,
void* pOption);
s32 PS4_SYSV_ABI sceCameraGetHue(s32 handle, OrbisCameraChannel channel, s32* pHue, void* pOption);
s32 PS4_SYSV_ABI sceCameraGetLensCorrection(s32 handle, OrbisCameraChannel channel, u32* pEnable,
void* pOption);
s32 PS4_SYSV_ABI sceCameraGetMmapConnectedCount();
s32 PS4_SYSV_ABI sceCameraGetProductInfo();
s32 PS4_SYSV_ABI sceCameraGetRegister();
s32 PS4_SYSV_ABI sceCameraGetRegistryInfo();
s32 PS4_SYSV_ABI sceCameraGetSaturation(s32 handle, OrbisCameraChannel channel, u32* pSaturation,
void* pOption);
s32 PS4_SYSV_ABI sceCameraGetSharpness(s32 handle, OrbisCameraChannel channel, u32* pSharpness,
void* pOption);
s32 PS4_SYSV_ABI sceCameraGetVrCaptureInfo();
s32 PS4_SYSV_ABI sceCameraGetWhiteBalance(s32 handle, OrbisCameraChannel channel,
OrbisCameraWhiteBalance* pWhiteBalance, void* pOption);
s32 PS4_SYSV_ABI sceCameraInitializeRegistryCalibData();
s32 PS4_SYSV_ABI sceCameraIsAttached(s32 index);
s32 PS4_SYSV_ABI sceCameraIsConfigChangeDone();
s32 PS4_SYSV_ABI sceCameraIsValidFrameData(int handle, OrbisCameraFrameData* pFrameData);
s32 PS4_SYSV_ABI sceCameraOpen(Libraries::UserService::OrbisUserServiceUserId userId, s32 type,
s32 index, OrbisCameraOpenParameter* pParam);
s32 PS4_SYSV_ABI sceCameraOpenByModuleId();
s32 PS4_SYSV_ABI sceCameraRemoveAppModuleFocus();
s32 PS4_SYSV_ABI sceCameraSetAppModuleFocus();
s32 PS4_SYSV_ABI sceCameraSetAttribute(s32 handle, OrbisCameraAttribute* pAttribute);
s32 PS4_SYSV_ABI sceCameraSetAttributeInternal();
s32 PS4_SYSV_ABI sceCameraSetAutoExposureGain(s32 handle, OrbisCameraChannel channel, u32 enable,
void* pOption);
s32 PS4_SYSV_ABI sceCameraSetAutoWhiteBalance(s32 handle, OrbisCameraChannel channel, u32 enable,
void* pOption);
s32 PS4_SYSV_ABI sceCameraSetCalibData();
s32 PS4_SYSV_ABI sceCameraSetConfig(s32 handle, OrbisCameraConfig* pConfig);
s32 PS4_SYSV_ABI sceCameraSetConfigInternal();
s32 PS4_SYSV_ABI sceCameraSetContrast(s32 handle, OrbisCameraChannel channel, u32 contrast,
void* pOption);
s32 PS4_SYSV_ABI sceCameraSetDebugStop();
s32 PS4_SYSV_ABI sceCameraSetDefectivePixelCancellation(s32 handle, OrbisCameraChannel channel,
u32 enable, void* pOption);
s32 PS4_SYSV_ABI sceCameraSetDefectivePixelCancellationInternal();
s32 PS4_SYSV_ABI sceCameraSetExposureGain(s32 handle, OrbisCameraChannel channel,
OrbisCameraExposureGain* pExposureGain, void* pOption);
s32 PS4_SYSV_ABI sceCameraSetForceActivate();
s32 PS4_SYSV_ABI sceCameraSetGamma(s32 handle, OrbisCameraChannel channel, OrbisCameraGamma* pGamma,
void* pOption);
s32 PS4_SYSV_ABI sceCameraSetHue(s32 handle, OrbisCameraChannel channel, s32 hue, void* pOption);
s32 PS4_SYSV_ABI sceCameraSetLensCorrection(s32 handle, OrbisCameraChannel channel, u32 enable,
void* pOption);
s32 PS4_SYSV_ABI sceCameraSetLensCorrectionInternal();
s32 PS4_SYSV_ABI sceCameraSetProcessFocus();
s32 PS4_SYSV_ABI sceCameraSetProcessFocusByHandle();
s32 PS4_SYSV_ABI sceCameraSetRegister();
s32 PS4_SYSV_ABI sceCameraSetSaturation(s32 handle, OrbisCameraChannel channel, u32 saturation,
void* pOption);
s32 PS4_SYSV_ABI sceCameraSetSharpness(s32 handle, OrbisCameraChannel channel, u32 sharpness,
void* pOption);
s32 PS4_SYSV_ABI sceCameraSetTrackerMode();
s32 PS4_SYSV_ABI sceCameraSetUacModeInternal();
s32 PS4_SYSV_ABI sceCameraSetVideoSync(s32 handle, OrbisCameraVideoSyncParameter* pVideoSync);
s32 PS4_SYSV_ABI sceCameraSetVideoSyncInternal();
s32 PS4_SYSV_ABI sceCameraSetWhiteBalance(s32 handle, OrbisCameraChannel channel,
OrbisCameraWhiteBalance* pWhiteBalance, void* pOption);
s32 PS4_SYSV_ABI sceCameraStart(s32 handle, OrbisCameraStartParameter* pParam);
s32 PS4_SYSV_ABI sceCameraStartByHandle();
s32 PS4_SYSV_ABI sceCameraStop(s32 handle);
s32 PS4_SYSV_ABI sceCameraStopByHandle();
void RegisterLib(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::Camera

View File

@ -0,0 +1,29 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
constexpr int ORBIS_CAMERA_ERROR_PARAM = 0x802E0000;
constexpr int ORBIS_CAMERA_ERROR_ALREADY_INIT = 0x802E0001;
constexpr int ORBIS_CAMERA_ERROR_NOT_INIT = 0x802E0002;
constexpr int ORBIS_CAMERA_ERROR_ALREADY_OPEN = 0x802E0003;
constexpr int ORBIS_CAMERA_ERROR_NOT_OPEN = 0x802E0004;
constexpr int ORBIS_CAMERA_ERROR_ALREADY_START = 0x802E0005;
constexpr int ORBIS_CAMERA_ERROR_NOT_START = 0x802E0006;
constexpr int ORBIS_CAMERA_ERROR_FORMAT_UNKNOWN = 0x802E0007;
constexpr int ORBIS_CAMERA_ERROR_RESOLUTION_UNKNOWN = 0x802E0008;
constexpr int ORBIS_CAMERA_ERROR_BAD_FRAMERATE = 0x802E0009;
constexpr int ORBIS_CAMERA_ERROR_TIMEOUT = 0x802E000A;
constexpr int ORBIS_CAMERA_ERROR_ATTRIBUTE_UNKNOWN = 0x802E000B;
constexpr int ORBIS_CAMERA_ERROR_BUSY = 0x802E000C;
constexpr int ORBIS_CAMERA_ERROR_UNKNOWN_CONFIG = 0x802E000D;
constexpr int ORBIS_CAMERA_ERROR_ALREADY_READ = 0x802E000F;
constexpr int ORBIS_CAMERA_ERROR_NOT_CONNECTED = 0x802E0010;
constexpr int ORBIS_CAMERA_ERROR_NOT_SUPPORTED = 0x802E0011;
constexpr int ORBIS_CAMERA_ERROR_INVALID_CONFIG = 0x802E0013;
constexpr int ORBIS_CAMERA_ERROR_MAX_HANDLE = 0x802E0014;
constexpr int ORBIS_CAMERA_ERROR_MAX_PROCESS = 0x802E00FB;
constexpr int ORBIS_CAMERA_ERROR_COPYOUT_FAILED = 0x802E00FC;
constexpr int ORBIS_CAMERA_ERROR_COPYIN_FAILED = 0x802E00FD;
constexpr int ORBIS_CAMERA_ERROR_KPROC_CREATE = 0x802E00FE;
constexpr int ORBIS_CAMERA_ERROR_FATAL = 0x802E00FF;

View File

@ -0,0 +1,27 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/types.h"
// companion_httpd error codes
constexpr int ORBIS_COMPANION_HTTPD_ERROR_UNKNOWN = 0x80E40001;
constexpr int ORBIS_COMPANION_HTTPD_ERROR_FATAL = 0x80E40002;
constexpr int ORBIS_COMPANION_HTTPD_ERROR_NOMEM = 0x80E40003;
constexpr int ORBIS_COMPANION_HTTPD_ERROR_INVALID_PARAM = 0x80E40004;
constexpr int ORBIS_COMPANION_HTTPD_ERROR_INVALID_OPERATION = 0x80E40005;
constexpr int ORBIS_COMPANION_HTTPD_ERROR_NOT_INITIALIZED = 0x80E40006;
constexpr int ORBIS_COMPANION_HTTPD_ERROR_ALREADY_INITIALIZED = 0x80E40007;
constexpr int ORBIS_COMPANION_HTTPD_ERROR_NO_EVENT = 0x80E40008;
constexpr int ORBIS_COMPANION_HTTPD_ERROR_NOT_GENERATE_RESPONSE = 0x80E40009;
constexpr int ORBIS_COMPANION_HTTPD_ERROR_ALREADY_STARTED = 0x80E4000A;
constexpr int ORBIS_COMPANION_HTTPD_ERROR_NOT_STARTED = 0x80E4000B;
constexpr int ORBIS_COMPANION_HTTPD_ERROR_ALREADY_REGISTERED = 0x80E4000;
constexpr int ORBIS_COMPANION_HTTPD_ERROR_NOT_CONNECTED = 0x80E4000D;
constexpr int ORBIS_COMPANION_HTTPD_ERROR_USER_NOT_FOUND = 0x80E4000E;
// companion_util error codes
constexpr u32 ORBIS_COMPANION_UTIL_INVALID_ARGUMENT = 0x80AD0004;
constexpr u32 ORBIS_COMPANION_UTIL_INVALID_POINTER = 0x80AD0006;
constexpr u32 ORBIS_COMPANION_UTIL_NO_EVENT = 0x80AD0008;

View File

@ -0,0 +1,142 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
#include "companion_error.h"
#include "core/libraries/companion/companion_httpd.h"
#include "core/libraries/error_codes.h"
#include "core/libraries/libs.h"
namespace Libraries::CompanionHttpd {
s32 PS4_SYSV_ABI sceCompanionHttpdAddHeader(const char* key, const char* value,
OrbisCompanionHttpdResponse* response) {
LOG_ERROR(Lib_CompanionHttpd, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI
sceCompanionHttpdGet2ndScreenStatus(Libraries::UserService::OrbisUserServiceUserId) {
LOG_ERROR(Lib_CompanionHttpd, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCompanionHttpdGetEvent(OrbisCompanionHttpdEvent* pEvent) {
pEvent->event = ORBIS_COMPANION_HTTPD_EVENT_DISCONNECT; // disconnected
LOG_DEBUG(Lib_CompanionHttpd, "device disconnected");
return ORBIS_COMPANION_HTTPD_ERROR_NO_EVENT; // No events to obtain
}
s32 PS4_SYSV_ABI
sceCompanionHttpdGetUserId(u32 addr, Libraries::UserService::OrbisUserServiceUserId* userId) {
LOG_ERROR(Lib_CompanionHttpd, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCompanionHttpdInitialize() {
LOG_ERROR(Lib_CompanionHttpd, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCompanionHttpdInitialize2() {
LOG_ERROR(Lib_CompanionHttpd, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCompanionHttpdOptParamInitialize() {
LOG_ERROR(Lib_CompanionHttpd, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCompanionHttpdRegisterRequestBodyReceptionCallback(
OrbisCompanionHttpdRequestBodyReceptionCallback function, void* param) {
LOG_ERROR(Lib_CompanionHttpd, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI
sceCompanionHttpdRegisterRequestCallback(OrbisCompanionHttpdRequestCallback function, void* param) {
LOG_ERROR(Lib_CompanionHttpd, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCompanionHttpdRegisterRequestCallback2(
OrbisCompanionHttpdRequestCallback function, void* param) {
LOG_ERROR(Lib_CompanionHttpd, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCompanionHttpdSetBody(const char* body, u64 bodySize,
OrbisCompanionHttpdResponse* response) {
LOG_ERROR(Lib_CompanionHttpd, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCompanionHttpdSetStatus(s32 status, OrbisCompanionHttpdResponse* response) {
LOG_ERROR(Lib_CompanionHttpd, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCompanionHttpdStart() {
LOG_ERROR(Lib_CompanionHttpd, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCompanionHttpdStop() {
LOG_ERROR(Lib_CompanionHttpd, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCompanionHttpdTerminate() {
LOG_ERROR(Lib_CompanionHttpd, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCompanionHttpdUnregisterRequestBodyReceptionCallback() {
LOG_ERROR(Lib_CompanionHttpd, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCompanionHttpdUnregisterRequestCallback() {
LOG_ERROR(Lib_CompanionHttpd, "(STUBBED) called");
return ORBIS_OK;
}
void RegisterLib(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("8pWltDG7h6A", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
sceCompanionHttpdAddHeader);
LIB_FUNCTION("B-QBMeFdNgY", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
sceCompanionHttpdGet2ndScreenStatus);
LIB_FUNCTION("Vku4big+IYM", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
sceCompanionHttpdGetEvent);
LIB_FUNCTION("0SySxcuVNG0", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
sceCompanionHttpdGetUserId);
LIB_FUNCTION("ykNpWs3ktLY", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
sceCompanionHttpdInitialize);
LIB_FUNCTION("OA6FbORefbo", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
sceCompanionHttpdInitialize2);
LIB_FUNCTION("r-2-a0c7Kfc", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
sceCompanionHttpdOptParamInitialize);
LIB_FUNCTION("fHNmij7kAUM", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
sceCompanionHttpdRegisterRequestBodyReceptionCallback);
LIB_FUNCTION("OaWw+IVEdbI", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
sceCompanionHttpdRegisterRequestCallback);
LIB_FUNCTION("-0c9TCTwnGs", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
sceCompanionHttpdRegisterRequestCallback2);
LIB_FUNCTION("h3OvVxzX4qM", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
sceCompanionHttpdSetBody);
LIB_FUNCTION("w7oz0AWHpT4", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
sceCompanionHttpdSetStatus);
LIB_FUNCTION("k7F0FcDM-Xc", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
sceCompanionHttpdStart);
LIB_FUNCTION("0SCgzfVQHpo", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
sceCompanionHttpdStop);
LIB_FUNCTION("+-du9tWgE9s", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
sceCompanionHttpdTerminate);
LIB_FUNCTION("ZSHiUfYK+QI", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
sceCompanionHttpdUnregisterRequestBodyReceptionCallback);
LIB_FUNCTION("xweOi2QT-BE", "libSceCompanionHttpd", 1, "libSceCompanionHttpd", 1, 1,
sceCompanionHttpdUnregisterRequestCallback);
};
} // namespace Libraries::CompanionHttpd

View File

@ -0,0 +1,91 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/types.h"
#include "core/libraries/network/net.h"
#include "core/libraries/system/userservice.h"
namespace Core::Loader {
class SymbolsResolver;
}
namespace Libraries::CompanionHttpd {
// OrbisCompanionHttpdEvent event codes
constexpr int ORBIS_COMPANION_HTTPD_EVENT_CONNECT = 0x10000001;
constexpr int ORBIS_COMPANION_HTTPD_EVENT_DISCONNECT = 0x10000002;
struct OrbisCompanionHttpdHeader {
char* key;
char* value;
struct OrbisCompanionHttpdHeader* header;
};
struct OrbisCompanionHttpdRequest {
s32 method;
char* url;
OrbisCompanionHttpdHeader* header;
char* body;
u64 bodySize;
};
struct OrbisCompanionHttpdResponse {
s32 status;
OrbisCompanionHttpdHeader* header;
char* body;
u64 bodySize;
};
using OrbisCompanionHttpdRequestBodyReceptionCallback =
PS4_SYSV_ABI s32 (*)(s32 event, Libraries::UserService::OrbisUserServiceUserId userId,
const OrbisCompanionHttpdRequest* httpRequest, void* param);
using OrbisCompanionHttpdRequestCallback =
PS4_SYSV_ABI s32 (*)(Libraries::UserService::OrbisUserServiceUserId userId,
const OrbisCompanionHttpdRequest* httpRequest,
OrbisCompanionHttpdResponse* httpResponse, void* param);
struct OrbisCompanionUtilDeviceInfo {
Libraries::UserService::OrbisUserServiceUserId userId;
Libraries::Net::OrbisNetSockaddrIn addr;
char reserved[236];
};
struct OrbisCompanionHttpdEvent {
s32 event;
union {
OrbisCompanionUtilDeviceInfo deviceInfo;
Libraries::UserService::OrbisUserServiceUserId userId;
char reserved[256];
} data;
};
s32 PS4_SYSV_ABI sceCompanionHttpdAddHeader(const char* key, const char* value,
OrbisCompanionHttpdResponse* response);
s32 PS4_SYSV_ABI
sceCompanionHttpdGet2ndScreenStatus(Libraries::UserService::OrbisUserServiceUserId userId);
s32 PS4_SYSV_ABI sceCompanionHttpdGetEvent(OrbisCompanionHttpdEvent* pEvent);
s32 PS4_SYSV_ABI sceCompanionHttpdGetUserId(u32 addr,
Libraries::UserService::OrbisUserServiceUserId* userId);
s32 PS4_SYSV_ABI sceCompanionHttpdInitialize();
s32 PS4_SYSV_ABI sceCompanionHttpdInitialize2();
s32 PS4_SYSV_ABI sceCompanionHttpdOptParamInitialize();
s32 PS4_SYSV_ABI sceCompanionHttpdRegisterRequestBodyReceptionCallback(
OrbisCompanionHttpdRequestBodyReceptionCallback function, void* param);
s32 PS4_SYSV_ABI
sceCompanionHttpdRegisterRequestCallback(OrbisCompanionHttpdRequestCallback function, void* param);
s32 PS4_SYSV_ABI
sceCompanionHttpdRegisterRequestCallback2(OrbisCompanionHttpdRequestCallback function, void* param);
s32 PS4_SYSV_ABI sceCompanionHttpdSetBody(const char* body, u64 bodySize,
OrbisCompanionHttpdResponse* response);
s32 PS4_SYSV_ABI sceCompanionHttpdSetStatus(s32 status, OrbisCompanionHttpdResponse* response);
s32 PS4_SYSV_ABI sceCompanionHttpdStart();
s32 PS4_SYSV_ABI sceCompanionHttpdStop();
s32 PS4_SYSV_ABI sceCompanionHttpdTerminate();
s32 PS4_SYSV_ABI sceCompanionHttpdUnregisterRequestBodyReceptionCallback();
s32 PS4_SYSV_ABI sceCompanionHttpdUnregisterRequestCallback();
void RegisterLib(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::CompanionHttpd

View File

@ -0,0 +1,72 @@
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
#include "companion_error.h"
#include "core/libraries/companion/companion_util.h"
#include "core/libraries/error_codes.h"
#include "core/libraries/libs.h"
namespace Libraries::CompanionUtil {
u32 PS4_SYSV_ABI getEvent(sceCompanionUtilContext* ctx, sceCompanionUtilEvent* outEvent,
s32 param_3) {
if (outEvent == 0) {
return ORBIS_COMPANION_UTIL_INVALID_ARGUMENT;
}
if (ctx == nullptr) {
return ORBIS_COMPANION_UTIL_INVALID_POINTER;
}
uint8_t* base = ctx->blob;
int flag = *reinterpret_cast<int*>(base + 0x178);
if (flag == 0) {
return ORBIS_COMPANION_UTIL_NO_EVENT;
}
return ORBIS_COMPANION_UTIL_OK;
}
s32 PS4_SYSV_ABI sceCompanionUtilGetEvent(sceCompanionUtilEvent* outEvent) {
sceCompanionUtilContext* ctx = nullptr;
u32 ret = getEvent(ctx, outEvent, 1);
LOG_DEBUG(Lib_CompanionUtil, "(STUBBED) called ret: {}", ret);
return ret;
}
s32 PS4_SYSV_ABI sceCompanionUtilGetRemoteOskEvent() {
LOG_ERROR(Lib_CompanionUtil, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCompanionUtilInitialize() {
LOG_ERROR(Lib_CompanionUtil, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCompanionUtilOptParamInitialize() {
LOG_ERROR(Lib_CompanionUtil, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceCompanionUtilTerminate() {
LOG_ERROR(Lib_CompanionUtil, "(STUBBED) called");
return ORBIS_OK;
}
void RegisterLib(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("cE5Msy11WhU", "libSceCompanionUtil", 1, "libSceCompanionUtil", 1, 1,
sceCompanionUtilGetEvent);
LIB_FUNCTION("MaVrz79mT5o", "libSceCompanionUtil", 1, "libSceCompanionUtil", 1, 1,
sceCompanionUtilGetRemoteOskEvent);
LIB_FUNCTION("xb1xlIhf0QY", "libSceCompanionUtil", 1, "libSceCompanionUtil", 1, 1,
sceCompanionUtilInitialize);
LIB_FUNCTION("IPN-FRSrafk", "libSceCompanionUtil", 1, "libSceCompanionUtil", 1, 1,
sceCompanionUtilOptParamInitialize);
LIB_FUNCTION("H1fYQd5lFAI", "libSceCompanionUtil", 1, "libSceCompanionUtil", 1, 1,
sceCompanionUtilTerminate);
};
} // namespace Libraries::CompanionUtil

View File

@ -0,0 +1,33 @@
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/types.h"
namespace Core::Loader {
class SymbolsResolver;
}
namespace Libraries::CompanionUtil {
constexpr u32 ORBIS_COMPANION_UTIL_OK = 0;
struct sceCompanionUtilEvent {
std::uint8_t blob[0x104]{}; /// 0x104 bytes of data, dont know what it is exactly
};
struct sceCompanionUtilContext {
std::uint8_t blob[0x27B]{}; /// 0x27B bytes of data, dont know what it is exactly
};
u32 PS4_SYSV_ABI getEvent(sceCompanionUtilContext* ctx, sceCompanionUtilEvent* outEvent,
s32 param_3);
s32 PS4_SYSV_ABI sceCompanionUtilGetEvent(sceCompanionUtilEvent* outEvent);
s32 PS4_SYSV_ABI sceCompanionUtilGetRemoteOskEvent();
s32 PS4_SYSV_ABI sceCompanionUtilInitialize();
s32 PS4_SYSV_ABI sceCompanionUtilOptParamInitialize();
s32 PS4_SYSV_ABI sceCompanionUtilTerminate();
void RegisterLib(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::CompanionUtil

View File

@ -34,7 +34,7 @@ int PS4_SYSV_ABI Func_E7EBCE96E92F91F8() {
return ORBIS_DISC_MAP_ERROR_NO_BITMAP_INFO; return ORBIS_DISC_MAP_ERROR_NO_BITMAP_INFO;
} }
void RegisterlibSceDiscMap(Core::Loader::SymbolsResolver* sym) { void RegisterLib(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("fl1eoDnwQ4s", "libSceDiscMap", 1, "libSceDiscMap", 1, 1, LIB_FUNCTION("fl1eoDnwQ4s", "libSceDiscMap", 1, "libSceDiscMap", 1, 1,
sceDiscMapGetPackageSize); sceDiscMapGetPackageSize);
LIB_FUNCTION("lbQKqsERhtE", "libSceDiscMap", 1, "libSceDiscMap", 1, 1, LIB_FUNCTION("lbQKqsERhtE", "libSceDiscMap", 1, "libSceDiscMap", 1, 1,

View File

@ -18,5 +18,5 @@ int PS4_SYSV_ABI Func_8A828CAEE7EDD5E9(char* path, s64 offset, s64 nbytes, int*
int* ret2); int* ret2);
int PS4_SYSV_ABI Func_E7EBCE96E92F91F8(); int PS4_SYSV_ABI Func_E7EBCE96E92F91F8();
void RegisterlibSceDiscMap(Core::Loader::SymbolsResolver* sym); void RegisterLib(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::DiscMap } // namespace Libraries::DiscMap

View File

@ -545,7 +545,7 @@ s32 PS4_SYSV_ABI sceFiberSwitch(OrbisFiber* fiber, u64 arg_on_run_to, u64* arg_o
return sceFiberSwitchImpl(fiber, nullptr, 0, arg_on_run_to, arg_on_run); return sceFiberSwitchImpl(fiber, nullptr, 0, arg_on_run_to, arg_on_run);
} }
void RegisterlibSceFiber(Core::Loader::SymbolsResolver* sym) { void RegisterLib(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("hVYD7Ou2pCQ", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberInitialize); LIB_FUNCTION("hVYD7Ou2pCQ", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberInitialize);
LIB_FUNCTION("7+OJIpko9RY", "libSceFiber", 1, "libSceFiber", 1, 1, LIB_FUNCTION("7+OJIpko9RY", "libSceFiber", 1, "libSceFiber", 1, 1,
sceFiberInitializeImpl); // _sceFiberInitializeWithInternalOptionImpl sceFiberInitializeImpl); // _sceFiberInitializeWithInternalOptionImpl

View File

@ -116,5 +116,5 @@ s32 PS4_SYSV_ABI sceFiberRename(OrbisFiber* fiber, const char* name);
s32 PS4_SYSV_ABI sceFiberGetThreadFramePointerAddress(u64* addr_frame_pointer); s32 PS4_SYSV_ABI sceFiberGetThreadFramePointerAddress(u64* addr_frame_pointer);
void RegisterlibSceFiber(Core::Loader::SymbolsResolver* sym); void RegisterLib(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::Fiber } // namespace Libraries::Fiber

View File

@ -246,7 +246,7 @@ int PS4_SYSV_ABI sceGameLiveStreamingUnregisterCallback() {
return ORBIS_OK; return ORBIS_OK;
} }
void RegisterlibSceGameLiveStreaming(Core::Loader::SymbolsResolver* sym) { void RegisterLib(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("caqgDl+V9qA", "libSceGameLiveStreaming_debug", 1, "libSceGameLiveStreaming", 1, 1, LIB_FUNCTION("caqgDl+V9qA", "libSceGameLiveStreaming_debug", 1, "libSceGameLiveStreaming", 1, 1,
sceGameLiveStreamingStartDebugBroadcast); sceGameLiveStreamingStartDebugBroadcast);
LIB_FUNCTION("0i8Lrllxwow", "libSceGameLiveStreaming_debug", 1, "libSceGameLiveStreaming", 1, 1, LIB_FUNCTION("0i8Lrllxwow", "libSceGameLiveStreaming_debug", 1, "libSceGameLiveStreaming", 1, 1,

View File

@ -77,5 +77,5 @@ int PS4_SYSV_ABI sceGameLiveStreamingStopSocialFeedbackMessageFiltering();
int PS4_SYSV_ABI sceGameLiveStreamingTerminate(); int PS4_SYSV_ABI sceGameLiveStreamingTerminate();
int PS4_SYSV_ABI sceGameLiveStreamingUnregisterCallback(); int PS4_SYSV_ABI sceGameLiveStreamingUnregisterCallback();
void RegisterlibSceGameLiveStreaming(Core::Loader::SymbolsResolver* sym); void RegisterLib(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::GameLiveStreaming } // namespace Libraries::GameLiveStreaming

View File

@ -179,7 +179,7 @@ s32 PS4_SYSV_ABI sceGnmComputeWaitOnAddress(u32* cmdbuf, u32 size, uintptr_t add
auto* wait_reg_mem = reinterpret_cast<PM4CmdWaitRegMem*>(cmdbuf); auto* wait_reg_mem = reinterpret_cast<PM4CmdWaitRegMem*>(cmdbuf);
wait_reg_mem->header = PM4Type3Header{PM4ItOpcode::WaitRegMem, 5}; wait_reg_mem->header = PM4Type3Header{PM4ItOpcode::WaitRegMem, 5};
wait_reg_mem->raw = (is_mem << 4u) | (cmp_func & 7u); wait_reg_mem->raw = (is_mem << 4u) | (cmp_func & 7u);
wait_reg_mem->poll_addr_lo = u32(addr & addr_mask); wait_reg_mem->poll_addr_lo_raw = u32(addr & addr_mask);
wait_reg_mem->poll_addr_hi = u32(addr >> 32u); wait_reg_mem->poll_addr_hi = u32(addr >> 32u);
wait_reg_mem->ref = ref; wait_reg_mem->ref = ref;
wait_reg_mem->mask = mask; wait_reg_mem->mask = mask;
@ -505,9 +505,10 @@ s32 PS4_SYSV_ABI sceGnmDrawIndexIndirectCountMulti(u32* cmdbuf, u32 size, u32 da
u32 flags) { u32 flags) {
LOG_TRACE(Lib_GnmDriver, "called"); LOG_TRACE(Lib_GnmDriver, "called");
if ((!sceKernelIsNeoMode() || !UseNeoCompatSequences) && !cmdbuf && (size == 16) && if ((!sceKernelIsNeoMode() || !UseNeoCompatSequences) && cmdbuf && (size == 16) &&
(shader_stage < ShaderStages::Max) && (vertex_sgpr_offset < 0x10u) && (vertex_sgpr_offset < 0x10u) && (instance_sgpr_offset < 0x10u) &&
(instance_sgpr_offset < 0x10u)) { (shader_stage == ShaderStages::Vs || shader_stage == ShaderStages::Es ||
shader_stage == ShaderStages::Ls)) {
cmdbuf = WriteHeader<PM4ItOpcode::Nop>(cmdbuf, 2); cmdbuf = WriteHeader<PM4ItOpcode::Nop>(cmdbuf, 2);
cmdbuf = WriteBody(cmdbuf, 0u); cmdbuf = WriteBody(cmdbuf, 0u);
@ -535,10 +536,33 @@ s32 PS4_SYSV_ABI sceGnmDrawIndexIndirectCountMulti(u32* cmdbuf, u32 size, u32 da
return -1; return -1;
} }
int PS4_SYSV_ABI sceGnmDrawIndexIndirectMulti() { int PS4_SYSV_ABI sceGnmDrawIndexIndirectMulti(u32* cmdbuf, u32 size, u32 data_offset, u32 max_count,
LOG_ERROR(Lib_GnmDriver, "(STUBBED) called"); u32 shader_stage, u32 vertex_sgpr_offset,
UNREACHABLE(); u32 instance_sgpr_offset, u32 flags) {
return ORBIS_OK; LOG_TRACE(Lib_GnmDriver, "called");
if (cmdbuf && (size == 11) && (vertex_sgpr_offset < 0x10u) && (instance_sgpr_offset < 0x10u) &&
(shader_stage == ShaderStages::Vs || shader_stage == ShaderStages::Es ||
shader_stage == ShaderStages::Ls)) {
const auto predicate = flags & 1 ? PM4Predicate::PredEnable : PM4Predicate::PredDisable;
cmdbuf = WriteHeader<PM4ItOpcode::DrawIndexIndirectMulti>(
cmdbuf, 6, PM4ShaderType::ShaderGraphics, predicate);
const auto sgpr_offset = indirect_sgpr_offsets[shader_stage];
cmdbuf[0] = data_offset;
cmdbuf[1] = vertex_sgpr_offset == 0 ? 0 : (vertex_sgpr_offset & 0xffffu) + sgpr_offset;
cmdbuf[2] = instance_sgpr_offset == 0 ? 0 : (instance_sgpr_offset & 0xffffu) + sgpr_offset;
cmdbuf[3] = max_count;
cmdbuf[4] = sizeof(DrawIndexedIndirectArgs);
cmdbuf[5] = sceKernelIsNeoMode() ? flags & 0xe0000000u : 0;
cmdbuf += 6;
WriteTrailingNop<3>(cmdbuf);
return ORBIS_OK;
}
return -1;
} }
int PS4_SYSV_ABI sceGnmDrawIndexMultiInstanced() { int PS4_SYSV_ABI sceGnmDrawIndexMultiInstanced() {
@ -2799,7 +2823,7 @@ int PS4_SYSV_ABI Func_F916890425496553() {
return ORBIS_OK; return ORBIS_OK;
} }
void RegisterlibSceGnmDriver(Core::Loader::SymbolsResolver* sym) { void RegisterLib(Core::Loader::SymbolsResolver* sym) {
LOG_INFO(Lib_GnmDriver, "Initializing presenter"); LOG_INFO(Lib_GnmDriver, "Initializing presenter");
liverpool = std::make_unique<AmdGpu::Liverpool>(); liverpool = std::make_unique<AmdGpu::Liverpool>();
presenter = std::make_unique<Vulkan::Presenter>(*g_window, liverpool.get()); presenter = std::make_unique<Vulkan::Presenter>(*g_window, liverpool.get());
@ -2810,7 +2834,7 @@ void RegisterlibSceGnmDriver(Core::Loader::SymbolsResolver* sym) {
} }
if (Config::copyGPUCmdBuffers()) { if (Config::copyGPUCmdBuffers()) {
liverpool->reserveCopyBufferSpace(); liverpool->ReserveCopyBufferSpace();
} }
Platform::IrqC::Instance()->Register(Platform::InterruptId::GpuIdle, ResetSubmissionLock, Platform::IrqC::Instance()->Register(Platform::InterruptId::GpuIdle, ResetSubmissionLock,

View File

@ -51,7 +51,9 @@ s32 PS4_SYSV_ABI sceGnmDrawIndexIndirectCountMulti(u32* cmdbuf, u32 size, u32 da
u32 max_count, u64 count_addr, u32 shader_stage, u32 max_count, u64 count_addr, u32 shader_stage,
u32 vertex_sgpr_offset, u32 instance_sgpr_offset, u32 vertex_sgpr_offset, u32 instance_sgpr_offset,
u32 flags); u32 flags);
int PS4_SYSV_ABI sceGnmDrawIndexIndirectMulti(); int PS4_SYSV_ABI sceGnmDrawIndexIndirectMulti(u32* cmdbuf, u32 size, u32 data_offset, u32 max_count,
u32 shader_stage, u32 vertex_sgpr_offset,
u32 instance_sgpr_offset, u32 flags);
int PS4_SYSV_ABI sceGnmDrawIndexMultiInstanced(); int PS4_SYSV_ABI sceGnmDrawIndexMultiInstanced();
s32 PS4_SYSV_ABI sceGnmDrawIndexOffset(u32* cmdbuf, u32 size, u32 index_offset, u32 index_count, s32 PS4_SYSV_ABI sceGnmDrawIndexOffset(u32* cmdbuf, u32 size, u32 index_offset, u32 index_count,
u32 flags); u32 flags);
@ -295,5 +297,5 @@ int PS4_SYSV_ABI Func_BFB41C057478F0BF();
int PS4_SYSV_ABI Func_E51D44DB8151238C(); int PS4_SYSV_ABI Func_E51D44DB8151238C();
int PS4_SYSV_ABI Func_F916890425496553(); int PS4_SYSV_ABI Func_F916890425496553();
void RegisterlibSceGnmDriver(Core::Loader::SymbolsResolver* sym); void RegisterLib(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::GnmDriver } // namespace Libraries::GnmDriver

View File

@ -939,7 +939,7 @@ s32 PS4_SYSV_ABI Func_FF2E0E53015FE231() {
return ORBIS_OK; return ORBIS_OK;
} }
void RegisterlibSceHmd(Core::Loader::SymbolsResolver* sym) { void RegisterLib(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("8gH1aLgty5I", "libsceHmdReprojectionMultilayer", 1, "libSceHmd", 1, 1, LIB_FUNCTION("8gH1aLgty5I", "libsceHmdReprojectionMultilayer", 1, "libSceHmd", 1, 1,
sceHmdReprojectionStartMultilayer); sceHmdReprojectionStartMultilayer);
LIB_FUNCTION("gEokC+OGI8g", "libSceHmdDistortion", 1, "libSceHmd", 1, 1, LIB_FUNCTION("gEokC+OGI8g", "libSceHmdDistortion", 1, "libSceHmd", 1, 1,

View File

@ -199,5 +199,5 @@ s32 PS4_SYSV_ABI Func_B9A6FA0735EC7E49();
s32 PS4_SYSV_ABI Func_FC193BD653F2AF2E(); s32 PS4_SYSV_ABI Func_FC193BD653F2AF2E();
s32 PS4_SYSV_ABI Func_FF2E0E53015FE231(); s32 PS4_SYSV_ABI Func_FF2E0E53015FE231();
void RegisterlibSceHmd(Core::Loader::SymbolsResolver* sym); void RegisterLib(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::Hmd } // namespace Libraries::Hmd

View File

@ -190,7 +190,7 @@ Status PS4_SYSV_ABI sceErrorDialogUpdateStatus() {
return g_status; return g_status;
} }
void RegisterlibSceErrorDialog(Core::Loader::SymbolsResolver* sym) { void RegisterLib(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("ekXHb1kDBl0", "libSceErrorDialog", 1, "libSceErrorDialog", 1, 1, LIB_FUNCTION("ekXHb1kDBl0", "libSceErrorDialog", 1, "libSceErrorDialog", 1, 1,
sceErrorDialogClose); sceErrorDialogClose);
LIB_FUNCTION("t2FvHRXzgqk", "libSceErrorDialog", 1, "libSceErrorDialog", 1, 1, LIB_FUNCTION("t2FvHRXzgqk", "libSceErrorDialog", 1, "libSceErrorDialog", 1, 1,

View File

@ -24,5 +24,5 @@ int PS4_SYSV_ABI sceErrorDialogOpenWithReport();
CommonDialog::Error PS4_SYSV_ABI sceErrorDialogTerminate(); CommonDialog::Error PS4_SYSV_ABI sceErrorDialogTerminate();
CommonDialog::Status PS4_SYSV_ABI sceErrorDialogUpdateStatus(); CommonDialog::Status PS4_SYSV_ABI sceErrorDialogUpdateStatus();
void RegisterlibSceErrorDialog(Core::Loader::SymbolsResolver* sym); void RegisterLib(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::ErrorDialog } // namespace Libraries::ErrorDialog

View File

@ -18,9 +18,11 @@ static ImeUi g_ime_ui;
class ImeHandler { class ImeHandler {
public: public:
ImeHandler(const OrbisImeKeyboardParam* param) { ImeHandler(const OrbisImeKeyboardParam* param) {
LOG_INFO(Lib_Ime, "Creating ImeHandler for keyboard");
Init(param, false); Init(param, false);
} }
ImeHandler(const OrbisImeParam* param) { ImeHandler(const OrbisImeParam* param) {
LOG_INFO(Lib_Ime, "Creating ImeHandler for IME");
Init(param, true); Init(param, true);
} }
~ImeHandler() = default; ~ImeHandler() = default;
@ -38,13 +40,18 @@ public:
openEvent.id = (ime_mode ? OrbisImeEventId::Open : OrbisImeEventId::KeyboardOpen); openEvent.id = (ime_mode ? OrbisImeEventId::Open : OrbisImeEventId::KeyboardOpen);
if (ime_mode) { if (ime_mode) {
sceImeGetPanelSize(&m_param.ime, &openEvent.param.rect.width, LOG_INFO(Lib_Ime, "calling sceImeGetPanelSize");
&openEvent.param.rect.height); Error e = sceImeGetPanelSize(&m_param.ime, &openEvent.param.rect.width,
&openEvent.param.rect.height);
if (e != Error::OK) {
LOG_ERROR(Lib_Ime, "sceImeGetPanelSize returned 0x{:X}", static_cast<u32>(e));
}
openEvent.param.rect.x = m_param.ime.posx; openEvent.param.rect.x = m_param.ime.posx;
openEvent.param.rect.y = m_param.ime.posy; openEvent.param.rect.y = m_param.ime.posy;
} else { } else {
openEvent.param.resource_id_array.userId = 1; openEvent.param.resource_id_array.user_id = 1;
openEvent.param.resource_id_array.resourceId[0] = 1; openEvent.param.resource_id_array.resource_id[0] = 1;
} }
// Are we supposed to call the event handler on init with // Are we supposed to call the event handler on init with
@ -59,13 +66,13 @@ public:
} }
} }
s32 Update(OrbisImeEventHandler handler) { Error Update(OrbisImeEventHandler handler) {
if (!m_ime_mode) { if (!m_ime_mode) {
/* We don't handle any events for ImeKeyboard */ /* We don't handle any events for ImeKeyboard */
return ORBIS_OK; return Error::OK;
} }
std::unique_lock lock{g_ime_state.queue_mutex}; std::unique_lock<std::mutex> lock{g_ime_state.queue_mutex};
while (!g_ime_state.event_queue.empty()) { while (!g_ime_state.event_queue.empty()) {
OrbisImeEvent event = g_ime_state.event_queue.front(); OrbisImeEvent event = g_ime_state.event_queue.front();
@ -73,7 +80,7 @@ public:
Execute(handler, &event, false); Execute(handler, &event, false);
} }
return ORBIS_OK; return Error::OK;
} }
void Execute(OrbisImeEventHandler handler, OrbisImeEvent* event, bool use_param_handler) { void Execute(OrbisImeEventHandler handler, OrbisImeEvent* event, bool use_param_handler) {
@ -94,14 +101,14 @@ public:
} }
} }
s32 SetText(const char16_t* text, u32 length) { Error SetText(const char16_t* text, u32 length) {
g_ime_state.SetText(text, length); g_ime_state.SetText(text, length);
return ORBIS_OK; return Error::OK;
} }
s32 SetCaret(const OrbisImeCaret* caret) { Error SetCaret(const OrbisImeCaret* caret) {
g_ime_state.SetCaret(caret->index); g_ime_state.SetCaret(caret->index);
return ORBIS_OK; return Error::OK;
} }
bool IsIme() { bool IsIme() {
@ -144,17 +151,22 @@ int PS4_SYSV_ABI sceImeCheckUpdateTextInfo() {
return ORBIS_OK; return ORBIS_OK;
} }
s32 PS4_SYSV_ABI sceImeClose() { Error PS4_SYSV_ABI sceImeClose() {
LOG_INFO(Lib_Ime, "(STUBBED) called"); LOG_INFO(Lib_Ime, "called");
if (!g_ime_handler) { if (!g_ime_handler) {
return ORBIS_IME_ERROR_NOT_OPENED; return Error::NOT_OPENED;
} }
g_ime_handler.release(); g_ime_handler.release();
if (g_keyboard_handler) {
return Error::INTERNAL;
}
g_ime_ui = ImeUi(); g_ime_ui = ImeUi();
g_ime_state = ImeState(); g_ime_state = ImeState();
return ORBIS_OK;
LOG_INFO(Lib_Ime, "IME closed successfully");
return Error::OK;
} }
int PS4_SYSV_ABI sceImeConfigGet() { int PS4_SYSV_ABI sceImeConfigGet() {
@ -222,40 +234,87 @@ int PS4_SYSV_ABI sceImeGetPanelPositionAndForm() {
return ORBIS_OK; return ORBIS_OK;
} }
s32 PS4_SYSV_ABI sceImeGetPanelSize(const OrbisImeParam* param, u32* width, u32* height) { Error PS4_SYSV_ABI sceImeGetPanelSize(const OrbisImeParam* param, u32* width, u32* height) {
LOG_INFO(Lib_Ime, "called"); LOG_INFO(Lib_Ime, "sceImeGetPanelSize called");
if (!width || !height) { if (!param) {
return ORBIS_IME_ERROR_INVALID_ADDRESS; LOG_ERROR(Lib_Ime, "Invalid param: NULL");
return Error::INVALID_ADDRESS;
}
if (!width) {
LOG_ERROR(Lib_Ime, "Invalid *width: NULL");
return Error::INVALID_ADDRESS;
}
if (!height) {
LOG_ERROR(Lib_Ime, "Invalid *height: NULL");
return Error::INVALID_ADDRESS;
}
if (static_cast<u32>(param->option) & ~0x7BFF) { // Basic check for invalid options
LOG_ERROR(Lib_Ime, "Invalid option 0x{:X}", static_cast<u32>(param->option));
return Error::INVALID_OPTION;
} }
switch (param->type) { switch (param->type) {
case OrbisImeType::Default: case OrbisImeType::Default:
*width = 500; // dummy value
*height = 100; // dummy value
LOG_DEBUG(Lib_Ime, "param->type: Default ({})", static_cast<u32>(param->type));
break;
case OrbisImeType::BasicLatin: case OrbisImeType::BasicLatin:
*width = 500; // dummy value
*height = 100; // dummy value
LOG_DEBUG(Lib_Ime, "param->type: BasicLatin ({})", static_cast<u32>(param->type));
break;
case OrbisImeType::Url: case OrbisImeType::Url:
*width = 500; // dummy value
*height = 100; // dummy value
LOG_DEBUG(Lib_Ime, "param->type: Url ({})", static_cast<u32>(param->type));
break;
case OrbisImeType::Mail: case OrbisImeType::Mail:
// We set our custom sizes, commented sizes are the original ones // We set our custom sizes, commented sizes are the original ones
*width = 500; // 793 *width = 500; // 793
*height = 100; // 408 *height = 100; // 408
LOG_DEBUG(Lib_Ime, "param->type: Mail ({})", static_cast<u32>(param->type));
break; break;
case OrbisImeType::Number: case OrbisImeType::Number:
*width = 370; *width = 370;
*height = 402; *height = 402;
LOG_DEBUG(Lib_Ime, "param->type: Number ({})", static_cast<u32>(param->type));
break; break;
default:
LOG_ERROR(Lib_Ime, "Invalid param->type: ({})", static_cast<u32>(param->type));
return Error::INVALID_TYPE;
} }
return ORBIS_OK; LOG_INFO(Lib_Ime, "IME panel size: width={}, height={}", *width, *height);
return Error::OK;
} }
s32 PS4_SYSV_ABI sceImeKeyboardClose(s32 userId) { Error PS4_SYSV_ABI sceImeKeyboardClose(Libraries::UserService::OrbisUserServiceUserId userId) {
LOG_INFO(Lib_Ime, "(STUBBED) called"); LOG_INFO(Lib_Ime, "called");
if (!g_keyboard_handler) { if (!g_keyboard_handler) {
return ORBIS_IME_ERROR_NOT_OPENED; LOG_ERROR(Lib_Ime, "No keyboard handler is open");
return Error::NOT_OPENED;
}
if ((userId < 0 || userId > 4) &&
false) { // TODO: Check for valid user IDs. Disabled until user manager is ready.
// Maybe g_keyboard_handler should hold a user ID and I must compare it here?
LOG_ERROR(Lib_Ime, "Invalid userId: {}", userId);
return Error::INVALID_USER_ID;
} }
g_keyboard_handler.release(); g_keyboard_handler.release();
return ORBIS_OK; if (g_ime_handler) {
LOG_ERROR(Lib_Ime, "failed to close keyboard handler, IME handler is still open");
return Error::INTERNAL;
}
LOG_INFO(Lib_Ime, "Keyboard handler closed successfully for user ID: {}", userId);
return Error::OK;
} }
int PS4_SYSV_ABI sceImeKeyboardGetInfo() { int PS4_SYSV_ABI sceImeKeyboardGetInfo() {
@ -268,25 +327,62 @@ int PS4_SYSV_ABI sceImeKeyboardGetResourceId() {
return ORBIS_OK; return ORBIS_OK;
} }
s32 PS4_SYSV_ABI sceImeKeyboardOpen(s32 userId, const OrbisImeKeyboardParam* param) { Error PS4_SYSV_ABI sceImeKeyboardOpen(Libraries::UserService::OrbisUserServiceUserId userId,
const OrbisImeKeyboardParam* param) {
LOG_INFO(Lib_Ime, "called"); LOG_INFO(Lib_Ime, "called");
if (!param) { if (!param) {
return ORBIS_IME_ERROR_INVALID_ADDRESS; LOG_ERROR(Lib_Ime, "Invalid param: NULL");
} return Error::INVALID_ADDRESS;
if (!param->arg) {
return ORBIS_IME_ERROR_INVALID_ARG;
} }
if (!param->handler) { if (!param->handler) {
return ORBIS_IME_ERROR_INVALID_HANDLER; LOG_ERROR(Lib_Ime, "Invalid param->handler: NULL");
return Error::INVALID_HANDLER;
}
// seems like arg is optional, need to check if it is used in the handler
if (!param->arg && false) { // Todo: check if arg is used in the handler, temporarily disabled
LOG_ERROR(Lib_Ime, "Invalid param->arg: NULL");
return Error::INVALID_ARG;
}
if (static_cast<u32>(param->option) & ~kValidOrbisImeKeyboardOptionMask) {
LOG_ERROR(Lib_Ime,
"Invalid param->option\n"
"option: {:032b}\n"
"validMask: {:032b}",
static_cast<u32>(param->option), kValidOrbisImeKeyboardOptionMask);
return Error::INVALID_OPTION;
}
if ((userId < 0 || userId > 4) &&
false) { // TODO: Check for valid user IDs. Disabled until user manager is ready.
LOG_ERROR(Lib_Ime, "Invalid userId: {}", userId);
return Error::INVALID_USER_ID;
}
for (size_t i = 0; i < sizeof(param->reserved1); ++i) {
if (param->reserved1[i] != 0) {
LOG_ERROR(Lib_Ime, "Invalid reserved1: not zeroed");
return Error::INVALID_RESERVED;
}
}
for (size_t i = 0; i < sizeof(param->reserved2); ++i) {
if (param->reserved2[i] != 0) {
LOG_ERROR(Lib_Ime, "Invalid reserved2: not zeroed");
return Error::INVALID_RESERVED;
}
}
if (false) { // Todo: figure out what it is, always true for now
LOG_ERROR(Lib_Ime, "USB keyboard some special kind of failure");
return Error::CONNECTION_FAILED;
} }
if (g_keyboard_handler) { if (g_keyboard_handler) {
return ORBIS_IME_ERROR_BUSY; LOG_ERROR(Lib_Ime, "Keyboard handler is already open");
return Error::BUSY;
} }
g_keyboard_handler = std::make_unique<ImeHandler>(param); g_keyboard_handler = std::make_unique<ImeHandler>(param);
return ORBIS_OK; if (!g_keyboard_handler) {
LOG_ERROR(Lib_Ime, "Failed to create keyboard handler");
return Error::INTERNAL; // or Error::NO_MEMORY;
}
LOG_INFO(Lib_Ime, "Keyboard handler created successfully for user ID: {}", userId);
return Error::OK;
} }
int PS4_SYSV_ABI sceImeKeyboardOpenInternal() { int PS4_SYSV_ABI sceImeKeyboardOpenInternal() {
@ -304,18 +400,190 @@ int PS4_SYSV_ABI sceImeKeyboardUpdate() {
return ORBIS_OK; return ORBIS_OK;
} }
s32 PS4_SYSV_ABI sceImeOpen(const OrbisImeParam* param, const void* extended) { Error PS4_SYSV_ABI sceImeOpen(const OrbisImeParam* param, const OrbisImeParamExtended* extended) {
LOG_INFO(Lib_Ime, "called"); LOG_INFO(Lib_Ime, "called");
if (!param) { if (!param) {
return ORBIS_IME_ERROR_INVALID_ADDRESS; LOG_ERROR(Lib_Ime, "Invalid param: NULL");
return Error::INVALID_ADDRESS;
} else {
// LOG_DEBUG values for debugging purposes
LOG_DEBUG(Lib_Ime, "param->user_id: {}", param->user_id);
LOG_DEBUG(Lib_Ime, "param->type: {}", static_cast<u32>(param->type));
LOG_DEBUG(Lib_Ime, "param->supported_languages: {:064b}",
static_cast<u64>(param->supported_languages));
LOG_DEBUG(Lib_Ime, "param->enter_label: {}", static_cast<u32>(param->enter_label));
LOG_DEBUG(Lib_Ime, "param->input_method: {}", static_cast<u32>(param->input_method));
LOG_DEBUG(Lib_Ime, "param->filter: {:p}", reinterpret_cast<void*>(param->filter));
LOG_DEBUG(Lib_Ime, "param->option: {:032b}", static_cast<u32>(param->option));
LOG_DEBUG(Lib_Ime, "param->maxTextLength: {}", param->maxTextLength);
LOG_DEBUG(Lib_Ime, "param->inputTextBuffer: {:p}",
static_cast<const void*>(param->inputTextBuffer));
LOG_DEBUG(Lib_Ime, "param->posx: {}", param->posx);
LOG_DEBUG(Lib_Ime, "param->posy: {}", param->posy);
LOG_DEBUG(Lib_Ime, "param->horizontal_alignment: {}",
static_cast<u32>(param->horizontal_alignment));
LOG_DEBUG(Lib_Ime, "param->vertical_alignment: {}",
static_cast<u32>(param->vertical_alignment));
LOG_DEBUG(Lib_Ime, "param->work: {:p}", param->work);
LOG_DEBUG(Lib_Ime, "param->arg: {:p}", param->arg);
LOG_DEBUG(Lib_Ime, "param->handler: {:p}", reinterpret_cast<void*>(param->handler));
} }
if (!extended) {
LOG_INFO(Lib_Ime, "Not used extended: NULL");
} else {
LOG_DEBUG(Lib_Ime, "extended->option: {:032b}", static_cast<u32>(extended->option));
LOG_DEBUG(Lib_Ime, "extended->color_base: {{{},{},{},{}}}", extended->color_base.r,
extended->color_base.g, extended->color_base.b, extended->color_base.a);
LOG_DEBUG(Lib_Ime, "extended->color_line: {{{},{},{},{}}}", extended->color_line.r,
extended->color_line.g, extended->color_line.b, extended->color_line.a);
LOG_DEBUG(Lib_Ime, "extended->color_text_field: {{{},{},{},{}}}",
extended->color_text_field.r, extended->color_text_field.g,
extended->color_text_field.b, extended->color_text_field.a);
LOG_DEBUG(Lib_Ime, "extended->color_preedit: {{{},{},{},{}}}", extended->color_preedit.r,
extended->color_preedit.g, extended->color_preedit.b, extended->color_preedit.a);
LOG_DEBUG(Lib_Ime, "extended->color_button_default: {{{},{},{},{}}}",
extended->color_button_default.r, extended->color_button_default.g,
extended->color_button_default.b, extended->color_button_default.a);
LOG_DEBUG(Lib_Ime, "extended->color_button_function: {{{},{},{},{}}}",
extended->color_button_function.r, extended->color_button_function.g,
extended->color_button_function.b, extended->color_button_function.a);
LOG_DEBUG(Lib_Ime, "extended->color_button_symbol: {{{},{},{},{}}}",
extended->color_button_symbol.r, extended->color_button_symbol.g,
extended->color_button_symbol.b, extended->color_button_symbol.a);
LOG_DEBUG(Lib_Ime, "extended->color_text: {{{},{},{},{}}}", extended->color_text.r,
extended->color_text.g, extended->color_text.b, extended->color_text.a);
LOG_DEBUG(Lib_Ime, "extended->color_special: {{{},{},{},{}}}", extended->color_special.r,
extended->color_special.g, extended->color_special.b, extended->color_special.a);
LOG_DEBUG(Lib_Ime, "extended->priority: {}", static_cast<u32>(extended->priority));
LOG_DEBUG(Lib_Ime, "extended->additional_dictionary_path: {:p}",
static_cast<const void*>(extended->additional_dictionary_path));
LOG_DEBUG(Lib_Ime, "extended->ext_keyboard_filter: {:p}",
reinterpret_cast<void*>(extended->ext_keyboard_filter));
LOG_DEBUG(Lib_Ime, "extended->disable_device: {:032b}",
static_cast<u32>(extended->disable_device));
LOG_DEBUG(Lib_Ime, "extended->ext_keyboard_mode: {}", extended->ext_keyboard_mode);
}
if (param->user_id < 1 || param->user_id > 4) { // Todo: check valid user IDs
LOG_ERROR(Lib_Ime, "Invalid user_id: {}", static_cast<u32>(param->user_id));
return Error::INVALID_USER_ID;
}
if (!magic_enum::enum_contains(param->type)) {
LOG_ERROR(Lib_Ime, "Invalid type: {}", static_cast<u32>(param->type));
return Error::INVALID_TYPE;
}
if (static_cast<u64>(param->supported_languages) & ~kValidOrbisImeLanguageMask) {
LOG_ERROR(Lib_Ime,
"Invalid supported_languages\n"
"supported_languages: {:064b}\n"
"valid_mask: {:064b}",
static_cast<u64>(param->supported_languages), kValidOrbisImeLanguageMask);
return Error::INVALID_SUPPORTED_LANGUAGES;
}
if (!magic_enum::enum_contains(param->enter_label)) {
LOG_ERROR(Lib_Ime, "Invalid enter_label: {}", static_cast<u32>(param->enter_label));
return Error::INVALID_ENTER_LABEL;
}
if (!magic_enum::enum_contains(param->input_method)) {
LOG_ERROR(Lib_Ime, "Invalid input_method: {}", static_cast<u32>(param->input_method));
return Error::INVALID_INPUT_METHOD;
}
if (static_cast<u32>(param->option) & ~kValidImeOptionMask) {
LOG_ERROR(Lib_Ime, "option has invalid bits set (0x{:X}), mask=(0x{:X})",
static_cast<u32>(param->option), kValidImeOptionMask);
return Error::INVALID_OPTION;
}
if (param->maxTextLength == 0 || param->maxTextLength > ORBIS_IME_DIALOG_MAX_TEXT_LENGTH) {
LOG_ERROR(Lib_Ime, "Invalid maxTextLength: {}", param->maxTextLength);
return Error::INVALID_MAX_TEXT_LENGTH;
}
if (!param->inputTextBuffer) {
LOG_ERROR(Lib_Ime, "Invalid inputTextBuffer: NULL");
return Error::INVALID_INPUT_TEXT_BUFFER;
}
bool useHighRes = True(param->option & OrbisImeOption::USE_OVER_2K_COORDINATES);
const float maxWidth = useHighRes ? 3840.0f : 1920.0f;
const float maxHeight = useHighRes ? 2160.0f : 1080.0f;
if (param->posx < 0.0f || param->posx >= maxWidth) {
LOG_ERROR(Lib_Ime, "Invalid posx: {}, range: 0.0 - {}", param->posx, maxWidth);
return Error::INVALID_POSX;
}
if (param->posy < 0.0f || param->posy >= maxHeight) {
LOG_ERROR(Lib_Ime, "Invalid posy: {}, range: 0.0 - {}", param->posy, maxHeight);
return Error::INVALID_POSY;
}
if (!magic_enum::enum_contains(param->horizontal_alignment)) {
LOG_ERROR(Lib_Ime, "Invalid horizontal_alignment: {}",
static_cast<u32>(param->horizontal_alignment));
return Error::INVALID_HORIZONTALIGNMENT;
}
if (!magic_enum::enum_contains(param->vertical_alignment)) {
LOG_ERROR(Lib_Ime, "Invalid vertical_alignment: {}",
static_cast<u32>(param->vertical_alignment));
return Error::INVALID_VERTICALALIGNMENT;
}
if (extended) {
u32 ext_option_value = static_cast<u32>(extended->option);
if (ext_option_value & ~kValidImeExtOptionMask) {
LOG_ERROR(Lib_Ime,
"Invalid extended->option\n"
"option: {:032b}\n"
"valid_mask: {:032b}",
ext_option_value, kValidImeExtOptionMask);
return Error::INVALID_EXTENDED;
}
}
if (!param->work) {
LOG_ERROR(Lib_Ime, "Invalid work: NULL");
return Error::INVALID_WORK;
}
// Todo: validate arg
if (false) {
LOG_ERROR(Lib_Ime, "Invalid arg: NULL");
return Error::INVALID_ARG;
}
// Todo: validate handler
if (false) {
LOG_ERROR(Lib_Ime, "Invalid handler: NULL");
return Error::INVALID_HANDLER;
}
for (size_t i = 0; i < sizeof(param->reserved); ++i) {
if (param->reserved[i] != 0) {
LOG_ERROR(Lib_Ime, "Invalid reserved: not zeroed");
return Error::INVALID_RESERVED;
}
}
if (g_ime_handler) { if (g_ime_handler) {
return ORBIS_IME_ERROR_BUSY; LOG_ERROR(Lib_Ime, "IME handler is already open");
return Error::BUSY;
} }
g_ime_handler = std::make_unique<ImeHandler>(param); g_ime_handler = std::make_unique<ImeHandler>(param);
return ORBIS_OK; if (!g_ime_handler) {
LOG_ERROR(Lib_Ime, "Failed to create IME handler");
return Error::NO_MEMORY; // or Error::INTERNAL
}
LOG_INFO(Lib_Ime, "IME handler created successfully");
return Error::OK;
} }
int PS4_SYSV_ABI sceImeOpenInternal() { int PS4_SYSV_ABI sceImeOpenInternal() {
@ -324,7 +592,7 @@ int PS4_SYSV_ABI sceImeOpenInternal() {
} }
void PS4_SYSV_ABI sceImeParamInit(OrbisImeParam* param) { void PS4_SYSV_ABI sceImeParamInit(OrbisImeParam* param) {
LOG_INFO(Lib_Ime, "called"); LOG_INFO(Lib_Ime, "sceImeParamInit called");
if (!param) { if (!param) {
return; return;
@ -339,27 +607,27 @@ int PS4_SYSV_ABI sceImeSetCandidateIndex() {
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceImeSetCaret(const OrbisImeCaret* caret) { Error PS4_SYSV_ABI sceImeSetCaret(const OrbisImeCaret* caret) {
LOG_TRACE(Lib_Ime, "called"); LOG_TRACE(Lib_Ime, "called");
if (!g_ime_handler) { if (!g_ime_handler) {
return ORBIS_IME_ERROR_NOT_OPENED; return Error::NOT_OPENED;
} }
if (!caret) { if (!caret) {
return ORBIS_IME_ERROR_INVALID_ADDRESS; return Error::INVALID_ADDRESS;
} }
return g_ime_handler->SetCaret(caret); return g_ime_handler->SetCaret(caret);
} }
s32 PS4_SYSV_ABI sceImeSetText(const char16_t* text, u32 length) { Error PS4_SYSV_ABI sceImeSetText(const char16_t* text, u32 length) {
LOG_TRACE(Lib_Ime, "called"); LOG_TRACE(Lib_Ime, "called");
if (!g_ime_handler) { if (!g_ime_handler) {
return ORBIS_IME_ERROR_NOT_OPENED; return Error::NOT_OPENED;
} }
if (!text) { if (!text) {
return ORBIS_IME_ERROR_INVALID_ADDRESS; return Error::INVALID_ADDRESS;
} }
return g_ime_handler->SetText(text, length); return g_ime_handler->SetText(text, length);
@ -370,7 +638,7 @@ int PS4_SYSV_ABI sceImeSetTextGeometry() {
return ORBIS_OK; return ORBIS_OK;
} }
s32 PS4_SYSV_ABI sceImeUpdate(OrbisImeEventHandler handler) { Error PS4_SYSV_ABI sceImeUpdate(OrbisImeEventHandler handler) {
if (g_ime_handler) { if (g_ime_handler) {
g_ime_handler->Update(handler); g_ime_handler->Update(handler);
} }
@ -380,10 +648,10 @@ s32 PS4_SYSV_ABI sceImeUpdate(OrbisImeEventHandler handler) {
} }
if (!g_ime_handler || !g_keyboard_handler) { if (!g_ime_handler || !g_keyboard_handler) {
return ORBIS_IME_ERROR_NOT_OPENED; return Error::NOT_OPENED;
} }
return ORBIS_OK; return Error::OK;
} }
int PS4_SYSV_ABI sceImeVshClearPreedit() { int PS4_SYSV_ABI sceImeVshClearPreedit() {
@ -481,7 +749,7 @@ int PS4_SYSV_ABI sceImeVshUpdateContext2() {
return ORBIS_OK; return ORBIS_OK;
} }
void RegisterlibSceIme(Core::Loader::SymbolsResolver* sym) { void RegisterLib(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("mN+ZoSN-8hQ", "libSceIme", 1, "libSceIme", 1, 1, FinalizeImeModule); LIB_FUNCTION("mN+ZoSN-8hQ", "libSceIme", 1, "libSceIme", 1, 1, FinalizeImeModule);
LIB_FUNCTION("uTW+63goeJs", "libSceIme", 1, "libSceIme", 1, 1, InitializeImeModule); LIB_FUNCTION("uTW+63goeJs", "libSceIme", 1, "libSceIme", 1, 1, InitializeImeModule);
LIB_FUNCTION("Lf3DeGWC6xg", "libSceIme", 1, "libSceIme", 1, 1, sceImeCheckFilterText); LIB_FUNCTION("Lf3DeGWC6xg", "libSceIme", 1, "libSceIme", 1, 1, sceImeCheckFilterText);

View File

@ -13,78 +13,12 @@ class SymbolsResolver;
namespace Libraries::Ime { namespace Libraries::Ime {
constexpr u32 ORBIS_IME_MAX_TEXT_LENGTH = 2048;
enum class OrbisImeKeyboardOption : u32 {
Default = 0,
Repeat = 1,
RepeatEachKey = 2,
AddOsk = 4,
EffectiveWithIme = 8,
DisableResume = 16,
DisableCapslockWithoutShift = 32,
};
DECLARE_ENUM_FLAG_OPERATORS(OrbisImeKeyboardOption)
enum class OrbisImeOption : u32 {
DEFAULT = 0,
MULTILINE = 1,
NO_AUTO_CAPITALIZATION = 2,
PASSWORD = 4,
LANGUAGES_FORCED = 8,
EXT_KEYBOARD = 16,
NO_LEARNING = 32,
FIXED_POSITION = 64,
DISABLE_RESUME = 256,
DISABLE_AUTO_SPACE = 512,
DISABLE_POSITION_ADJUSTMENT = 2048,
EXPANDED_PREEDIT_BUFFER = 4096,
USE_JAPANESE_EISUU_KEY_AS_CAPSLOCK = 8192,
USE_2K_COORDINATES = 16384,
};
DECLARE_ENUM_FLAG_OPERATORS(OrbisImeOption)
struct OrbisImeKeyboardParam {
OrbisImeKeyboardOption option;
s8 reserved1[4];
void* arg;
OrbisImeEventHandler handler;
s8 reserved2[8];
};
struct OrbisImeParam {
s32 user_id;
OrbisImeType type;
u64 supported_languages;
OrbisImeEnterLabel enter_label;
OrbisImeInputMethod input_method;
OrbisImeTextFilter filter;
OrbisImeOption option;
u32 maxTextLength;
char16_t* inputTextBuffer;
float posx;
float posy;
OrbisImeHorizontalAlignment horizontal_alignment;
OrbisImeVerticalAlignment vertical_alignment;
void* work;
void* arg;
OrbisImeEventHandler handler;
s8 reserved[8];
};
struct OrbisImeCaret {
f32 x;
f32 y;
u32 height;
u32 index;
};
int PS4_SYSV_ABI FinalizeImeModule(); int PS4_SYSV_ABI FinalizeImeModule();
int PS4_SYSV_ABI InitializeImeModule(); int PS4_SYSV_ABI InitializeImeModule();
int PS4_SYSV_ABI sceImeCheckFilterText(); int PS4_SYSV_ABI sceImeCheckFilterText();
int PS4_SYSV_ABI sceImeCheckRemoteEventParam(); int PS4_SYSV_ABI sceImeCheckRemoteEventParam();
int PS4_SYSV_ABI sceImeCheckUpdateTextInfo(); int PS4_SYSV_ABI sceImeCheckUpdateTextInfo();
int PS4_SYSV_ABI sceImeClose(); Error PS4_SYSV_ABI sceImeClose();
int PS4_SYSV_ABI sceImeConfigGet(); int PS4_SYSV_ABI sceImeConfigGet();
int PS4_SYSV_ABI sceImeConfigSet(); int PS4_SYSV_ABI sceImeConfigSet();
int PS4_SYSV_ABI sceImeConfirmCandidate(); int PS4_SYSV_ABI sceImeConfirmCandidate();
@ -98,22 +32,23 @@ int PS4_SYSV_ABI sceImeDisableController();
int PS4_SYSV_ABI sceImeFilterText(); int PS4_SYSV_ABI sceImeFilterText();
int PS4_SYSV_ABI sceImeForTestFunction(); int PS4_SYSV_ABI sceImeForTestFunction();
int PS4_SYSV_ABI sceImeGetPanelPositionAndForm(); int PS4_SYSV_ABI sceImeGetPanelPositionAndForm();
s32 PS4_SYSV_ABI sceImeGetPanelSize(const OrbisImeParam* param, u32* width, u32* height); Error PS4_SYSV_ABI sceImeGetPanelSize(const OrbisImeParam* param, u32* width, u32* height);
s32 PS4_SYSV_ABI sceImeKeyboardClose(s32 userId); Error PS4_SYSV_ABI sceImeKeyboardClose(Libraries::UserService::OrbisUserServiceUserId userId);
int PS4_SYSV_ABI sceImeKeyboardGetInfo(); int PS4_SYSV_ABI sceImeKeyboardGetInfo();
int PS4_SYSV_ABI sceImeKeyboardGetResourceId(); int PS4_SYSV_ABI sceImeKeyboardGetResourceId();
s32 PS4_SYSV_ABI sceImeKeyboardOpen(s32 userId, const OrbisImeKeyboardParam* param); Error PS4_SYSV_ABI sceImeKeyboardOpen(Libraries::UserService::OrbisUserServiceUserId userId,
const OrbisImeKeyboardParam* param);
int PS4_SYSV_ABI sceImeKeyboardOpenInternal(); int PS4_SYSV_ABI sceImeKeyboardOpenInternal();
int PS4_SYSV_ABI sceImeKeyboardSetMode(); int PS4_SYSV_ABI sceImeKeyboardSetMode();
int PS4_SYSV_ABI sceImeKeyboardUpdate(); int PS4_SYSV_ABI sceImeKeyboardUpdate();
s32 PS4_SYSV_ABI sceImeOpen(const OrbisImeParam* param, const void* extended); Error PS4_SYSV_ABI sceImeOpen(const OrbisImeParam* param, const OrbisImeParamExtended* extended);
int PS4_SYSV_ABI sceImeOpenInternal(); int PS4_SYSV_ABI sceImeOpenInternal();
void PS4_SYSV_ABI sceImeParamInit(OrbisImeParam* param); void PS4_SYSV_ABI sceImeParamInit(OrbisImeParam* param);
int PS4_SYSV_ABI sceImeSetCandidateIndex(); int PS4_SYSV_ABI sceImeSetCandidateIndex();
s32 PS4_SYSV_ABI sceImeSetCaret(const OrbisImeCaret* caret); Error PS4_SYSV_ABI sceImeSetCaret(const OrbisImeCaret* caret);
s32 PS4_SYSV_ABI sceImeSetText(const char16_t* text, u32 length); Error PS4_SYSV_ABI sceImeSetText(const char16_t* text, u32 length);
int PS4_SYSV_ABI sceImeSetTextGeometry(); int PS4_SYSV_ABI sceImeSetTextGeometry();
s32 PS4_SYSV_ABI sceImeUpdate(OrbisImeEventHandler handler); Error PS4_SYSV_ABI sceImeUpdate(OrbisImeEventHandler handler);
int PS4_SYSV_ABI sceImeVshClearPreedit(); int PS4_SYSV_ABI sceImeVshClearPreedit();
int PS4_SYSV_ABI sceImeVshClose(); int PS4_SYSV_ABI sceImeVshClose();
int PS4_SYSV_ABI sceImeVshConfirmPreedit(); int PS4_SYSV_ABI sceImeVshConfirmPreedit();
@ -134,6 +69,6 @@ int PS4_SYSV_ABI sceImeVshUpdate();
int PS4_SYSV_ABI sceImeVshUpdateContext(); int PS4_SYSV_ABI sceImeVshUpdateContext();
int PS4_SYSV_ABI sceImeVshUpdateContext2(); int PS4_SYSV_ABI sceImeVshUpdateContext2();
void RegisterlibSceIme(Core::Loader::SymbolsResolver* sym); void RegisterLib(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::Ime } // namespace Libraries::Ime

View File

@ -3,9 +3,273 @@
#pragma once #pragma once
#include <core/libraries/system/userservice.h>
#include <magic_enum/magic_enum.hpp>
#include "common/enum.h"
#include "common/types.h" #include "common/types.h"
#include "core/libraries/rtc/rtc.h" #include "core/libraries/rtc/rtc.h"
constexpr u32 ORBIS_IME_MAX_TEXT_LENGTH = 2048;
constexpr u32 ORBIS_IME_DIALOG_MAX_TEXT_LENGTH = 2048;
template <typename E>
const std::underlying_type_t<E> generate_full_mask() {
static_assert(std::is_enum_v<E>, "E must be an enum type.");
static_assert(magic_enum::customize::enum_range<E>::is_flags,
"E must be marked as is_flags = true.");
using U = std::underlying_type_t<E>;
const auto values = magic_enum::enum_values<E>();
U mask = 0;
// Use index-based loop for better constexpr compatibility
for (std::size_t i = 0; i < values.size(); ++i) {
mask |= static_cast<U>(values[i]);
}
return mask;
}
enum class Error : u32 {
OK = 0x0,
// ImeDialog library
BUSY = 0x80bc0001,
NOT_OPENED = 0x80bc0002,
NO_MEMORY = 0x80bc0003,
CONNECTION_FAILED = 0x80bc0004,
TOO_MANY_REQUESTS = 0x80bc0005,
INVALID_TEXT = 0x80bc0006,
EVENT_OVERFLOW = 0x80bc0007,
NOT_ACTIVE = 0x80bc0008,
IME_SUSPENDING = 0x80bc0009,
DEVICE_IN_USE = 0x80bc000a,
INVALID_USER_ID = 0x80bc0010,
INVALID_TYPE = 0x80bc0011,
INVALID_SUPPORTED_LANGUAGES = 0x80bc0012,
INVALID_ENTER_LABEL = 0x80bc0013,
INVALID_INPUT_METHOD = 0x80bc0014,
INVALID_OPTION = 0x80bc0015,
INVALID_MAX_TEXT_LENGTH = 0x80bc0016,
INVALID_INPUT_TEXT_BUFFER = 0x80bc0017,
INVALID_POSX = 0x80bc0018,
INVALID_POSY = 0x80bc0019,
INVALID_HORIZONTALIGNMENT = 0x80bc001a,
INVALID_VERTICALALIGNMENT = 0x80bc001b,
INVALID_EXTENDED = 0x80bc001c,
INVALID_KEYBOARD_TYPE = 0x80bc001d,
INVALID_WORK = 0x80bc0020,
INVALID_ARG = 0x80bc0021,
INVALID_HANDLER = 0x80bc0022,
NO_RESOURCE_ID = 0x80bc0023,
INVALID_MODE = 0x80bc0024,
INVALID_PARAM = 0x80bc0030,
INVALID_ADDRESS = 0x80bc0031,
INVALID_RESERVED = 0x80bc0032,
INVALID_TIMING = 0x80bc0033,
INTERNAL = 0x80bc00ff,
// Ime library
DIALOG_INVALID_TITLE = 0x80bc0101,
DIALOG_NOT_RUNNING = 0x80bc0105,
DIALOG_NOT_FINISHED = 0x80bc0106,
DIALOG_NOT_IN_USE = 0x80bc0107
};
enum class OrbisImeOption : u32 {
DEFAULT = 0,
MULTILINE = 1,
NO_AUTO_CAPITALIZATION = 2,
PASSWORD = 4,
LANGUAGES_FORCED = 8,
EXT_KEYBOARD = 16,
NO_LEARNING = 32,
FIXED_POSITION = 64,
DISABLE_COPY_PASTE = 128,
DISABLE_RESUME = 256,
DISABLE_AUTO_SPACE = 512,
DISABLE_POSITION_ADJUSTMENT = 2048,
EXPANDED_PREEDIT_BUFFER = 4096,
USE_JAPANESE_EISUU_KEY_AS_CAPSLOCK = 8192,
USE_OVER_2K_COORDINATES = 16384,
};
DECLARE_ENUM_FLAG_OPERATORS(OrbisImeOption);
template <>
struct magic_enum::customize::enum_range<OrbisImeOption> {
static constexpr bool is_flags = true;
};
const u32 kValidImeOptionMask = generate_full_mask<OrbisImeOption>();
enum class OrbisImeExtOption : u32 {
DEFAULT = 0x00000000,
SET_PRIORITY = 0x00000002,
PRIORITY_FULL_WIDTH = 0x00000008,
PRIORITY_FIXED_PANEL = 0x00000010,
DISABLE_POINTER = 0x00000040,
ENABLE_ADDITIONAL_DICTIONARY = 0x00000080,
DISABLE_STARTUP_SE = 0x00000100,
DISABLE_LIST_FOR_EXT_KEYBOARD = 0x00000200,
HIDE_KEYPANEL_IF_EXT_KEYBOARD = 0x00000400,
INIT_EXT_KEYBOARD_MODE = 0x00000800,
ENABLE_ACCESSIBILITY = 0x00001000, // ImeDialog unly
ADDITIONAL_DICTIONARY_PRIORITY_MODE = 0x00004000, // ImeDialog only
};
DECLARE_ENUM_FLAG_OPERATORS(OrbisImeExtOption);
constexpr u32 kValidImeExtOptionMask = static_cast<u32>(
OrbisImeExtOption::SET_PRIORITY | OrbisImeExtOption::PRIORITY_FULL_WIDTH |
OrbisImeExtOption::PRIORITY_FIXED_PANEL | OrbisImeExtOption::DISABLE_POINTER |
OrbisImeExtOption::ENABLE_ADDITIONAL_DICTIONARY | OrbisImeExtOption::DISABLE_STARTUP_SE |
OrbisImeExtOption::DISABLE_LIST_FOR_EXT_KEYBOARD |
OrbisImeExtOption::HIDE_KEYPANEL_IF_EXT_KEYBOARD | OrbisImeExtOption::INIT_EXT_KEYBOARD_MODE);
template <>
struct magic_enum::customize::enum_range<OrbisImeExtOption> {
static constexpr bool is_flags = true;
};
const u32 kValidImeDialogExtOptionMask = generate_full_mask<OrbisImeExtOption>();
enum class OrbisImeLanguage : u64 {
DANISH = 0x0000000000000001,
GERMAN = 0x0000000000000002,
ENGLISH_US = 0x0000000000000004,
SPANISH = 0x0000000000000008,
FRENCH = 0x0000000000000010,
ITALIAN = 0x0000000000000020,
DUTCH = 0x0000000000000040,
NORWEGIAN = 0x0000000000000080,
POLISH = 0x0000000000000100,
PORTUGUESE_PT = 0x0000000000000200,
RUSSIAN = 0x0000000000000400,
FINNISH = 0x0000000000000800,
SWEDISH = 0x0000000000001000,
JAPANESE = 0x0000000000002000,
KOREAN = 0x0000000000004000,
SIMPLIFIED_CHINESE = 0x0000000000008000,
TRADITIONAL_CHINESE = 0x0000000000010000,
PORTUGUESE_BR = 0x0000000000020000,
ENGLISH_GB = 0x0000000000040000,
TURKISH = 0x0000000000080000,
SPANISH_LA = 0x0000000000100000,
ARABIC = 0x0000000001000000,
FRENCH_CA = 0x0000000002000000,
THAI = 0x0000000004000000,
CZECH = 0x0000000008000000,
GREEK = 0x0000000010000000,
INDONESIAN = 0x0000000020000000,
VIETNAMESE = 0x0000000040000000,
ROMANIAN = 0x0000000080000000,
HUNGARIAN = 0x0000000100000000,
};
DECLARE_ENUM_FLAG_OPERATORS(OrbisImeLanguage);
template <>
struct magic_enum::customize::enum_range<OrbisImeLanguage> {
static constexpr bool is_flags = true;
};
const u64 kValidOrbisImeLanguageMask = generate_full_mask<OrbisImeLanguage>();
enum class OrbisImeDisableDevice : u32 {
DEFAULT = 0x00000000,
CONTROLLER = 0x00000001,
EXT_KEYBOARD = 0x00000002,
REMOTE_OSK = 0x00000004,
};
DECLARE_ENUM_FLAG_OPERATORS(OrbisImeDisableDevice);
template <>
struct magic_enum::customize::enum_range<OrbisImeDisableDevice> {
static constexpr bool is_flags = true;
};
const u32 kValidOrbisImeDisableDeviceMask = generate_full_mask<OrbisImeDisableDevice>();
enum class OrbisImeInputMethodState : u32 {
PREEDIT = 0x01000000,
SELECTED = 0x02000000,
NATIVE = 0x04000000,
NATIVE2 = 0x08000000,
FULL_WIDTH = 0x10000000,
};
DECLARE_ENUM_FLAG_OPERATORS(OrbisImeInputMethodState);
template <>
struct magic_enum::customize::enum_range<OrbisImeInputMethodState> {
static constexpr bool is_flags = true;
};
const u32 kValidOrbisImeInputMethodStateMask = generate_full_mask<OrbisImeInputMethodState>();
enum class OrbisImeInitExtKeyboardMode : u32 {
ISABLE_ARABIC_INDIC_NUMERALS = 0x00000001,
ENABLE_FORMAT_CHARACTERS = 0x00000002,
INPUT_METHOD_STATE_NATIVE = 0x04000000,
INPUT_METHOD_STATE_NATIVE2 = 0x08000000,
INPUT_METHOD_STATE_FULL_WIDTH = 0x10000000,
};
DECLARE_ENUM_FLAG_OPERATORS(OrbisImeInitExtKeyboardMode);
template <>
struct magic_enum::customize::enum_range<OrbisImeInitExtKeyboardMode> {
static constexpr bool is_flags = true;
};
const u32 kValidOrbisImeInitExtKeyboardModeMask = generate_full_mask<OrbisImeInitExtKeyboardMode>();
enum class OrbisImeKeycodeState : u32 {
KEYCODE_VALID = 0x00000001,
CHARACTER_VALID = 0x00000002,
WITH_IME = 0x00000004,
FROM_OSK = 0x00000008,
FROM_OSK_SHORTCUT = 0x00000010,
FROM_IME_OPERATION = 0x00000020,
REPLACE_CHARACTER = 0x00000040,
CONTINUOUS_EVENT = 0x00000080,
MODIFIER_L_CTRL = 0x00000100,
MODIFIER_L_SHIFT = 0x00000200,
MODIFIER_L_ALT = 0x00000400,
MODIFIER_L_GUI = 0x00000800,
MODIFIER_R_CTRL = 0x00001000,
MODIFIER_R_SHIFT = 0x00002000,
MODIFIER_R_ALT = 0x00004000,
MODIFIER_R_GUI = 0x00008000,
LED_NUM_LOCK = 0x00010000,
LED_CAPS_LOCK = 0x00020000,
LED_SCROLL_LOCK = 0x00040000,
RESERVED1 = 0x00080000,
RESERVED2 = 0x00100000,
FROM_IME_INPUT = 0x00200000,
};
DECLARE_ENUM_FLAG_OPERATORS(OrbisImeKeycodeState);
template <>
struct magic_enum::customize::enum_range<OrbisImeKeycodeState> {
static constexpr bool is_flags = true;
};
const u32 kValidOrbisImeKeycodeStateMask = generate_full_mask<OrbisImeKeycodeState>();
enum class OrbisImeKeyboardOption : u32 {
Default = 0,
Repeat = 1,
RepeatEachKey = 2,
AddOsk = 4,
EffectiveWithIme = 8,
DisableResume = 16,
DisableCapslockWithoutShift = 32,
};
DECLARE_ENUM_FLAG_OPERATORS(OrbisImeKeyboardOption)
template <>
struct magic_enum::customize::enum_range<OrbisImeKeyboardOption> {
static constexpr bool is_flags = true;
};
const u32 kValidOrbisImeKeyboardOptionMask = generate_full_mask<OrbisImeKeyboardOption>();
enum class OrbisImeKeyboardMode : u32 {
Auto = 0,
Manual = 1,
Alphabet = 0,
Native = 2,
Part = 4,
Katakana = 8,
Hkana = 16,
ArabicIndicNumerals = 32,
DisableFormatCharacters = 64,
};
enum class OrbisImeType : u32 { enum class OrbisImeType : u32 {
Default = 0, Default = 0,
BasicLatin = 1, BasicLatin = 1,
@ -41,6 +305,7 @@ enum class OrbisImeEventId : u32 {
Open = 0, Open = 0,
UpdateText = 1, UpdateText = 1,
UpdateCaret = 2, UpdateCaret = 2,
ChangeSize = 3,
PressClose = 4, PressClose = 4,
PressEnter = 5, PressEnter = 5,
Abort = 6, Abort = 6,
@ -51,10 +316,14 @@ enum class OrbisImeEventId : u32 {
CandidateDone = 11, CandidateDone = 11,
CandidateCancel = 12, CandidateCancel = 12,
ChangeDevice = 14, ChangeDevice = 14,
JumpToNextObject = 15,
JumpToBeforeObject = 16,
ChangeWindowType = 17,
ChangeInputMethodState = 18, ChangeInputMethodState = 18,
KeyboardOpen = 256, KeyboardOpen = 256,
KeyboardKeycodeDoen = 257, KeyboardKeycodeDown = 257,
KeyboardKeycodeUp = 258, KeyboardKeycodeUp = 258,
KeyboardKeycodeRepeat = 259, KeyboardKeycodeRepeat = 259,
KeyboardConnection = 260, KeyboardConnection = 260,
@ -110,6 +379,13 @@ enum class OrbisImeDeviceType : u32 {
RemoteOsk = 3, RemoteOsk = 3,
}; };
enum class OrbisImePanelPriority : u32 {
Default = 0,
Alphabet = 1,
Symbol = 2,
Accent = 3,
};
struct OrbisImeRect { struct OrbisImeRect {
f32 x; f32 x;
f32 y; f32 y;
@ -117,8 +393,22 @@ struct OrbisImeRect {
u32 height; u32 height;
}; };
struct OrbisImeColor {
u8 r;
u8 g;
u8 b;
u8 a;
};
enum class OrbisImeTextAreaMode : u32 {
Disable = 0,
Edit = 1,
Preedit = 2,
Select = 3,
};
struct OrbisImeTextAreaProperty { struct OrbisImeTextAreaProperty {
u32 mode; // OrbisImeTextAreaMode OrbisImeTextAreaMode mode;
u32 index; u32 index;
s32 length; s32 length;
}; };
@ -135,14 +425,14 @@ struct OrbisImeKeycode {
char16_t character; char16_t character;
u32 status; u32 status;
OrbisImeKeyboardType type; OrbisImeKeyboardType type;
s32 user_id; Libraries::UserService::OrbisUserServiceUserId user_id;
u32 resource_id; u32 resource_id;
Libraries::Rtc::OrbisRtcTick timestamp; Libraries::Rtc::OrbisRtcTick timestamp;
}; };
struct OrbisImeKeyboardResourceIdArray { struct OrbisImeKeyboardResourceIdArray {
s32 userId; Libraries::UserService::OrbisUserServiceUserId user_id;
u32 resourceId[5]; u32 resource_id[5];
}; };
enum class OrbisImeCaretMovementDirection : u32 { enum class OrbisImeCaretMovementDirection : u32 {
@ -159,6 +449,16 @@ enum class OrbisImeCaretMovementDirection : u32 {
Bottom = 10, Bottom = 10,
}; };
enum class OrbisImePanelType : u32 {
Hide = 0,
Osk = 1,
Dialog = 2,
Candidate = 3,
Edit = 4,
EditAndCandidate = 5,
Accessibility = 6,
};
union OrbisImeEventParam { union OrbisImeEventParam {
OrbisImeRect rect; OrbisImeRect rect;
OrbisImeEditText text; OrbisImeEditText text;
@ -168,6 +468,7 @@ union OrbisImeEventParam {
char16_t* candidate_word; char16_t* candidate_word;
s32 candidate_index; s32 candidate_index;
OrbisImeDeviceType device_type; OrbisImeDeviceType device_type;
OrbisImePanelType panel_type;
u32 input_method_state; u32 input_method_state;
s8 reserved[64]; s8 reserved[64];
}; };
@ -177,7 +478,84 @@ struct OrbisImeEvent {
OrbisImeEventParam param; OrbisImeEventParam param;
}; };
using OrbisImeExtKeyboardFilter = PS4_SYSV_ABI int (*)(const OrbisImeKeycode* srcKeycode,
u16* outKeycode, u32* outStatus,
void* reserved);
using OrbisImeTextFilter = PS4_SYSV_ABI int (*)(char16_t* outText, u32* outTextLength, using OrbisImeTextFilter = PS4_SYSV_ABI int (*)(char16_t* outText, u32* outTextLength,
const char16_t* srcText, u32 srcTextLength); const char16_t* srcText, u32 srcTextLength);
using OrbisImeEventHandler = PS4_SYSV_ABI void (*)(void* arg, const OrbisImeEvent* e); using OrbisImeEventHandler = PS4_SYSV_ABI void (*)(void* arg, const OrbisImeEvent* e);
struct OrbisImeKeyboardParam {
OrbisImeKeyboardOption option;
s8 reserved1[4];
void* arg;
OrbisImeEventHandler handler;
s8 reserved2[8];
};
struct OrbisImeParam {
Libraries::UserService::OrbisUserServiceUserId user_id;
OrbisImeType type;
OrbisImeLanguage supported_languages;
OrbisImeEnterLabel enter_label;
OrbisImeInputMethod input_method;
OrbisImeTextFilter filter;
OrbisImeOption option;
u32 maxTextLength;
char16_t* inputTextBuffer;
f32 posx;
f32 posy;
OrbisImeHorizontalAlignment horizontal_alignment;
OrbisImeVerticalAlignment vertical_alignment;
void* work;
void* arg;
OrbisImeEventHandler handler;
s8 reserved[8];
};
struct OrbisImeCaret {
f32 x;
f32 y;
u32 height;
u32 index;
};
struct OrbisImeDialogParam {
Libraries::UserService::OrbisUserServiceUserId user_id;
OrbisImeType type;
OrbisImeLanguage supported_languages;
OrbisImeEnterLabel enter_label;
OrbisImeInputMethod input_method;
OrbisImeTextFilter filter;
OrbisImeOption option;
u32 max_text_length;
char16_t* input_text_buffer;
f32 posx;
f32 posy;
OrbisImeHorizontalAlignment horizontal_alignment;
OrbisImeVerticalAlignment vertical_alignment;
const char16_t* placeholder;
const char16_t* title;
s8 reserved[16];
};
struct OrbisImeParamExtended {
OrbisImeExtOption option;
OrbisImeColor color_base;
OrbisImeColor color_line;
OrbisImeColor color_text_field;
OrbisImeColor color_preedit;
OrbisImeColor color_button_default;
OrbisImeColor color_button_function;
OrbisImeColor color_button_symbol;
OrbisImeColor color_text;
OrbisImeColor color_special;
OrbisImePanelPriority priority;
char* additional_dictionary_path;
OrbisImeExtKeyboardFilter ext_keyboard_filter;
OrbisImeDisableDevice disable_device;
u32 ext_keyboard_mode;
s8 reserved[60];
};

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