143 Commits

Author SHA1 Message Date
AlpinDale
de6c5bbb83 cli: add --show-fps to the CLI launcher (#3860)
* cli: add `--show-fps` to the CLI launcher

* fix: clang-format

* nit: PascalCase -> camelCase
2025-12-08 21:02:54 +01:00
Stephen Miller
65f0b07c34 libkernel: Implement sceKernelEnableDmemAliasing, proper mapping type checks in posix_mmap (#3859)
* Basic handling for MAP_VOID, MAP_STACK, and MAP_ANON in mmap.

* Update memory.cpp

* Update memory.cpp

* Dmem aliasing check

* Oops
2025-12-08 13:46:32 +02:00
kalaposfos13
2a5910ed51 New translations en_us.ts (OpenOrbis) (#3858) 2025-12-07 23:56:51 +02:00
Stephen Miller
391d30cbb1 cpu_patches: Patch stack canary accesses (#3857)
* Patch stack checks done using fs:[0x28]

Additionally adds support for multiple patches per instruction, since this makes two separate patches we need to conditionally perform for mov instructions.

* Missing include

* Disable patches for Apple

Mac can use their native FS segment directly, so these patches aren't needed

* Oops
2025-12-06 22:47:39 -08:00
TheTurtle
d3ad728ac0 vector_alu: Handle -1 as src1 in v_cmp_u64 (#3855) 2025-12-06 15:11:29 -08:00
Odukoya Abdullahi Ademola
5183cbe686 sceHttpUriSweepPath (#3854) 2025-12-04 10:50:24 +02:00
Odukoya Abdullahi Ademola
9e80cde60d Implement http uri escape unescape (#3853)
* Implement sceHttpUriEscape and sceHttpUriUnescape

* Implement sceHttpUriEscape and sceHttpUriUnescape

* edge case

---------

Co-authored-by: Pirky10 <odukoyaabdullah@gmail.com>
2025-12-04 10:50:01 +02:00
kalaposfos13
98fd0689ac Revert non-Linux parts of #3819 (#3852)
* Revert non-Linux parts of #3819

* More OpenOrbis stuff that I couldn't be bothered to put in a new PR
2025-12-03 15:05:19 +02:00
Lander Gallastegi
9db4642f66 video_core: Scheduler priority pending operation queue (#3848)
* Priority pending ops

* Use priority operations on image download

* clang-format

* Simplify thread

* I'm tired, it's too late :(
2025-12-02 22:27:01 +01:00
kalaposfos13
b135a056ba Remove debug logging 2025-12-02 09:50:11 +01:00
kalaposfos13
dc6013cf0e Block normal mouse inputs in mouse-to-touchpad mode
shadow sniped my PR. :(
2025-12-02 09:41:06 +01:00
Pirky
e5ea55e425 np: Add dialog state tracking for NpCommerce (#3841) 2025-12-02 10:22:41 +02:00
kalaposfos13
c3f7a4301c Add basic mouse-to-touchpad emulation (#3842) 2025-12-02 10:21:01 +02:00
Stephen Miller
a5f9280841 Return CPU mode based on param.sfo attributes (#3846)
Values are based on hardware observations.
2025-12-01 10:21:19 +02:00
kalaposfos13
cf866ab294 Don't bother trying to restart the emulator if sceSystemServiceLoadExec is called with an invalid path (#3845) 2025-11-30 22:40:58 +02:00
Connor Garey
052f3260f3 Sdl message box when no args provided (#3843)
* Added a message box when no arguments are passed.

* clang-fix

* clang-fix episode 2

* Output message box error to stderr instead of stdout
2025-11-30 19:57:14 +02:00
TheThunderTurner
78e301c3db libSceNpCommerce (#3839)
* libSceNpCommerce

* copyright notice
2025-11-29 23:47:15 +02:00
psucien
a9f8eaf778 video_core: Initial implementation of pipeline cache (#3816)
* Initial implementation

* Fix for crash caused by stale stages data; cosmetics applied

* Someone mentioned the assert

* Async blob writer

* Fix for memory leak

* Remain stuff

* Async changed to `packaged_task`
2025-11-29 11:52:08 +02:00
Quang Ngô
f9ef57f74b Fix metainfo (#3834) 2025-11-28 18:36:11 +02:00
squidbus
1394852791 renderer_vulkan: Remove primitive restart disable support check. (#3827) 2025-11-24 23:51:39 -08:00
Stephen Miller
6295c32e5c Render.Recompiler: Implement V_FLOOR_F64 (#3828)
* VectorFpRound64 decode table

Also fixed definition for V_TRUNC_F64, though I doubt that would change anything important.

* V_FLOOR_F64 implementation

Used by Just Cause 4

* Oops

Never forget your 64s
2025-11-24 23:51:06 -08:00
TheTurtle
14d71a155a video_core: Reimplement inline data as buffer fill (#3825) 2025-11-24 23:25:22 +02:00
kalaposfos13
2577dfde7e Add assert on SFO file being empty (#3815) 2025-11-23 17:30:09 -08:00
Missake
8123c44ad1 Make FSR off by default (#3801)
* Make FSR and RCAS off by default

* Update config.cpp
2025-11-23 17:28:48 -08:00
TheTurtle
f1a8b7d85e vector_alu: Fix V_CMP_U64 (#3823)
* vector_alu: Fix V_CMP_U64

* vector_alu: Also handle vcc in V_CMP_U64
2025-11-23 17:26:34 -08:00
Stephen Miller
f6ae5544fd Kernel.Vmm: Protect Fixes (#3822)
* Some mprotect fixes

The biggest thing here is preventing mprotect on memory that isn't mapped in address space. This would cause exceptions before, but succeeds on real hardware.
I've also included a couple other minor fixes, mostly based around some tests I recently performed.

Note: All changes to memory pools in this PR are assumed. I have not yet tested memory pools with any of this logic, but I do at least want to prevent mprotect on pool reserved memory to avoid crashes.

* Update memory.cpp

* clang
2025-11-22 10:32:53 +02:00
oltolm
4922d526fe msys2: fix build (#3818)
* cmake: fix mingw-w64 build

* time.cpp: fix build with Clang on Windows

* tls.h: include malloc.h for alloca
2025-11-22 10:32:29 +02:00
kalaposfos13
56109a1331 Avoid storing the Tcb pointer on the stack (#3819)
* Avoid storing the Tcb pointer on the stack

* Just return the already stored pointer in GetTcbBase

* Replace uses of GetTcbBase with g_curthread->tcb

* copyright 2025

* sir clang offnir, the all-formatting
2025-11-21 00:42:49 -08:00
Osyotr
544a22a431 emulator: crash faster (#2360)
By disabling Windows Error Reporting.
2025-11-20 22:35:35 +02:00
marecl
6612a32523 Prevent writing to directories (#3820)
* Prevent writing to directories

* Prevent writing to directories
2025-11-20 19:41:01 +02:00
TheTurtle
3f86c2e94a buffer_cache: Split DMA fault handling code from buffer cache (#3809)
Its better not to have that raw code there
2025-11-18 08:46:51 +02:00
Alexandre Bouvier
5b699090e6 cmake: fix sdl3_mixer target name (#3811) 2025-11-17 18:56:01 +02:00
TheTurtle
aa5c045555 logging: Format message after filter check (#3808) 2025-11-16 17:34:23 +02:00
rainmakerv2
ed14359c87 Re-implement custom trophy sounds using sdl3 mixer (#3805)
* re-implement custom trophy sounds using sdl3 mixer

* fix build vars

* Don't change SDL version
2025-11-16 10:36:54 +02:00
Missake
6a9f9abda0 Delete lines about Qt in building doc for Windows (#3800) 2025-11-14 21:48:04 -08:00
TheTurtle
2f55636626 vk_rasterizer: Attempt to optimize compute clears (#3795) 2025-11-15 07:44:25 +02:00
Stephen Miller
94d0f2e7ed Avoid initializing Shader::PsColorBuffer in RefreshGraphicsKey (#3799)
The bitfield in the struct is padded, which produces uninitialized memory on initialization.
To avoid modifying the struct while making our GraphicsPipelineKey struct properly hashable, set values directly instead of re-initializing.

This fixes pipeline compile spam, and the subsequent poor performance, on certain setups.
2025-11-14 19:50:14 -08:00
kalaposfos13
f557c6ac64 Update MoltenVK to the shadPS4 fork (#3797) 2025-11-14 21:47:16 +02:00
Stephen Miller
93c340c6e1 calloc libusb_interface instead of pointer (#3793)
interface->num_altsetting is oob
2025-11-12 17:26:26 +02:00
Joshua de Reeper
25344a3b89 calloc UsbDevice instead of pointer (#3790) 2025-11-12 12:40:39 +02:00
Missake
bbd985fe4b Update building-windows.md (#3792) 2025-11-11 16:56:03 +01:00
Stephen Miller
ee2bc97248 Windows: Limit address space maximum when higher addresses are not needed (#3775)
* Earlier initialization of elf info.

Everything used for elf info initialization comes from the param.sfo, so we can initialize this earlier to have this information accessible during memory init.

* Extract compiled SDK version from pubtoolinfo string

Up until now, we've been using the game's reported "firmware version" as our compiled SDK version. This behavior is inaccurate, and is something that has come up in my hardware tests before.

For the actual compiled SDK version, we should use the SDK version in the PUBTOOLINFO string of the param.sfo, only falling back on the firmware version when that the sdk_ver component isn't present.

* Store compiled SDK version in ElfInfo

* Limit address space for compiled SDK version at or above FW 3

Sony placed a hard cap at 0xfc00000000, with a slight extension for stack mappings. For now, though stack mappings aren't implemented, there's no harm in keeping a slightly extended address space (since this cap is lower than our old user max).

Limiting the max through address space is necessary for Windows due to performance issues, in the future I plan to properly implement checks in memory manager code to properly handle this behavior for all platforms.

* Use compiled SDK version for sceKernelGetCompiledSdkVersion

I think this is pretty self explanatory.

* Log SDK version

Since this value is what most internal firmware version checks are against, logging the value will help with debugging.

* Update address_space.cpp

* Update emulator.cpp

* Backwards compatible logging

Because that's apparently an issue now
2025-11-10 17:07:17 +02:00
Connor Garey
bebfee58d6 Nix shell fixes for uuid (#3784)
* added "with pkgs;" so pkgs does not need to be appended for all the buildInputs.

* Added util linux as missing uuid. Compiles successfully.
2025-11-08 19:08:18 -08:00
georgemoralis
5ddabda2b8 started 0.12.6 WIP 2025-11-07 09:16:58 +02:00
georgemoralis
3ce1ac5e86 tagged 0.12.5 release 2025-11-07 08:59:26 +02:00
Emma
b4628b80e2 ImGui: keep drawing when there's a pending change_layer (#3782) 2025-11-06 20:58:15 -03:00
Emma
2f022a462d filesystem: return st_mtim in posix_stat (fixes RB4 / CUSA02901 DLC crash) (#3781)
* filesystem: return st_mtim in posix_stat

* filesystem: stat - remove reliance on clock_cast

* filesystem: stat - remove reliance on to_time_t
2025-11-06 22:47:40 +02:00
Joshua de Reeper
f5505daaca usbd: Emulate Dimensions Toypad (#3779)
* Dimensions Toypad

* update comment
2025-11-06 17:46:43 +02:00
Joshua de Reeper
8c1ec863da Add Infinity Base Backend (#3778) 2025-11-06 16:34:52 +02:00
kalaposfos13
604f8d9398 More OpenOrbis stuff (#3776) 2025-11-06 13:22:26 +02:00
Stephen Miller
19e974bf21 Libkernel: Implement/stub some functions (#3774)
* Define latest released firmware version, use that for sceKernelGetSystemSwVersion

I feel this is less hacky and error-prone than just returning the game firmware.

* sceKernelGetAllowedSdkVersionOnSystem

* sceKernelHasNeoMode

* sceKernelGetAppInfo stub

* sceKernelGetCurrentCpu

* fixups

* sceKernelGetMainSocId

Used by libSceAvPlayer to determine if console is a pro or not.

* Update process.cpp

* Set has_param_sfo to true

* Clang
2025-11-05 16:58:15 -08:00
Stephen Miller
7031f5968e Better return stub (#3773)
Gets THE PLAYROOM (CUSA00001) further.
2025-11-05 18:32:24 +02:00
georgemoralis
ff8869262f [Libs] Font lib HLE implementation (#2761)
* dummy fontlib libs

* register font libs

* typo fix

* added font error file

* added sceFontCharacterGetBidiLevel (from RE)

* fixup

* sceFontCharacterGetTextOrder , sceFontCharacterLooksFormatCharacters , sceFontCharacterLooksWhiteSpace RE

* sceFontCharacterRefersTextBack,sceFontCharacterRefersTextNext,sceFontRenderSurfaceInit,sceFontRenderSurfaceSetScissor  RE

* sceFontRenderSurfaceSetStyleFrame ,sceFontStyleFrameGetEffectSlant RE added

* clang fix

* sceFontStyleFrameGetEffectWeight

* added sceFontStyleFrameGetScalePixel

* Update types.h

* fixup merge
2025-11-04 17:14:22 +02:00
Stephen Miller
683e5f3b04 Core: Simulate write-only file access with read-write access (#3360)
* Swap write access mode for read write

Opening with access mode w will erase the opened file. We do not want this.

* Create mode

Opening with write access was previously the only way to create a file through open, so add a separate FileAccessMode that uses the write access mode to create files.

* Update file_system.cpp

Remove a hack added to posix_rename to bypass the file clearing behaviors of FileAccessMode::Write

* Check access mode in read functions

Write-only files cause the EBADF return on the various read functions. Now that we're opening files differently, properly handling this is necessary.

* Separate appends into proper modes

Fixes a potential regression from one of my prior PRs, and ensures the Write | Append flag combo also behaves properly in read-related functions.

* Move IsWriteOnly check after device/socket reads

file->f is only valid for files, so checking this before checking for sockets/devices will cause access violations.

* Fix issues

Now that Write is identical to ReadWrite, internal uses of Write need to be swapped to my new Create mode

* Fix remaining uses of FileAccessMode write to create files

Missed these before.

* Fix rebase

* Add stubbed get_authinfo (#3722)

* mostly stubbed get_authinfo

* Return value observed on console if get_authinfo was called for the current thread, esrch otherwise

---------

Co-authored-by: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com>
Co-authored-by: georgemoralis <giorgosmrls@gmail.com>
2025-11-04 10:57:26 +02:00
georgemoralis
08fe66a97f [Libs] Http HLE (part2) (#2762)
* added sceHttpParseStatusLine

* added sceHttpUriMerge

* macOS fix

* more macOS fix?

* typo

* Update src/core/libraries/network/http.cpp

Co-authored-by: illusony <37698908+illusion0001@users.noreply.github.com>

* some work on sceHttpGetStatusCode

* more draft on GetStatusCode

* added some debug info

* fixup

---------

Co-authored-by: illusony <37698908+illusion0001@users.noreply.github.com>
2025-11-04 10:41:26 +02:00
Stephen Miller
bc44865cda Implement sceGnmDrawInitToDefaultContextStateInternal functions (#3770)
These are used by LLE libSceVideodec.
From decompiling the two GnmDriver libraries, it seems like sceGnmDrawInitToDefaultContextStateInternalCommand inlines a call to sceGnmDrawInitToDefaultContextState, so I've replaced that with an actual call to the function for readability.
sceGnmDrawInitToDefaultContextStateInternalSize is one to one with decomp.
2025-11-03 11:06:26 -08:00
kalaposfos13
a42ae46553 Fix game arguments not being passed under a certain condition (#3769) 2025-11-02 23:16:11 +02:00
Vinicius Rangel
a4c3c665fe add null gpu notice (#3768) 2025-11-02 19:55:43 +02:00
Kyoskii
caccc05fb2 buffer_cache: smaller regions (#3764)
* buffer_cache: smaller regions

this was a change back between v0.9.0 to v0.10.0
9f37ede336

reverting the TRACKER_HIGHER_PAGE_BITS from 24 to 22 gives a notable increase to performance.

* Update region_definitions.h

updated copyright
2025-11-01 16:20:45 +02:00
kalaposfos13
8238ecf88a Fix patches being applied multiple times redundantly (#3763) 2025-11-01 13:47:38 +02:00
Joshua de Reeper
8bbb3956a2 Skylander Portal (#3762) 2025-11-01 12:18:34 +02:00
georgemoralis
f466352dde revert controller change from #3750. Seems to cause issues in several games need to be reinvested 2025-11-01 11:40:26 +02:00
Joshua de Reeper
430f2e4700 Fix Typo in CMakeLists for MoltenVK MacOS (#3758) 2025-10-31 09:48:34 -07:00
Pavel
6c7c5eb59c get_authinfo (#3760) 2025-10-31 15:56:11 +02:00
oltolm
493cda07c0 fix divide by zero (#3759) 2025-10-31 15:36:27 +02:00
ElBread3
eda6be746f usbd: Implement usb backend system (#3737)
* initial impl

* reviews

* upstreamed deReaperJosh changes

* fixed config.cpp

---------

Co-authored-by: georgemoralis <giorgosmrls@gmail.com>
2025-10-31 11:11:14 +02:00
georgemoralis
ed9ffbfb64 Remove Qt from emulator (#3733)
* actions removal

* removed qt dir

# Conflicts:
#	src/qt_gui/check_update.cpp
#	src/qt_gui/translations/ar_SA.ts
#	src/qt_gui/translations/ca_ES.ts
#	src/qt_gui/translations/da_DK.ts
#	src/qt_gui/translations/de_DE.ts
#	src/qt_gui/translations/el_GR.ts
#	src/qt_gui/translations/en_US.ts
#	src/qt_gui/translations/es_ES.ts
#	src/qt_gui/translations/fa_IR.ts
#	src/qt_gui/translations/fi_FI.ts
#	src/qt_gui/translations/fr_FR.ts
#	src/qt_gui/translations/hu_HU.ts
#	src/qt_gui/translations/id_ID.ts
#	src/qt_gui/translations/it_IT.ts
#	src/qt_gui/translations/ja_JP.ts
#	src/qt_gui/translations/ko_KR.ts
#	src/qt_gui/translations/lt_LT.ts
#	src/qt_gui/translations/nb_NO.ts
#	src/qt_gui/translations/nl_NL.ts
#	src/qt_gui/translations/pl_PL.ts
#	src/qt_gui/translations/pt_BR.ts
#	src/qt_gui/translations/pt_PT.ts
#	src/qt_gui/translations/ro_RO.ts
#	src/qt_gui/translations/ru_RU.ts
#	src/qt_gui/translations/sl_SI.ts
#	src/qt_gui/translations/sq_AL.ts
#	src/qt_gui/translations/sr_CS.ts
#	src/qt_gui/translations/sv_SE.ts
#	src/qt_gui/translations/tr_TR.ts
#	src/qt_gui/translations/uk_UA.ts
#	src/qt_gui/translations/ur_PK.ts
#	src/qt_gui/translations/vi_VN.ts
#	src/qt_gui/translations/zh_CN.ts
#	src/qt_gui/translations/zh_TW.ts

* removed CMakePresets for qt builds

* clear cmakelists from qt

* sync config file with qtlauncher

* fixing review stuff

* Remove Qt code from memory patcher and add non-Qt fallback for automatic loading of patches
The second feature is disabled if IPC is present, to avoid conflicts with it.

* Add json submodule

* More Qt removal

* Documentation update

* fix build

* fix REUSE?

* removed qrc file

* fix clang

* Simplify Qt installation instructions for macOS

Removed instructions for installing x86_64 Qt on ARM and x86_64 Macs.

* Remove Qt installation instructions from guide

Removed instructions for downloading and configuring Qt.

---------

Co-authored-by: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com>
2025-10-31 10:28:39 +02:00
georgemoralis
5cabd6ddd8 started 0.12.1 WIP 2025-10-31 09:28:17 +02:00
georgemoralis
f06e126330 tagged v0.12.0 2025-10-31 09:01:12 +02:00
Stephen Miller
715eb512c9 Core: Read-only file mmap fix (#3757)
* Extra validity checks for file mmaps

* Add comment
2025-10-30 15:47:08 -07:00
jzwmvqttmd-svg
87e09b613b Fixes scePlayGoDialog status stub (#3750)
* Fixes scePlayGoDialog status stub

* input: Fix analog stick stuttering caused by excessive state buffering
2025-10-26 05:40:00 +02:00
Randomuser8219
6c08c6983b Change log level from WARNING to INFO for tiler compilation (#3749) 2025-10-25 17:43:52 -07:00
squidbus
6bd74ef769 Add CMake presets for macOS. (#3748) 2025-10-24 16:55:41 -07:00
squidbus
bf34665a8f externals: Update and simplify MoltenVK setup. (#3747) 2025-10-23 10:17:47 +03:00
DanielSvoboda
2d17ab8e4b Add informative update message for Qt build deprecation (#3740)
* Add informative update message for Qt build deprecation

* Update ru_RU.ts
2025-10-20 13:19:35 +03:00
Valdis Bogdāns
db9921baf2 GE2: Fix IME text conversion length handling (#3735)
- Reserve an extra space for the terminating character, resolving an issue in GE2 where the last character did not appear when input reached the maximum length.

Co-authored-by: w1naenator <valdis.bogdans@hotmail.com>
2025-10-14 08:41:47 +03:00
rainmakerv2
17fab7fdf1 IPC: commands for volume adjustment, input parsing, fsr, gamepad select (#3734)
* Add IPC functions: volume, fsr settings, parse inputs

* always process fsr values

* set controller command
2025-10-13 15:04:34 +03:00
Valdis Bogdāns
0cd6248eee Ime fixes (#3731)
* Changes
-Added support for OrbisImeParamExtended (extended IME parameters) in ImeHandler, ImeState, and ImeUi
-Updated all relevant constructors and logic to propagate and store the extended parameter
- Now fully supports passing extended options from sceImeOpen to the IME UI and backend

* Potential CUSA00434 [Debug] <Critical> assert.cpp:30 assert_fail_debug_msg: Assertion Failed!
buf_len + 1 <= buf_size && "Is your input buffer properly zero-terminated?" at C:/VS/shadPS4-ime-fixes/externals/dear_imgui/imgui_widgets.cpp:4601 fix

* Attempting to resolve an assertion failure in Diablo III:
- Adjusted buffer sizes
- Updated the calculation of text‑length values

* ime-lib another hotfix

Fixed incorrect param->title validation, which caused the IME dialog to fail to appear in Stardew Valley. Need to be checked.

* Clang fix

* FF9 ImeDialog Hotfix

* Removed the validation that disallowed null text and null placeholder, since using null values is valid in `ImeDialog`.
* Added additional debug logs to aid troubleshooting.

* IME Fixes
- Add missing flags to `OrbisImeExtOption`
- Improve debug logging
- Resolve nonstop `sceImeKeyboardOpen` calls in Stardew Valley (MonoGame engine) for `userId = 254`

* IME: guard null params for CUSA04909

- Add null checks in IME constructors to prevent crashes seen in CUSA04909.
- Leave a clear note about deferring keyboard event dispatch until guest-space translation is ready.

* Some improvements
- Added debug logs so every IME event and host callback (text/caret updates) shows what the guest sent back.
- Updated ImeState to respect the guest’s text-length limit, keep buffers in sync, and record caret/text changes without duplicates.
- Fixed shutdown by actually destroying the handler on close and letting sceImeUpdate exit quietly once the IME is gone.

* CLang

* IME: simplify handlers, add param checks, fix caret index

- Unify ImeHandler init; support optional OrbisImeParamExtended; drop userId from keyboard handler.
- Add basic null checks for work and inputTextBuffer; early error logging.
- Fixed incorrect caret position. Make caret and text area indices 1-based in ImeUi::InputTextCallback.
- Set default user_id to ORBIS_USER_SERVICE_USER_ID_INVALID in sceImeParamInit.
- Reduce noisy debug logs; promote key calls to LOG_INFO.
- Remove unused extended fields from ImeState; minor cleanups.

* IME: text/caret sync fixes; add Enter payload

- Sync UI input and work buffers on UpdateText
- Sync caret position on mouse click by emiting multiple UpdateCaret events for jumps (loop over delta)
- Add text payload to PressEnter (and Close); fixes IME in God Eater 2
- Queue initial Open event after open
- Fix UTF-8 → UTF-16 conversion bounds
- Add debug logs for all queued events

* CLang

* fixed accidental copy / paste replacement in text update event that broke text deletion.

* IME: Add code-point limited InputText and use in IME UI

- Add InputTextExLimited helper to cap Unicode code points and forward callbacks
- Switch IME input to InputTextExLimited with ime_param->maxTextLength and CallbackAlways

---------

Co-authored-by: w1naenator <valdis.bogdans@hotmail.com>
2025-10-13 13:38:44 +03:00
Stephen Miller
a1973438db Documents: More verbose warning about using --depth 1 when cloning (#3732)
* More verbose warning about --depth 1 flag in git clone

Just spent an hour and a half learning what this does the hard way, hopefully this prevents at least a few others from facing the same issues.

* Adjust grammar

Also updated copyright year, because why not.
2025-10-12 21:07:51 -07:00
tomboylover93
a7376dd41f Mark linux-sdl and macos-sdl binaries as executable (#3730) 2025-10-12 15:59:02 -07:00
Stephen Miller
6b6294a750 Filesystem: Always log mode as an octal (#3729)
Mode is an octal, print it as one.
2025-10-11 20:22:35 -07:00
Alexandre Bouvier
999960a6e6 fix for fmt 12 (#3719) 2025-10-08 01:49:46 -07:00
kalaposfos13
6805baffb2 posix_pthread_mutex_destroy (#3720) 2025-10-08 01:44:17 -07:00
Stephen Miller
109b239ddf Fix NoOverwrite flag behavior in MapMemory (#3718)
Reserved memory counts here, so we need to use !IsFree instead of IsMapped.
I swear this is like the 10th time I've messed this sorta thing up. Seems like it's the last case of this type of mistake in our current code though.
2025-10-07 18:39:39 -07:00
Stephen Miller
1714647343 Fix return for running out of flexible memory (#3717) 2025-10-07 17:33:09 -07:00
Stephen Miller
794d593a02 Fix alignment for mmap (#3716) 2025-10-07 16:22:21 -07:00
Stephen Miller
b34556702e NpAuth: Improved stubs (#3712)
* Some structs and function definitions

* Fill in remaining function definitions and structs

The original variants of GetIdToken and GetAuthorizationCode use an online id instead of user id.
The V3 functions use the same internal function, but with a different flag. Unless games show me something different, they likely use the same structs, and definitely use the same parameters.

* Some errors

* Minor formatting change

* Some more errors

* GetIdToken error cases

* Remaining error cases

Just need to tackle request-related logic now.

* Basic request handling

Seems to internally behave similarly to libSceNpManager, but the actual data stored in libSceNpAuth requests appears to be different, so I've kept everything separated.

* NpAuthRequest usage

Again, behavior mirrors libSceNpManager request behavior, though it appears to be a separate implementation.
The only time libSceNpAuth uses libSceNpManager is to actually send the requests, where the act of sending a request involves creating a completely separate NpManager request, using NpManager functions to retrieve the desired data, then deleting the underlying NpManager request. All of this would happen inside GetAuthorizationCode and GetIdToken.

* Oops

* Missing mutexes

* Default output variables to zero

Not sure what all games might check for here, but setting the outputs to zero is probably safe.
2025-10-05 17:31:21 -07:00
Stephen Miller
a0e7f7fb65 NpManager: Implement more request-related behavior (#3703)
* Implement sceNpCheckPlus

* Rework request storage

We'll need to store more data to "fake" async requests.

* sceNpAbortRequest

Pretty simple to add, so might as well.

* Formatting changes

* Async request logic

There's probably some things I'm getting wrong for cases where PSN is connected, but for reasons that should be pretty obvious, learning how that all works is a little more involved than the PSN disconnected results.

* Add missing error check

* Update np_manager.cpp

* Add a mutex to prevent concurrent reads/writes to g_requests

I imagine multi-threading is a lot more commonly used with the async functions, though I haven't tested enough to know.

* Update np_manager.h

* Move request creation to separate internal function

* Oops

Not sure how that got missed, but good thing I spotted it

* Oops
2025-10-05 17:25:46 -07:00
TheTurtle
8f37cfb739 amdgpu: Split liverpool registers and cleanup (#3707) 2025-10-05 13:42:40 -07:00
Stephen Miller
d17a4fb8cc Include older Windows 11 builds in the address space workaround (#3711)
For now, I've included up to Windows 11 22H2 in the workaround.
I've only personally seen reports of issues on Windows 11 21H2, but better safe than sorry (considering Windows 10 22H2 has issues).
2025-10-05 12:46:06 -07:00
kalaposfos13
4fa435490c Add missing function exports for OpenOrbis (#3708)
* Add missing function exports for OpenOrbis

* copyright 2025

* review comment
2025-10-05 19:31:05 +03:00
Stephen Miller
11229c1dc0 Use correct trophy folder for games with multiple trophy lists (#3704)
Based on the games I've checked, it seems like the service label parameter of sceNpTrophyCreateContext is what determines the trophy list.
Since we're already storing the service label in our contexts, and we're already extracting all trophy lists, all that needs doing is using the service label to select the right trophy list.
2025-10-05 18:39:14 +03:00
Stephen Miller
455cd37aae Fix tess addr (#3706) 2025-10-05 18:23:42 +03:00
Stephen Miller
e7194af881 Core: Increase address space limits and rework Windows address space initialization. (#3697)
* SearchFree adjustments

* Robust address validation

I've adjusted IsValidAddress to take in a size, and check whether the whole range is contained in vma map.
If no size is provided, the function reverts to the old form of address validation instead.

* Map around gaps

As is, this should work mostly.
Only remaining issue is adding logic to pass the "mapped regions" to the guest vma map (and make such logic cross-platform).

* Initialize vma_map using gaps

This should allow memory code to catch any issues from address space gaps, and prevent non-fixed mappings from jumping to a location that isn't actually available.

* Clang

* Fix compile

* Clang

* Fix compile again

* Set system_managed_base and system_managed_size based on

Many places in our code use system_managed_base as the minimum mappable address, ensure this fact remains the same  on Windows to prevent potential bugs.

* Reduce address validation in SearchFree

Allows SearchFree to function when a certain Windows GPU driver goes and reserves the whole system managed area.

Since SearchFree is only called on flexible addresses, allowing this particular case, where addresses are in bounds, but there's not enough space to map, should be safe enough.

* Bump address space size further

To handle Madden NFL 16 (and any games like it)

* More thorough logging of available memory regions

Should help with spotting weirdness.

* Formatting fixes

* Clang

* Slight reduction of user space

Still large enough to handle EA's shenanigans, but small enough that Linux doesn't break.

* Assert on VirtualQuery failure

* Extra debugging information

* Further reduce user space

This will unfix most of EA's titles, but UFC will still work.
Older windows versions support the high addresses, but trying to actually use them causes significant performance issues.

* Extra debugging info

Just in case other testers still run into issues.

* Remove debug logging

* Revert user space increases

Technically this constant is still higher than before, but weird side effects of our old logic resulted in a max address somewhere around this in main.

* address_space: Support expanded virtual memory space on macOS.

Co-Authored-By: squidbus <175574877+squidbus@users.noreply.github.com>

* Move address space constants to address_space.cpp

This ensures that all code must use the calculated address space memory values instead of the constants, since the calculated values can differ based on the platform.

This does require slight modification to thread state and gnmdriver code, since both were already using these constants directly.

* Workaround Windows 10 limitations

If a Windows 10 device is detected, use a lower value for USER_MAX to prevent system-wide hangs in VirtualAlloc2 calls.

* Fix compile for Windows-Qt

* Move tessellation_factors_ring_addr initialization to sceGnmGetTheTessellationFactorRingBufferBaseAddress

* Set image base address on Windows

This seems to work fine on Windows 11, needs testing from Windows 10 due to the previously discussed bugs.

* Set Linux executable base to 0x700000000000

This allows Linux to map the full user space without any workarounds.

Co-Authored-By: Marcin Mikołajczyk <2052578+mikusp@users.noreply.github.com>

* Basic formatting changes

* Reduce USER_MAX on Linux

Seems like finding a reliable way to move shadPS4's position in memory is difficult, for now limit the user size so we aren't trying to overwrite ourselves.

* Move memory and address_space variables.

---------

Co-authored-by: squidbus <175574877+squidbus@users.noreply.github.com>
Co-authored-by: Marcin Mikołajczyk <2052578+mikusp@users.noreply.github.com>
2025-10-04 14:52:50 -07:00
TheTurtle
08878385e1 image_info: Fix guest size calculation for linear render targets (#3700) 2025-10-04 23:09:40 +03:00
kalaposfos13
81098da509 did really no one ever test this (#3702) 2025-10-04 23:09:10 +03:00
kalaposfos13
5fedf9daea add missing pthread_condvar_signal export (#3701) 2025-10-04 12:09:03 +03:00
Niram7777
23d0fc6493 Vk validation core on for game specific + optimize search extension (#3698)
* VK validation Core on by default

* VK stop searching extension when found
2025-10-03 12:45:46 -07:00
Niram7777
5c7f802233 VK Layer Settings remove deprecated (#3676) 2025-10-02 12:50:23 -07:00
Niram7777
54b5520c1a VK settings activation based on layers (#3691) 2025-10-02 12:50:12 -07:00
kalaposfos13
02f9aef34a restore accidentally deleted line (#3695) 2025-10-02 12:34:17 +03:00
Valdis Bogdāns
8de385a4f1 IME: guard null params for CUSA04909 (#3680)
* Changes
-Added support for OrbisImeParamExtended (extended IME parameters) in ImeHandler, ImeState, and ImeUi
-Updated all relevant constructors and logic to propagate and store the extended parameter
- Now fully supports passing extended options from sceImeOpen to the IME UI and backend

* Potential CUSA00434 [Debug] <Critical> assert.cpp:30 assert_fail_debug_msg: Assertion Failed!
buf_len + 1 <= buf_size && "Is your input buffer properly zero-terminated?" at C:/VS/shadPS4-ime-fixes/externals/dear_imgui/imgui_widgets.cpp:4601 fix

* Attempting to resolve an assertion failure in Diablo III:
- Adjusted buffer sizes
- Updated the calculation of text‑length values

* ime-lib another hotfix

Fixed incorrect param->title validation, which caused the IME dialog to fail to appear in Stardew Valley. Need to be checked.

* Clang fix

* FF9 ImeDialog Hotfix

* Removed the validation that disallowed null text and null placeholder, since using null values is valid in `ImeDialog`.
* Added additional debug logs to aid troubleshooting.

* IME Fixes
- Add missing flags to `OrbisImeExtOption`
- Improve debug logging
- Resolve nonstop `sceImeKeyboardOpen` calls in Stardew Valley (MonoGame engine) for `userId = 254`

* IME: guard null params for CUSA04909

- Add null checks in IME constructors to prevent crashes seen in CUSA04909.
- Leave a clear note about deferring keyboard event dispatch until guest-space translation is ready.

* Some improvements
- Added debug logs so every IME event and host callback (text/caret updates) shows what the guest sent back.
- Updated ImeState to respect the guest’s text-length limit, keep buffers in sync, and record caret/text changes without duplicates.
- Fixed shutdown by actually destroying the handler on close and letting sceImeUpdate exit quietly once the IME is gone.

* CLang

---------

Co-authored-by: w1naenator <valdis.bogdans@hotmail.com>
2025-10-02 10:25:58 +03:00
squidbus
110a735a04 externals: Update MoltenVK (#3694) 2025-10-01 18:52:12 -07:00
kalaposfos13
74c0ea8432 Add CLI argument to launch the emulator with global config or with default settings (#3688)
* --config-clean, --config-global

* copyright 2025

* fine you win

* copyright 2024
2025-10-01 12:28:34 -07:00
Stephen Miller
af147debc6 Lock linker mutex in RelocateAnyImports (#3693)
Module relocation is not thread safe, games calling LoadAndStartModule on multiple threads can invalidate pointers while iterating through m_modules.

This fixes crashes in some apps on Windows.
2025-10-01 22:27:12 +03:00
Vladislav Mikhalin
1020c3150f avplayer: remove maximum audio delay (#3692) 2025-10-01 22:26:28 +03:00
TheTurtle
0134b8c3a8 buffer_cache: Bring back CPU path (#3679)
It was reported this resulted in a noticeable 10+ fps drop in Driveclub so bring it back just with check to avoid it if the source range is an image alias
2025-10-01 22:22:48 +03:00
Stephen Miller
6fb64a8054 Kernel.Fs: Device file cleanup and /dev/rng implementation (#3682)
* Add RNG device

* rng device implementation

Tailored around libSceSsl2's usage, and based on fpPS4's implementation.

* Device file function types and log fixups

* Updated creates

Updates device file create functions to be the same as the directory file create functions.

* Fix compile

* Includes cleanup

Generally preferred to have full paths. Also removed some unused imports too.

* Fix buffer size

* Bring back cstdlib imports

Needed for Mac OS.
2025-10-01 12:20:58 -07:00
squidbus
6d0b179d24 videoout: Move HDR swapchain configuration to present thread. (#3690) 2025-10-01 12:20:43 -07:00
squidbus
68fca2552f audioout: Do not wait for data within timer. (#3689) 2025-10-01 12:20:35 -07:00
¥IGA
0e6dea1059 Update Qt to 6.9.3 (#3683) 2025-10-01 16:11:39 +03:00
squidbus
8a8ee395c5 image: Improve enforcement of image copy layer rules. (#3681) 2025-09-30 22:47:56 -07:00
Niram7777
a8f4a20b24 VK Wayland RenderDoc log incompatible (#3675) 2025-09-30 07:21:48 -07:00
squidbus
505e80e756 video_core: Fix some image copy and buffer offset validation errors. (#3673) 2025-09-30 16:17:22 +03:00
TheTurtle
ad99bda08d video_core: Better handling of image copies with DmaData (#3672) 2025-09-30 15:51:30 +03:00
TheTurtle
a35c9f3586 Handle mixed samples attachments (V2) (#3667)
* video_core: Refactor render target bind to allow disabling MSAA

* video_core: Implement swapping of backing samples

* clang format

* video_core: Better implementation

Instead of downgrading to 1 sample, always try to match depth samples. This avoids needing to copy depth-stencil attachment and copying multisampled stencil is not possible on some vendors

* video_core: Small bugfixes

* image: Add null check

* vk_rasterizer: Swap backing samples on resolve dst

* vk_presenter: Reset backing samples before present

* video_core: Small refactor to make this implementation better

* reinterpret: Fix channel check for degamma

Seems this was simpler than I thought, hardware doesn't apply degamma on the W channel regardless of swizzle

* image: Add missing end rendering call

* blit_helper: Fix bug in old reinterpret path

* blit_helper: Remove unused layer vertex

Should be used in the future if copying many layers is needed

* vk_rasterizer: Apply suggestion

* vk_rasterizer: More bind refactor

* vk_instance: Re-enable extensions
2025-09-29 16:27:39 +03:00
kalaposfos13
cad027845f Add configurable extra memory (#3513)
* Add configurable extra memory

* lowercase getter and setter

* Refactor memory setup to configure maximum memory limits at runtime

* sir clang offnir, the all-formatting

* Correctly update BackingSize on W*ndows too

* small format change

* remove total_memory_to_use from the header

* i have no idea how to name this commit
"addressing review comments" is a good name i guess

* Do not include extraDmem in the general config
2025-09-28 20:16:03 +03:00
Stephen Miller
6c5a84dc99 Core: Handle various edge cases related to executable permissions. (#3660)
* Fix flag handling on Windows

Fixes a weird homebrew kalaposfos made

* Fix backing protects

Windows requires that protections on areas committed through MapViewOfFile functions are less than the original mapping.
The best way to make sure everything works is to VirtualProtect the code area with the requested protection instead of applying prot directly.

* Fix error code for sceKernelMapDirectMemory2

Real hardware returns EINVAL instead of EACCES here

* Fix prot setting in ProtectBytes

* Handle some extra protection-related edge cases.

Real hardware treats read and write as separate perms, but appends read if you call with write-only (this is visible in VirtualQuery calls)

Additionally, execute permissions are ignored when protecting dmem mappings.

* Properly handle exec permission behavior for memory pools

Calling sceKernelMemoryPoolCommit with executable permissions returns EINVAL, mprotect on pooled mappings ignores the exec protection.

* Clang

* Allow execution protection for direct memory

Further hardware tests show that the dmem area is actually executable, this permission is just hidden from the end user.

* Clang

* More descriptive assert message

* Align address and size in mmap

Like most POSIX functions, mmap aligns address down to the nearest page boundary, and aligns address up to the nearest page boundary.
Since mmap is the only memory mapping function that doesn't error early on misaligned length or size, handle the alignment in the libkernel code.

* Clang

* Fix valid flags

After changing the value, games that specify just CpuWrite would hit the error return.

* Fix prot conversion functions

The True(bool) function returns true whenever value is greater than 0. While this rarely manifested before because of our wrongly defined CpuReadWrite prot, it's now causing trouble with the corrected values.
Technically this could've also caused trouble with games mapping GpuRead permissions, but that seems to be a rare enough use case that I guess it never happened?

I've also added a warning for the case where `write & !read`, since we don't properly handle write-only permissions, and I'm not entirely sure what it would take to deal with that.

* Fix some lingering dmem issues

ReleaseDirectMemory was always unmapping with the size parameter, which could cause it to unmap too much. Since multiple mappings can reference the same dmem area, I've calculated how much of each VMA we're supposed to unmap.
Additionally, I've adjusted the logic for carving out the free dmem area to properly work if ReleaseDirectMemory is called over multiple dmem areas.

Finally, I've patched a bug with my code in UnmapMemory.
2025-09-28 11:36:12 +03:00
Marcin Mikołajczyk
937d50cb00 np: stub sceNpSnsFacebookDialogUpdateStatus (#3661) 2025-09-26 19:19:41 -07:00
georgemoralis
905c536ef4 make sys_modules folder configurable (#3657)
* make sys_modules folder configurable

* Update src/common/config.cpp

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

---------

Co-authored-by: squidbus <175574877+squidbus@users.noreply.github.com>
2025-09-26 12:35:43 -07:00
Stephen Miller
528a060709 Core: Memory code cleanup and further direct memory fixes (#3655)
* Remove mapped dmem type

Since physical addresses can be mapped multiple times, tracking mapped pages is not necessary.
This also allows me to significantly simplify the MapMemory physical address validation logic.

* Proper implementation for sceKernelMtypeprotect

I've rewritten SetDirectMemoryType to use virtual addresses instead of physical addresses, allowing it to be used in sceKernelMtypeprotect.

To accommodate this change, I've also moved address and size alignment out of MemoryManager::Protect

* Apply memory type in sceKernelMemoryPoolCommit

* Organization

Some potentially important missing mutexes, removed some unnecessary mutexes, moved some mutexes after early error returns, and updated copyright dates

* Iterator logic cleanup

Missing end check in ClampRangeSize, and adjusted VirtualQuery and DirectMemoryQuery.

* Clang

* Adjustments

* Properly account for behavior differences in MapDirectMemory2

Undid the changes to direct memory areas, added more robust logic for changing dma types, and fixed DirectMemoryQuery to return hardware-accurate direct memory information in cases where dmas split here, but not on real hardware.

I've also changed MapMemory's is_exec flag to a validate_dmem flag, used to handle alternate behavior in MapDirectMemory2. is_exec is now determined by the use of MemoryProt::CpuExec instead.

* Clang

* Add execute permissions to physical backing

Needed for executable mappings to work properly on Windows, fixes regression in RE2 with prior commit.

* Minor variable cleanup

* Update memory.h

* Prohibit direct memory mappings with exec protections

Did a quick hardware test to confirm, only seems to be prohibited for dmem mappings though.

* Update memory.cpp
2025-09-26 02:28:32 -07:00
georgemoralis
6e27842562 Trophy fixes IXXXX (#3653)
* fixing missing trophy files extraction

* implemented sceNpTrophyGetGameIcon

* adjustments

* improvements

* argg

* added assert

* done

* fixed compiling
2025-09-26 00:00:12 -07:00
Vinicius Rangel
71f343d2d6 Impl sceSystemServiceLoadExec (#3647)
* Add support for restarting the emulator with new configurations

- Implement `Restart` function in `Emulator` to enable process relaunch with updated parameters.
- Modify `sceSystemServiceLoadExec` to use the restart functionality.

* Add logging for emulator restart and system service load execution

* Add IPC emulator PID output command

Impl `PID` output command to return the emulator process ID
- required for launches supporting emulator restart

* Add log file append mode support (used after restarting to keep the same log file)

* Keep game root between restarts

* add --wait-for-debugger option flag

* add --wait-for-pid flag

used for sync between parent & child process during restart

* impl restart via ipc

* fix override game root

* add qt flags to allow restart
2025-09-25 23:01:52 -03:00
Marcin Mikołajczyk
a6f5e4c7dc net: silence some epoll logs (#3654) 2025-09-25 12:41:31 -07:00
Stephen Miller
98ceb6e43e Allow overlapping direct memory mappings (#3648)
Real hardware allows this, and it worked fine in the past, so allow it here.
2025-09-24 19:22:48 +03:00
Stephen Miller
eeee6ad0ee Memory: Implement sceKernelMemoryPoolGetBlockStats (#3646)
* Implement sceKernelMemoryPoolGetBlockStats

Not entirely sure on the logic behind the cached blocks work, but flushed blocks seems to just be based on committed direct memory.

* Fix comment
2025-09-24 02:40:26 -07:00
Stephen Miller
5d8027f0c0 Core: Refactor direct memory handling (#3645)
* Refactor direct memory areas

At this point, swapping the multiple booleans for an enum is cleaner, and makes it easier to track the state of a direct memory area.

I've also sped up the logic for mapping direct memory by checking for out-of-bounds physical addresses before looping, and made the logic more solid using my dma type logic.

* Fix PoolCommit assert

Windows devices will throw an access violation if we don't check for iterator reaching end.
2025-09-23 22:42:15 +03:00
Vladislav Mikhalin
1eead6a5ee avplayer: fix play request state handling (#3644) 2025-09-23 21:17:48 +03:00
Stephen Miller
419ea140ab Core: physical backing for flexible and pooled memory allocations (#3639)
* Fix isDevKit

Previously, isDevKit could increase the physical memory used above the length we reserve in the backing file.

* Physical backing for flexible allocations

I took the simple approach here, creating a separate map for flexible allocations and pretty much just copying over the logic used in the direct memory map.

* Various fixups

* Fix mistake #1

* Assert + clang

* Fix 2

* Clang

* Fix CanMergeWith

Validate physical base for flexible mappings

* Clang

* Physical backing for pooled memory

* Allow VMA splitting in NameVirtualRange

This should be safe, since with the changes in this PR, the only issues that come from discrepancies between address space and vma_map are issues related to vmas being larger than address space mappings. NameVirtualRange will only ever shrink VMAs by naming part of one.

* Fix

* Fix NameVirtualRange

* Revert NameVirtualRange changes

Seems like it doesn't play nice for Windows

* Clean up isDevKit logic

We already log both isNeo and isDevKit in Emulator::Run, so the additional logging in MemoryManager::SetupMemoryRegions isn't really necessary.

I've also added a separate constant for non-pro devkit memory, as suggested.

Finally I've changed a couple constants to use the ORBIS prefix we generally follow here, instead of the SCE prefix.

* Erase flexible memory contents from physical memory on unmap

Flexible memory should not be preserved on unmap, so erase flexible contents from the physical backing when unmapping.

* Expand flexible memory map

Some games will end up fragmenting the physical backing space used for flexible memory. To reduce the frequency of this happening under normal circumstances, allocate the entirety of the remaining physical backing to the flexible memory map.

This is effectively a workaround to the problem, but at the moment I think this should suffice.

* Clang
2025-09-23 17:24:37 +03:00
Marcin Mikołajczyk
976d12f4e6 Epolls are file descriptors (#3622)
* net: Register epolls in file descriptor table

* fstat: stub epoll, resolver

* Fake async hostname resolution

* net: epoll fixes

* epoll: actually close the file descriptor
2025-09-22 22:57:51 +03:00
Vladislav Mikhalin
50a3081084 ajm: handle ParseRiffHeader flag (#3618)
* ajm: handle ParseRiffheader flag

* small optimizations and cleanup

* allow uninitialized instances handle RIFF

* fixed audio cutoff and small refactoring

* small fix to the returned data

* fix gapless init, reset total samples on RIFF init

* warning reporting + consume input buffer on gapless loop
2025-09-22 18:50:57 +03:00
Vladislav Mikhalin
525d24a7fc avplayer: do not start the video multiple times (#3638) 2025-09-21 16:03:24 +03:00
Missake212
51c96b8ee6 Lower "Trophy key is not specified" message from critical to info (#3636) 2025-09-20 12:47:46 -07:00
Vladislav Mikhalin
2b1c0b4f82 avplayer: implemented AddSourceEx, SetAvSyncMode, Pause and Resume (#2456)
* avplayer: code improvements

* avplayer: implemented pause/resume

* avplayer: implemented sync modes

* avplayer: issue warning on loopback

* avplayer: sync on video ts in default mode when audio ts is not available

* avplayer: removed waits for the frame in Get*Data, replaced cv with sleep

* avplayer: removed all waits from GetVideoData

* avplayer: fix warning propagation + small fixes

* Using texture memory for video frames, dropped video frame cache, syncing audio to video

* do not sync to audio when audio is not enabled

* removed logs, fixed sync

* reverted the removal of pre-allocated buffers
2025-09-20 19:27:16 +03:00
DanielSvoboda
eb18382396 Fix: V_MUL_I32_I24 | V_MUL_U32_U24 (#3632) 2025-09-19 19:05:22 -07:00
Missake212
fa489c023e Update game-bug-report.yaml (#3628) 2025-09-19 18:36:52 +03:00
kalaposfos13
f01b6295dd Make UpdatePlayTime not depend on Qt (#3629)
* Make UpdatePlayTime not depend on Qt

* sir clang offnir, the all-formatting
2025-09-19 18:34:21 +03:00
squidbus
be80276ec3 Fix Pthread memset warning and add comment. (#3625) 2025-09-19 02:17:30 -07:00
DanielSvoboda
71e81c836c Remove Crowdin integration and related Actions (#3623) 2025-09-18 23:36:38 +03:00
kalaposfos13
ddb59edd3e Enable autoupdating on actions that run for tags, not commits (#3621) 2025-09-18 16:30:53 +03:00
Marcin Mikołajczyk
7bd3eb485f Epoll (#3476)
* Epoll

* Change companion util stub to return NO_EVENT

* Revert "Change companion util stub to return NO_EVENT"

This reverts commit 8dd9913cda39b641cd3b65925e1f31fa713e8a24.

* added wepoll

* shallow..

* dist branch

* updated wepoll

* compiles on windows

---------

Co-authored-by: georgemoralis <giorgosmrls@gmail.com>
2025-09-18 11:53:04 +03:00
squidbus
0eff74223a shader_recompiler: Implement fallback path for missing shaderFloat16 support. (#3604) 2025-09-18 00:43:47 -07:00
georgemoralis
1e949c5813 started 0.11.1 WIP 2025-09-18 10:18:02 +03:00
403 changed files with 16762 additions and 110338 deletions

View File

@@ -35,7 +35,7 @@ body:
required: true
- label: I have disabled all patches and cheats and the issue is still present.
required: true
- label: I have all the required [system modules](https://github.com/shadps4-emu/shadPS4/wiki/I.-Quick-start-%5BUsers%5D#4-adding-modules) installed.
- label: I have all the required [system modules](https://github.com/shadps4-emu/shadPS4/wiki/I.-Quick-start-%5BUsers%5D#4-dumping-firmware-modules) installed.
required: true
- type: textarea
id: desc

View File

@@ -1,33 +0,0 @@
# SPDX-FileCopyrightText: 2024 shadPS4 Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
#!/bin/bash
if [[ -z $GITHUB_WORKSPACE ]]; then
GITHUB_WORKSPACE="${PWD%/*}"
fi
export Qt6_DIR="/usr/lib/qt6"
export PATH="$Qt6_DIR/bin:$PATH"
export EXTRA_QT_PLUGINS="waylandcompositor"
export EXTRA_PLATFORM_PLUGINS="libqwayland-egl.so;libqwayland-generic.so"
# Prepare Tools for building the AppImage
wget -q https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
wget -q https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage
wget -q https://github.com/linuxdeploy/linuxdeploy-plugin-checkrt/releases/download/continuous/linuxdeploy-plugin-checkrt-x86_64.sh
chmod a+x linuxdeploy-x86_64.AppImage
chmod a+x linuxdeploy-plugin-qt-x86_64.AppImage
chmod a+x linuxdeploy-plugin-checkrt-x86_64.sh
# Build AppImage
./linuxdeploy-x86_64.AppImage --appdir AppDir
./linuxdeploy-plugin-checkrt-x86_64.sh --appdir AppDir
cp -a "$GITHUB_WORKSPACE/build/translations" AppDir/usr/bin
./linuxdeploy-x86_64.AppImage --appdir AppDir -d "$GITHUB_WORKSPACE"/dist/net.shadps4.shadPS4.desktop -e "$GITHUB_WORKSPACE"/build/shadps4 -i "$GITHUB_WORKSPACE"/src/images/net.shadps4.shadPS4.svg --plugin qt
rm AppDir/usr/plugins/multimedia/libgstreamermediaplugin.so
./linuxdeploy-x86_64.AppImage --appdir AppDir --output appimage
mv shadPS4-x86_64.AppImage Shadps4-qt.AppImage

View File

@@ -17,14 +17,14 @@ jobs:
runs-on: ubuntu-24.04
continue-on-error: true
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- uses: fsfe/reuse-action@v5
clang-format:
runs-on: ubuntu-24.04
continue-on-error: true
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Install
@@ -45,7 +45,7 @@ jobs:
shorthash: ${{ steps.vars.outputs.shorthash }}
fullhash: ${{ steps.vars.outputs.fullhash }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: Get date and git hash
id: vars
run: |
@@ -60,7 +60,7 @@ jobs:
runs-on: windows-2025
needs: get-info
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
submodules: recursive
@@ -76,7 +76,7 @@ jobs:
${{ env.cache-name }}-
- name: Cache CMake Build
uses: hendrikmuhs/ccache-action@v1.2.18
uses: hendrikmuhs/ccache-action@v1.2.19
env:
cache-name: ${{ runner.os }}-sdl-cache-cmake-build
with:
@@ -95,69 +95,11 @@ jobs:
name: shadps4-win64-sdl-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }}
path: ${{github.workspace}}/build/shadPS4.exe
windows-qt:
runs-on: windows-2025
needs: get-info
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup Qt
uses: jurplel/install-qt-action@v4
with:
version: 6.9.2
host: windows
target: desktop
arch: win64_msvc2022_64
archives: qtbase qttools
modules: qtmultimedia
- name: Cache CMake Configuration
uses: actions/cache@v4
env:
cache-name: ${{ runner.os }}-qt-ninja-cache-cmake-configuration
with:
path: |
${{github.workspace}}/build
key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}
restore-keys: |
${{ env.cache-name }}-
- name: Cache CMake Build
uses: hendrikmuhs/ccache-action@v1.2.18
env:
cache-name: ${{ runner.os }}-qt-cache-cmake-build
with:
append-timestamp: false
key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', '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
- name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $env:NUMBER_OF_PROCESSORS
- name: Deploy and Package
run: |
mkdir upload
mkdir upload/qtplugins
move build/shadPS4.exe upload
cp dist/qt.conf upload/qt.conf
windeployqt --plugindir upload/qtplugins --no-compiler-runtime --no-system-d3d-compiler --no-system-dxc-compiler --dir upload upload/shadPS4.exe
Compress-Archive -Path upload/* -DestinationPath shadps4-win64-qt-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }}.zip
- name: Upload Windows Qt artifact
uses: actions/upload-artifact@v4
with:
name: shadps4-win64-qt-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }}
path: upload/
macos-sdl:
runs-on: macos-15
needs: get-info
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
submodules: recursive
@@ -178,7 +120,7 @@ jobs:
${{ env.cache-name }}-
- name: Cache CMake Build
uses: hendrikmuhs/ccache-action@v1.2.18
uses: hendrikmuhs/ccache-action@v1.2.19
env:
cache-name: ${{runner.os}}-sdl-cache-cmake-build
with:
@@ -204,72 +146,11 @@ jobs:
name: shadps4-macos-sdl-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }}
path: upload/
macos-qt:
runs-on: macos-15
needs: get-info
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup latest Xcode
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: latest
- name: Setup Qt
uses: jurplel/install-qt-action@v4
with:
version: 6.9.2
host: mac
target: desktop
arch: clang_64
archives: qtbase qttools
modules: qtmultimedia
- name: Cache CMake Configuration
uses: actions/cache@v4
env:
cache-name: ${{ runner.os }}-qt-cache-cmake-configuration
with:
path: |
${{github.workspace}}/build
key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}
restore-keys: |
${{ env.cache-name }}-
- name: Cache CMake Build
uses: hendrikmuhs/ccache-action@v1.2.18
env:
cache-name: ${{runner.os}}-qt-cache-cmake-build
with:
append-timestamp: false
create-symlink: true
key: ${{env.cache-name}}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}
variant: sccache
- name: Configure CMake
run: cmake --fresh -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_OSX_ARCHITECTURES=x86_64 -DENABLE_QT_GUI=ON -DENABLE_UPDATER=ON -DCMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE=ON -DCMAKE_C_COMPILER_LAUNCHER=sccache -DCMAKE_CXX_COMPILER_LAUNCHER=sccache
- name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $(sysctl -n hw.ncpu)
- name: Package and Upload macOS Qt artifact
run: |
mkdir upload
mv ${{github.workspace}}/build/shadps4.app upload
macdeployqt upload/shadps4.app
tar cf shadps4-macos-qt.tar.gz -C upload .
- uses: actions/upload-artifact@v4
with:
name: shadps4-macos-qt-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }}
path: shadps4-macos-qt.tar.gz
linux-sdl:
runs-on: ubuntu-24.04
needs: get-info
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
submodules: recursive
@@ -293,7 +174,7 @@ jobs:
${{ env.cache-name }}-
- name: Cache CMake Build
uses: hendrikmuhs/ccache-action@v1.2.18
uses: hendrikmuhs/ccache-action@v1.2.19
env:
cache-name: ${{ runner.os }}-sdl-cache-cmake-build
with:
@@ -326,63 +207,11 @@ jobs:
name: shadps4-linux-sdl-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }}
path: Shadps4-sdl.AppImage
linux-qt:
runs-on: ubuntu-24.04
needs: get-info
steps:
- uses: actions/checkout@v4
with:
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
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
uses: actions/cache@v4
env:
cache-name: ${{ runner.os }}-qt-cache-cmake-configuration
with:
path: |
${{github.workspace}}/build
key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}
restore-keys: |
${{ env.cache-name }}-
- name: Cache CMake Build
uses: hendrikmuhs/ccache-action@v1.2.18
env:
cache-name: ${{ runner.os }}-qt-cache-cmake-build
with:
append-timestamp: false
key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', '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-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
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $(nproc)
- name: Run AppImage packaging script
run: ./.github/linux-appimage-qt.sh
- name: Package and Upload Linux Qt artifact
run: |
tar cf shadps4-linux-qt.tar.gz -C ${{github.workspace}}/build shadps4
- uses: actions/upload-artifact@v4
with:
name: shadps4-linux-qt-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }}
path: Shadps4-qt.AppImage
linux-sdl-gcc:
runs-on: ubuntu-24.04
needs: get-info
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
submodules: recursive
@@ -401,7 +230,7 @@ jobs:
${{ env.cache-name }}-
- name: Cache CMake Build
uses: hendrikmuhs/ccache-action@v1.2.18
uses: hendrikmuhs/ccache-action@v1.2.19
env:
cache-name: ${{ runner.os }}-sdl-gcc-cache-cmake-build
with:
@@ -414,51 +243,20 @@ jobs:
- name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $(nproc)
linux-qt-gcc:
runs-on: ubuntu-24.04
needs: get-info
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- 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 mold build-essential qt6-base-dev qt6-tools-dev qt6-multimedia-dev libasound2-dev libpulse-dev libopenal-dev libudev-dev
- name: Cache CMake Configuration
uses: actions/cache@v4
env:
cache-name: ${{ runner.os }}-qt-gcc-cache-cmake-configuration
with:
path: |
${{github.workspace}}/build
key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}
restore-keys: |
${{ env.cache-name }}-
- name: Cache CMake Build
uses: hendrikmuhs/ccache-action@v1.2.18
env:
cache-name: ${{ runner.os }}-qt-gcc-cache-cmake-build
with:
append-timestamp: false
key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', '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_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
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $(nproc)
pre-release:
if: github.ref == 'refs/heads/main' && github.repository == 'shadps4-emu/shadPS4' && github.event_name == 'push'
needs: [get-info, windows-sdl, windows-qt, macos-sdl, macos-qt, linux-sdl, linux-qt]
needs: [get-info, windows-sdl, macos-sdl, linux-sdl]
runs-on: ubuntu-latest
steps:
- name: Download all artifacts
uses: actions/download-artifact@v4
uses: actions/download-artifact@v5
with:
path: ./artifacts
- name: Make SDL artifacts executable
run: |
chmod -R a+x ./artifacts/shadps4-linux-sdl-*
chmod -R a+x ./artifacts/shadps4-macos-sdl-*
- name: Compress individual directories (without parent directory)
run: |

View File

@@ -1,11 +0,0 @@
#!/bin/bash
set -e
sudo apt-get -y install qt6-l10n-tools python3
SCRIPT_PATH="src/qt_gui/translations/update_translation.sh"
chmod +x "$SCRIPT_PATH"
PATH=/usr/lib/qt6/bin:$PATH "$SCRIPT_PATH"

View File

@@ -1,30 +0,0 @@
name: Update Translation
on:
schedule:
- cron: "0 0 * * *" # Every day at 12am UTC.
workflow_dispatch: # As well as manually.
jobs:
update:
if: github.repository == 'shadps4-emu/shadPS4'
name: "Update Translation"
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: Set execution permissions for the script
run: chmod +x ./.github/workflows/scripts/update_translation.sh
- name: Update Base Translation
run: ./.github/workflows/scripts/update_translation.sh
- name: Create Pull Request
uses: peter-evans/create-pull-request@v7
with:
token: ${{ secrets.SHADPS4_TOKEN_REPO }}
title: "Qt GUI: Update Translation"
commit-message: "[ci skip] Qt GUI: Update Translation."
body: "Daily update of translation sources."
branch: update-translation
delete-branch: true

31
.gitmodules vendored
View File

@@ -91,18 +91,6 @@
path = externals/libpng
url = https://github.com/pnggroup/libpng
shallow = true
[submodule "externals/MoltenVK/SPIRV-Cross"]
path = externals/MoltenVK/SPIRV-Cross
url = https://github.com/KhronosGroup/SPIRV-Cross
shallow = true
[submodule "externals/MoltenVK/MoltenVK"]
path = externals/MoltenVK/MoltenVK
url = https://github.com/KhronosGroup/MoltenVK
shallow = true
[submodule "externals/MoltenVK/cereal"]
path = externals/MoltenVK/cereal
url = https://github.com/USCiLab/cereal
shallow = true
[submodule "externals/ext-libusb"]
path = externals/ext-libusb
url = https://github.com/shadps4-emu/ext-libusb.git
@@ -113,3 +101,22 @@
path = externals/hwinfo
url = https://github.com/shadps4-emu/ext-hwinfo
shallow = true
[submodule "externals/ext-wepoll"]
path = externals/ext-wepoll
url = https://github.com/shadps4-emu/ext-wepoll.git
shallow = true
branch = dist
[submodule "externals/MoltenVK"]
path = externals/MoltenVK
url = https://github.com/shadPS4-emu/ext-MoltenVK.git
shallow = true
[submodule "externals/json"]
path = externals/json
url = https://github.com/nlohmann/json.git
[submodule "externals/sdl3_mixer"]
path = externals/sdl3_mixer
url = https://github.com/libsdl-org/SDL_mixer
shallow = true
[submodule "externals/miniz"]
path = externals/miniz
url = https://github.com/richgel999/miniz

22
CMakeDarwinPresets.json Normal file
View File

@@ -0,0 +1,22 @@
{
"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}",
"CMAKE_OSX_ARCHITECTURES": "x86_64"
}
}
]
}

View File

@@ -31,7 +31,6 @@ if(UNIX AND NOT APPLE)
endif()
endif()
option(ENABLE_QT_GUI "Enable the Qt GUI. If not selected then the emulator uses a minimal SDL-based UI instead" OFF)
option(ENABLE_DISCORD_RPC "Enable the Discord RPC integration" ON)
option(ENABLE_UPDATER "Enables the options to updater" ON)
@@ -203,27 +202,23 @@ execute_process(
# Set Version
set(EMULATOR_VERSION_MAJOR "0")
set(EMULATOR_VERSION_MINOR "11")
set(EMULATOR_VERSION_PATCH "0")
set(EMULATOR_VERSION_MINOR "12")
set(EMULATOR_VERSION_PATCH "6")
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_IS_RELEASE true)
set(APP_VERSION "${EMULATOR_VERSION_MAJOR}.${EMULATOR_VERSION_MINOR}.${EMULATOR_VERSION_PATCH} WIP")
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)
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")
if(NOT (GIT_REMOTE_URL_LOWER MATCHES "shadps4-emu/shadps4" AND (GIT_BRANCH STREQUAL "main" OR "$ENV{GITHUB_REF}" MATCHES "refs/tags/")))
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")
find_package(Boost 1.84.0 CONFIG)
find_package(FFmpeg 5.1.2 MODULE)
@@ -233,11 +228,14 @@ find_package(half 1.12.0 MODULE)
find_package(magic_enum 0.9.7 CONFIG)
find_package(PNG 1.6 MODULE)
find_package(RenderDoc 1.6.0 MODULE)
find_package(SDL3 3.1.2 CONFIG)
find_package(SDL3_mixer 2.8.1 CONFIG)
if (SDL3_mixer_FOUND)
find_package(SDL3 3.1.2 CONFIG)
endif()
find_package(stb MODULE)
find_package(toml11 4.2.0 CONFIG)
find_package(tsl-robin-map 1.3.0 CONFIG)
find_package(VulkanHeaders 1.4.324 CONFIG)
find_package(VulkanHeaders 1.4.329 CONFIG)
find_package(VulkanMemoryAllocator 3.1.0 CONFIG)
find_package(xbyak 7.07 CONFIG)
find_package(xxHash 0.8.2 MODULE)
@@ -262,30 +260,6 @@ endif()
add_subdirectory(externals)
include_directories(src)
if(ENABLE_QT_GUI)
find_package(Qt6 REQUIRED COMPONENTS Widgets Concurrent LinguistTools Network Multimedia)
qt_standard_project_setup()
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(QT_TRANSLATIONS "${PROJECT_SOURCE_DIR}/src/qt_gui/translations")
file(GLOB_RECURSE TRANSLATIONS_TS ${QT_TRANSLATIONS}/*.ts)
set_source_files_properties(${TRANSLATIONS_TS} PROPERTIES OUTPUT_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/translations")
qt_add_translation(TRANSLATIONS_QM ${TRANSLATIONS_TS})
set(TRANSLATIONS_QRC ${CMAKE_CURRENT_BINARY_DIR}/translations/translations.qrc)
file(WRITE ${TRANSLATIONS_QRC} "<RCC><qresource prefix=\"translations\">\n")
foreach (QM ${TRANSLATIONS_QM})
get_filename_component(QM_FILE ${QM} NAME)
file(APPEND ${TRANSLATIONS_QRC} "<file>${QM_FILE}</file>\n")
endforeach (QM)
file(APPEND ${TRANSLATIONS_QRC} "</qresource></RCC>")
qt_add_resources(TRANSLATIONS ${TRANSLATIONS_QRC})
endif()
set(AJM_LIB src/core/libraries/ajm/ajm.cpp
src/core/libraries/ajm/ajm.h
src/core/libraries/ajm/ajm_at9.cpp
@@ -380,6 +354,10 @@ set(NETWORK_LIBS src/core/libraries/network/http.cpp
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_epoll.cpp
src/core/libraries/network/net_epoll.h
src/core/libraries/network/net_resolver.cpp
src/core/libraries/network/net_resolver.h
src/core/libraries/network/net_error.h
src/core/libraries/network/net.h
src/core/libraries/network/ssl.cpp
@@ -486,6 +464,12 @@ set(SYSTEM_LIBS src/core/libraries/system/commondialog.cpp
src/core/libraries/mouse/mouse.h
src/core/libraries/web_browser_dialog/webbrowserdialog.cpp
src/core/libraries/web_browser_dialog/webbrowserdialog.h
src/core/libraries/font/font.cpp
src/core/libraries/font/font.h
src/core/libraries/font/fontft.cpp
src/core/libraries/font/fontft.h
src/core/libraries/font/font_error.h
)
set(VIDEOOUT_LIB src/core/libraries/videoout/buffer.h
@@ -528,7 +512,7 @@ set(PAD_LIB src/core/libraries/pad/pad.cpp
src/core/libraries/pad/pad_errors.h
)
set(SYSTEM_GESTURE_LIB
set(SYSTEM_GESTURE_LIB
src/core/libraries/system_gesture/system_gesture.cpp
src/core/libraries/system_gesture/system_gesture.h
)
@@ -557,6 +541,13 @@ set(RANDOM_LIB src/core/libraries/random/random.cpp
set(USBD_LIB src/core/libraries/usbd/usbd.cpp
src/core/libraries/usbd/usbd.h
src/core/libraries/usbd/usb_backend.h
src/core/libraries/usbd/emulated/dimensions.cpp
src/core/libraries/usbd/emulated/dimensions.h
src/core/libraries/usbd/emulated/infinity.cpp
src/core/libraries/usbd/emulated/infinity.h
src/core/libraries/usbd/emulated/skylander.cpp
src/core/libraries/usbd/emulated/skylander.h
)
set(FIBER_LIB src/core/libraries/fiber/fiber_context.s
@@ -565,6 +556,8 @@ set(FIBER_LIB src/core/libraries/fiber/fiber_context.s
src/core/libraries/fiber/fiber_error.h
)
set_source_files_properties(src/core/libraries/fiber/fiber_context.s PROPERTIES COMPILE_OPTIONS -Wno-unused-command-line-argument)
set(VDEC_LIB src/core/libraries/videodec/videodec2_impl.cpp
src/core/libraries/videodec/videodec2_impl.h
src/core/libraries/videodec/videodec2.cpp
@@ -580,6 +573,8 @@ set(VDEC_LIB src/core/libraries/videodec/videodec2_impl.cpp
set(NP_LIBS src/core/libraries/np/np_error.h
src/core/libraries/np/np_common.cpp
src/core/libraries/np/np_common.h
src/core/libraries/np/np_commerce.cpp
src/core/libraries/np/np_commerce.h
src/core/libraries/np/np_manager.cpp
src/core/libraries/np/np_manager.h
src/core/libraries/np/np_score.cpp
@@ -596,6 +591,8 @@ set(NP_LIBS src/core/libraries/np/np_error.h
src/core/libraries/np/np_auth.h
src/core/libraries/np/np_profile_dialog.cpp
src/core/libraries/np/np_profile_dialog.h
src/core/libraries/np/np_sns_facebook_dialog.cpp
src/core/libraries/np/np_sns_facebook_dialog.h
)
set(ZLIB_LIB src/core/libraries/zlib/zlib.cpp
@@ -637,6 +634,7 @@ set(COMPANION_LIBS src/core/libraries/companion/companion_httpd.cpp
)
set(DEV_TOOLS src/core/devtools/layer.cpp
src/core/devtools/layer.h
src/core/devtools/layer_extra.cpp
src/core/devtools/options.cpp
src/core/devtools/options.h
src/core/devtools/gcn/gcn_context_regs.cpp
@@ -697,7 +695,6 @@ set(COMMON src/common/logging/backend.cpp
src/common/lru_cache.h
src/common/error.cpp
src/common/error.h
src/common/scope_exit.h
src/common/fixed_value.h
src/common/func_traits.h
src/common/native_clock.cpp
@@ -711,6 +708,8 @@ set(COMMON src/common/logging/backend.cpp
src/common/rdtsc.h
src/common/recursive_lock.cpp
src/common/recursive_lock.h
src/common/scope_exit.h
src/common/serdes.h
src/common/sha1.h
src/common/shared_first_mutex.h
src/common/signal_context.h
@@ -763,6 +762,8 @@ set(CORE src/core/aerolib/stubs.cpp
src/core/file_sys/devices/deci_tty6_device.h
src/core/file_sys/devices/random_device.cpp
src/core/file_sys/devices/random_device.h
src/core/file_sys/devices/rng_device.cpp
src/core/file_sys/devices/rng_device.h
src/core/file_sys/devices/urandom_device.cpp
src/core/file_sys/devices/urandom_device.h
src/core/file_sys/devices/srandom_device.cpp
@@ -820,6 +821,8 @@ set(CORE src/core/aerolib/stubs.cpp
${DEV_TOOLS}
src/core/debug_state.cpp
src/core/debug_state.h
src/core/debugger.cpp
src/core/debugger.h
src/core/linker.cpp
src/core/linker.h
src/core/memory.cpp
@@ -841,10 +844,10 @@ if (ARCHITECTURE STREQUAL "x86_64")
src/core/cpu_patches.h)
endif()
set(SHADER_RECOMPILER src/shader_recompiler/exception.h
src/shader_recompiler/profile.h
set(SHADER_RECOMPILER src/shader_recompiler/profile.h
src/shader_recompiler/recompiler.cpp
src/shader_recompiler/recompiler.h
src/shader_recompiler/resource.h
src/shader_recompiler/info.h
src/shader_recompiler/params.h
src/shader_recompiler/runtime_info.h
@@ -942,21 +945,30 @@ set(SHADER_RECOMPILER src/shader_recompiler/exception.h
src/shader_recompiler/ir/value.h
)
set(VIDEO_CORE src/video_core/amdgpu/liverpool.cpp
set(VIDEO_CORE src/video_core/amdgpu/cb_db_extent.h
src/video_core/amdgpu/liverpool.cpp
src/video_core/amdgpu/liverpool.h
src/video_core/amdgpu/pixel_format.cpp
src/video_core/amdgpu/pixel_format.h
src/video_core/amdgpu/pm4_cmds.h
src/video_core/amdgpu/pm4_opcodes.h
src/video_core/amdgpu/regs_color.h
src/video_core/amdgpu/regs_depth.h
src/video_core/amdgpu/regs.cpp
src/video_core/amdgpu/regs.h
src/video_core/amdgpu/regs_primitive.h
src/video_core/amdgpu/regs_shader.h
src/video_core/amdgpu/regs_texture.h
src/video_core/amdgpu/regs_vertex.h
src/video_core/amdgpu/resource.h
src/video_core/amdgpu/tiling.cpp
src/video_core/amdgpu/tiling.h
src/video_core/amdgpu/types.h
src/video_core/amdgpu/default_context.cpp
src/video_core/buffer_cache/buffer.cpp
src/video_core/buffer_cache/buffer.h
src/video_core/buffer_cache/buffer_cache.cpp
src/video_core/buffer_cache/buffer_cache.h
src/video_core/buffer_cache/fault_manager.cpp
src/video_core/buffer_cache/fault_manager.h
src/video_core/buffer_cache/memory_tracker.h
src/video_core/buffer_cache/range_set.h
src/video_core/buffer_cache/region_definitions.h
@@ -977,6 +989,8 @@ set(VIDEO_CORE src/video_core/amdgpu/liverpool.cpp
src/video_core/renderer_vulkan/vk_pipeline_cache.h
src/video_core/renderer_vulkan/vk_pipeline_common.cpp
src/video_core/renderer_vulkan/vk_pipeline_common.h
src/video_core/renderer_vulkan/vk_pipeline_serialization.cpp
src/video_core/renderer_vulkan/vk_pipeline_serialization.h
src/video_core/renderer_vulkan/vk_platform.cpp
src/video_core/renderer_vulkan/vk_platform.h
src/video_core/renderer_vulkan/vk_presenter.cpp
@@ -1014,6 +1028,8 @@ set(VIDEO_CORE src/video_core/amdgpu/liverpool.cpp
src/video_core/texture_cache/tile_manager.cpp
src/video_core/texture_cache/tile_manager.h
src/video_core/texture_cache/types.h
src/video_core/cache_storage.cpp
src/video_core/cache_storage.h
src/video_core/page_manager.cpp
src/video_core/page_manager.h
src/video_core/multi_level_page_table.h
@@ -1049,112 +1065,27 @@ set(EMULATOR src/emulator.cpp
src/sdl_window.cpp
)
# The above is shared in SDL and Qt version (TODO share them all)
if(ENABLE_QT_GUI)
qt_add_resources(RESOURCE_FILES src/shadps4.qrc)
if (ENABLE_UPDATER)
set(UPDATER src/qt_gui/check_update.cpp
src/qt_gui/check_update.h
)
endif()
set(QT_GUI src/qt_gui/about_dialog.cpp
src/qt_gui/about_dialog.h
src/qt_gui/about_dialog.ui
src/qt_gui/background_music_player.cpp
src/qt_gui/background_music_player.h
src/qt_gui/cheats_patches.cpp
src/qt_gui/cheats_patches.h
src/qt_gui/compatibility_info.cpp
src/qt_gui/compatibility_info.h
src/qt_gui/control_settings.cpp
src/qt_gui/control_settings.h
src/qt_gui/control_settings.ui
src/qt_gui/kbm_gui.cpp
src/qt_gui/kbm_gui.h
src/qt_gui/kbm_gui.ui
src/qt_gui/main_window_ui.h
src/qt_gui/main_window.cpp
src/qt_gui/main_window.h
src/qt_gui/gui_context_menus.h
src/qt_gui/game_list_utils.h
src/qt_gui/game_info.cpp
src/qt_gui/game_info.h
src/qt_gui/game_list_frame.cpp
src/qt_gui/game_list_frame.h
src/qt_gui/game_grid_frame.cpp
src/qt_gui/game_grid_frame.h
src/qt_gui/game_install_dialog.cpp
src/qt_gui/game_install_dialog.h
src/qt_gui/trophy_viewer.cpp
src/qt_gui/trophy_viewer.h
src/qt_gui/elf_viewer.cpp
src/qt_gui/elf_viewer.h
src/qt_gui/kbm_config_dialog.cpp
src/qt_gui/kbm_config_dialog.h
src/qt_gui/kbm_help_dialog.cpp
src/qt_gui/kbm_help_dialog.h
src/qt_gui/main_window_themes.cpp
src/qt_gui/main_window_themes.h
src/qt_gui/log_presets_dialog.cpp
src/qt_gui/log_presets_dialog.h
src/qt_gui/settings_dialog.cpp
src/qt_gui/settings_dialog.h
src/qt_gui/settings_dialog.ui
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
src/qt_gui/hotkeys.h
src/qt_gui/hotkeys.cpp
src/qt_gui/hotkeys.ui
${EMULATOR}
${RESOURCE_FILES}
${TRANSLATIONS}
${UPDATER}
add_executable(shadps4
${AUDIO_CORE}
${IMGUI}
${INPUT}
${COMMON}
${CORE}
${SHADER_RECOMPILER}
${VIDEO_CORE}
${EMULATOR}
src/main.cpp
src/emulator.cpp
src/emulator.h
src/sdl_window.h
src/sdl_window.cpp
)
endif()
if (ENABLE_QT_GUI)
qt_add_executable(shadps4
${AUDIO_CORE}
${IMGUI}
${INPUT}
${QT_GUI}
${COMMON}
${CORE}
${SHADER_RECOMPILER}
${VIDEO_CORE}
${EMULATOR}
src/images/shadPS4.icns
)
else()
add_executable(shadps4
${AUDIO_CORE}
${IMGUI}
${INPUT}
${COMMON}
${CORE}
${SHADER_RECOMPILER}
${VIDEO_CORE}
${EMULATOR}
src/main.cpp
src/emulator.cpp
src/emulator.h
src/sdl_window.h
src/sdl_window.cpp
)
endif()
create_target_directory_groups(shadps4)
target_link_libraries(shadps4 PRIVATE magic_enum::magic_enum fmt::fmt toml11::toml11 tsl::robin_map xbyak::xbyak Tracy::TracyClient RenderDoc::API FFmpeg::ffmpeg Dear_ImGui gcn half::half ZLIB::ZLIB PNG::PNG)
target_link_libraries(shadps4 PRIVATE Boost::headers GPUOpen::VulkanMemoryAllocator LibAtrac9 sirit Vulkan::Headers xxHash::xxhash Zydis::Zydis glslang::glslang SDL3::SDL3 pugixml::pugixml stb::headers libusb::usb lfreist-hwinfo::hwinfo)
target_link_libraries(shadps4 PRIVATE Boost::headers GPUOpen::VulkanMemoryAllocator LibAtrac9 sirit Vulkan::Headers xxHash::xxhash Zydis::Zydis glslang::glslang SDL3::SDL3 SDL3_mixer::SDL3_mixer pugixml::pugixml)
target_link_libraries(shadps4 PRIVATE stb::headers libusb::usb lfreist-hwinfo::hwinfo nlohmann_json::nlohmann_json miniz)
target_compile_definitions(shadps4 PRIVATE IMGUI_USER_CONFIG="imgui/imgui_config.h")
target_compile_definitions(Dear_ImGui PRIVATE IMGUI_USER_CONFIG="${PROJECT_SOURCE_DIR}/src/imgui/imgui_config.h")
@@ -1174,22 +1105,11 @@ endif()
if (APPLE)
# Include MoltenVK, along with an ICD file so it can be found by the system Vulkan loader if used for loading layers.
if (ENABLE_QT_GUI)
set(MVK_BUNDLE_PATH "Resources/vulkan/icd.d")
set_property(TARGET shadps4 APPEND PROPERTY BUILD_RPATH "@executable_path/../${MVK_BUNDLE_PATH}")
set(MVK_DST ${CMAKE_CURRENT_BINARY_DIR}/shadps4.app/Contents/${MVK_BUNDLE_PATH})
add_custom_command(
OUTPUT ${MVK_DST}
COMMAND ${CMAKE_COMMAND} -E make_directory ${MVK_DST})
else()
set_property(TARGET shadps4 APPEND PROPERTY BUILD_RPATH "@executable_path")
set(MVK_DST ${CMAKE_CURRENT_BINARY_DIR})
endif()
set(MVK_DYLIB_SRC ${CMAKE_CURRENT_BINARY_DIR}/externals/MoltenVK/libMoltenVK.dylib)
set_property(TARGET shadps4 APPEND PROPERTY BUILD_RPATH "@executable_path")
set(MVK_DST ${CMAKE_CURRENT_BINARY_DIR})
set(MVK_DYLIB_SRC ${CMAKE_CURRENT_BINARY_DIR}/externals/MoltenVK/MoltenVK/libMoltenVK.dylib)
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_SRC ${CMAKE_CURRENT_SOURCE_DIR}/externals/MoltenVK/MoltenVK/icd/MoltenVK_icd.json)
set(MVK_ICD_DST ${MVK_DST}/MoltenVK_icd.json)
add_custom_command(
@@ -1206,38 +1126,30 @@ if (APPLE)
if (ARCHITECTURE STREQUAL "x86_64")
# Reserve system-managed memory space.
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)
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,-segaddr,USER_AREA,0x7000000000,-image_base,0x700000000000)
endif()
# Replacement for std::chrono::time_zone
target_link_libraries(shadps4 PRIVATE date::date-tz epoll-shim)
endif()
if (ENABLE_QT_GUI)
target_link_libraries(shadps4 PRIVATE Qt6::Widgets Qt6::Concurrent Qt6::Network Qt6::Multimedia)
add_definitions(-DENABLE_QT_GUI)
if (ENABLE_UPDATER)
add_definitions(-DENABLE_UPDATER)
endif()
endif()
if (WIN32)
target_link_libraries(shadps4 PRIVATE mincore)
target_link_libraries(shadps4 PRIVATE mincore wepoll wbemuuid)
if (MSVC)
# MSVC likes putting opinions on what people can use, disable:
add_definitions(-D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE -D_SCL_SECURE_NO_WARNINGS)
add_compile_definitions(_CRT_SECURE_NO_WARNINGS _CRT_NONSTDC_NO_DEPRECATE _SCL_SECURE_NO_WARNINGS)
endif()
add_definitions(-DNOMINMAX -DWIN32_LEAN_AND_MEAN)
add_compile_definitions(NOMINMAX WIN32_LEAN_AND_MEAN)
if (MSVC)
# Needed for conflicts with time.h of windows.h
add_definitions(-D_TIMESPEC_DEFINED)
add_compile_definitions(_TIMESPEC_DEFINED)
endif()
# Target Windows 10 RS5
add_definitions(-DNTDDI_VERSION=0x0A000006 -D_WIN32_WINNT=0x0A00 -DWINVER=0x0A00)
add_compile_definitions(NTDDI_VERSION=0x0A000006 _WIN32_WINNT=0x0A00 WINVER=0x0A00)
if (MSVC)
target_link_libraries(shadps4 PRIVATE clang_rt.builtins-x86_64.lib)
@@ -1256,13 +1168,20 @@ if (WIN32)
else()
target_link_options(shadps4 PRIVATE -Wl,--stack,2097152)
endif()
# Change base image address
if (MSVC)
target_link_options(shadps4 PRIVATE /BASE:0x700000000000)
else()
target_link_options(shadps4 PRIVATE -Wl,--image-base=0x700000000000)
endif()
endif()
if (WIN32)
target_sources(shadps4 PRIVATE src/shadps4.rc)
endif()
add_definitions(-DBOOST_ASIO_STANDALONE)
add_compile_definitions(BOOST_ASIO_STANDALONE)
target_include_directories(shadps4 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
@@ -1291,25 +1210,6 @@ add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src/imgui/renderer)
add_dependencies(shadps4 ImGui_Resources)
target_include_directories(shadps4 PRIVATE ${IMGUI_RESOURCES_INCLUDE})
if (ENABLE_QT_GUI)
set_target_properties(shadps4 PROPERTIES
# WIN32_EXECUTABLE ON
MACOSX_BUNDLE ON
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/dist/MacOSBundleInfo.plist.in"
MACOSX_BUNDLE_ICON_FILE "shadPS4.icns"
MACOSX_BUNDLE_SHORT_VERSION_STRING "${APP_VERSION}"
)
set_source_files_properties(src/images/shadPS4.icns PROPERTIES
MACOSX_PACKAGE_LOCATION Resources)
endif()
if (UNIX AND NOT APPLE)
if (ENABLE_QT_GUI)
find_package(OpenSSL REQUIRED)
target_link_libraries(shadps4 PRIVATE ${OPENSSL_LIBRARIES})
endif()
endif()
# Discord RPC
if (ENABLE_DISCORD_RPC)
@@ -1318,10 +1218,3 @@ endif()
# Install rules
install(TARGETS shadps4 BUNDLE DESTINATION .)
if (ENABLE_QT_GUI AND CMAKE_SYSTEM_NAME STREQUAL "Linux")
install(FILES "dist/net.shadps4.shadPS4.desktop" DESTINATION "share/applications")
install(FILES "dist/net.shadps4.shadPS4.metainfo.xml" DESTINATION "share/metainfo")
install(FILES ".github/shadps4.png" DESTINATION "share/icons/hicolor/512x512/apps" RENAME "net.shadps4.shadPS4.png")
install(FILES "src/images/net.shadps4.shadPS4.svg" DESTINATION "share/icons/hicolor/scalable/apps")
endif()

View File

@@ -15,15 +15,6 @@
"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",
@@ -32,15 +23,6 @@
"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",
@@ -48,15 +30,6 @@
"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,18 +12,6 @@
"inheritEnvironments": [ "clang_cl_x64_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",
"generator": "Ninja",
@@ -36,18 +24,6 @@
"inheritEnvironments": [ "clang_cl_x64_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",
"generator": "Ninja",
@@ -59,18 +35,6 @@
"ctestCommandArgs": "",
"inheritEnvironments": [ "clang_cl_x64_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"
}
]
}

View File

@@ -36,6 +36,9 @@ SPDX-License-Identifier: GPL-2.0-or-later
**shadPS4** is an early **PlayStation 4** emulator for **Windows**, **Linux** and **macOS** written in C++.
> [!IMPORTANT]
> This is the emulator core, which does not include a GUI. If you just want to use the emulator as an end user, download the [**QtLauncher**](https://github.com/shadps4-emu/shadps4-qtlauncher/releases) instead.
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-compatibility/shadps4-game-compatibility).\
To discuss shadPS4 development, suggest ideas or to ask for help, join our [**Discord server**](https://discord.gg/bFJxfftGW6).\
@@ -55,9 +58,6 @@ This project began for fun. Given our limited free time, it may take some time b
# Building
> [!IMPORTANT]
> If you want to use shadPS4 to play your games, you don't have to follow the build instructions, you can simply download the emulator from either the [**release tab**](https://github.com/shadps4-emu/shadPS4/releases) or the [**action tab**](https://github.com/shadps4-emu/shadPS4/actions).
## Windows
Check the build instructions for [**Windows**](https://github.com/shadps4-emu/shadPS4/blob/main/documents/building-windows.md).
@@ -73,6 +73,22 @@ Check the build instructions for [**macOS**](https://github.com/shadps4-emu/shad
> [!IMPORTANT]
> macOS users need at least macOS 15.4 to run shadPS4. Due to GPU issues there are currently heavy bugs on Intel Macs.
# Usage examples
> [!IMPORTANT]
> For a user-friendly GUI, download the [**QtLauncher**](https://github.com/shadps4-emu/shadps4-qtlauncher/releases).
To get the list of all available commands and also a more detailed description of what each command does, please refer to the `--help` flag's output.
Below is a list of commonly used command patterns:
```sh
shadPS4 CUSA00001 # Searches for a game folder called CUSA00001 in the list of game install folders, and boots it.
shadPS4 --fullscreen true --config-clean CUSA00001 # the game argument is always the last one,
shadPS4 -g CUSA00001 --fullscreen true --config-clean # ...unless manually specified otherwise.
shadPS4 /path/to/game.elf # Boots a PS4 ELF file directly. Useful if you want to boot an executable that is not named eboot.bin.
shadPS4 CUSA00001 -- -flag1 -flag2 # Passes '-flag1' and '-flag2' to the game executable in argv.
```
# Debugging and reporting issues
For more information on how to test, debug and report issues with the emulator or games, read the [**Debugging documentation**](https://github.com/shadps4-emu/shadPS4/blob/main/documents/Debugging/Debugging.md).
@@ -160,15 +176,6 @@ Logo is done by [**Xphalnos**](https://github.com/Xphalnos)
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 :)
# Translations
If you want to translate shadPS4 to your language we use [**Crowdin**](https://crowdin.com/project/shadps4-emulator).
# Contributors
<a href="https://github.com/shadps4-emu/shadPS4/graphs/contributors">
<img src="https://contrib.rocks/image?repo=shadps4-emu/shadPS4&max=24">
</a>
# Special Thanks

View File

@@ -5,13 +5,12 @@ path = [
"REUSE.toml",
"crowdin.yml",
"CMakeSettings.json",
"CMakeDarwinPresets.json",
"CMakeLinuxPresets.json",
"CMakeWindowsPresets.json",
"CMakePresets.json",
".github/FUNDING.yml",
".github/shadps4.png",
".github/workflows/scripts/update_translation.sh",
".github/workflows/update_translation.yml",
".gitmodules",
"dist/MacOSBundleInfo.plist.in",
"dist/net.shadps4.shadPS4.desktop",
@@ -75,9 +74,7 @@ path = [
"src/images/trophy.wav",
"src/images/hotkey.png",
"src/images/game_settings.png",
"src/shadps4.qrc",
"src/shadps4.rc",
"src/qt_gui/translations/update_translation.sh",
]
precedence = "aggregate"
SPDX-FileCopyrightText = "shadPS4 Emulator Project"
@@ -132,9 +129,4 @@ SPDX-License-Identifier = "MIT"
[[annotations]]
path = "src/video_core/host_shaders/fsr/*"
SPDX-FileCopyrightText = "Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved."
SPDX-License-Identifier = "MIT"
[[annotations]]
path = "dist/qt.conf"
SPDX-FileCopyrightText = "shadPS4 Emulator Project"
SPDX-License-Identifier = "GPL-2.0-or-later"
SPDX-License-Identifier = "MIT"

View File

@@ -1,28 +0,0 @@
# 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

@@ -1,3 +0,0 @@
files:
- source: /src/qt_gui/translations/en_US.ts
translation: /%original_path%/%locale_with_underscore%.ts

View File

@@ -18,25 +18,31 @@
<screenshots>
<screenshot type="default">
<image type="source" translate="no" >https://cdn.jsdelivr.net/gh/shadps4-emu/shadps4@main/documents/Screenshots/1.png</image>
<caption>Bloodborne</caption>
<caption>Bloodborne by From Software</caption>
</screenshot>
<screenshot>
<image type="source" translate="no">https://cdn.jsdelivr.net/gh/shadps4-emu/shadps4@main/documents/Screenshots/2.png</image>
<caption>Hatsune Miku: Project DIVA Future Tone</caption>
<caption>Hatsune Miku Project DIVA Future Tone by SEGA</caption>
</screenshot>
<screenshot>
<image type="source" translate="no">https://cdn.jsdelivr.net/gh/shadps4-emu/shadps4@main/documents/Screenshots/3.png</image>
<caption>Yakuza 0</caption>
<caption>Yakuza 0 by SEGA</caption>
</screenshot>
<screenshot>
<image type="source" translate="no">https://cdn.jsdelivr.net/gh/shadps4-emu/shadps4@main/documents/Screenshots/4.png</image>
<caption>Persona 4 Golden</caption>
<caption>DRIVECLUB™ by Evolution Studios</caption>
</screenshot>
</screenshots>
<categories>
<category translate="no">Game</category>
</categories>
<releases>
<release version="0.12.5" date="2025-11-07">
<url>https://github.com/shadps4-emu/shadPS4/releases/tag/v.0.12.5</url>
</release>
<release version="0.12.0" date="2025-10-31">
<url>https://github.com/shadps4-emu/shadPS4/releases/tag/v.0.12.0</url>
</release>
<release version="0.11.0" date="2025-09-18">
<url>https://github.com/shadps4-emu/shadPS4/releases/tag/v.0.11.0</url>
</release>

2
dist/qt.conf vendored
View File

@@ -1,2 +0,0 @@
[Paths]
plugins = "./qtplugins"

View File

@@ -11,6 +11,13 @@ This document covers information about debugging, troubleshooting and reporting
This section will guide you through setting up tools for debugging the emulator. This list will likely expand as more tools and platforms receive consistent setups.
<details>
<summary>Linux</summary>
RenderDoc doesn't work with Wayland, so to use it you have to run the emulator with `SDL_VIDEODRIVER=x11` set.
</details>
<details>
<summary>Windows and Visual Studio</summary>

View File

@@ -17,8 +17,7 @@ First and foremost, Clang 18 is the **recommended compiler** as it is used for o
sudo apt install build-essential clang git cmake libasound2-dev \
libpulse-dev libopenal-dev libssl-dev zlib1g-dev libedit-dev \
libudev-dev libevdev-dev libsdl2-dev libjack-dev libsndio-dev \
qt6-base-dev qt6-tools-dev qt6-multimedia-dev libvulkan-dev \
vulkan-validationlayers libpng-dev
libvulkan-dev vulkan-validationlayers libpng-dev
```
#### Fedora
@@ -27,8 +26,6 @@ sudo apt install build-essential clang git cmake libasound2-dev \
sudo dnf install clang git cmake libatomic alsa-lib-devel \
pipewire-jack-audio-connection-kit-devel openal-soft-devel \
openssl-devel libevdev-devel libudev-devel libXext-devel \
qt6-qtbase-devel qt6-qtbase-private-devel \
qt6-qtmultimedia-devel qt6-qtsvg-devel qt6-qttools-devel \
vulkan-devel vulkan-validation-layers libpng-devel libuuid-devel
```
@@ -36,8 +33,7 @@ sudo dnf install clang git cmake libatomic alsa-lib-devel \
```bash
sudo pacman -S base-devel clang git cmake sndio jack2 openal \
qt6-base qt6-declarative qt6-multimedia qt6-tools sdl2 \
vulkan-validation-layers libpng
sdl2 vulkan-validation-layers libpng
```
**Note**: The `shadps4-git` AUR package is not maintained by any of the developers, and it uses the default compiler, which is often set to GCC. Use at your own discretion.
@@ -48,9 +44,7 @@ sudo pacman -S base-devel clang git cmake sndio jack2 openal \
sudo zypper install clang git cmake libasound2 libpulse-devel \
libsndio7 libjack-devel openal-soft-devel libopenssl-devel \
zlib-devel libedit-devel systemd-devel libevdev-devel \
qt6-base-devel qt6-multimedia-devel qt6-svg-devel \
qt6-linguist-devel qt6-gui-private-devel vulkan-devel \
vulkan-validationlayers libpng-devel
vulkan-devel vulkan-validationlayers libpng-devel
```
#### NixOS
@@ -90,12 +84,12 @@ There are 3 options you can choose from. Option 1 is **highly recommended**.
1. Generate the build directory in the shadPS4 directory.
```bash
cmake -S . -B build/ -DENABLE_QT_GUI=ON -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
cmake -S . -B build/ -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
```
To disable the Qt GUI, remove the `-DENABLE_QT_GUI=ON` flag. To change the build type (for debugging), add `-DCMAKE_BUILD_TYPE=Debug`.
To change the build type (for debugging), add `-DCMAKE_BUILD_TYPE=Debug`.
2. Use CMake to build the project:
1. Use CMake to build the project:
```bash
cmake --build ./build --parallel$(nproc)
@@ -103,18 +97,12 @@ cmake --build ./build --parallel$(nproc)
If your computer freezes during this step, this could be caused by excessive system resource usage. In that case, remove `--parallel$(nproc)`.
Now run the emulator. If Qt was enabled at configure time:
Now run the emulator to get the list of options:
```bash
./build/shadps4
```
Otherwise, specify the path to your game's boot file:
```bash
./build/shadps4 /"PATH"/"TO"/"GAME"/"FOLDER"/eboot.bin
```
You can also specify the Game ID as an argument for which game to boot, as long as the folder containing the games is specified in config.toml (example: Bloodborne (US) is CUSA00900).
#### Option 2: Configuring with cmake-gui
@@ -142,10 +130,6 @@ Go to Settings, filter by `@ext:ms-vscode.cmake-tools configure` and disable thi
![image](https://raw.githubusercontent.com/shadps4-emu/shadPS4/refs/heads/main/documents/Screenshots/Linux/1.png)
If you wish to build with the Qt GUI, add `-DENABLE_QT_GUI=ON` to the configure arguments:
![image](https://raw.githubusercontent.com/shadps4-emu/shadPS4/refs/heads/main/documents/Screenshots/Linux/2.png)
On the CMake tab, change the options as you wish, but make sure that it looks similar to or exactly like this:
![image](https://raw.githubusercontent.com/shadps4-emu/shadPS4/refs/heads/main/documents/Screenshots/Linux/4.png)

View File

@@ -24,21 +24,6 @@ eval $(/opt/homebrew/bin/brew shellenv)
brew install clang-format cmake
```
Next, install x86_64 Qt. You can skip these steps and move on to **Cloning and compiling** if you do not intend to build the Qt GUI.
**If you are on an ARM Mac:**
```
# Installs x86_64 Homebrew to /usr/local
arch -x86_64 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# Installs libraries.
arch -x86_64 /usr/local/bin/brew install qt@6
```
**If you are on an x86_64 Mac:**
```
brew install qt@6
```
### Cloning and compiling:
Clone the repository recursively:
@@ -52,8 +37,6 @@ Generate the build directory in the shadPS4 directory:
cmake -S . -B build/ -DCMAKE_OSX_ARCHITECTURES=x86_64
```
If you want to build the Qt GUI, add `-DENABLE_QT_GUI=ON` to the end of this command as well.
Enter the directory:
```
cd build/

View File

@@ -1,12 +1,14 @@
<!--
SPDX-FileCopyrightText: 2024 shadPS4 Emulator Project
SPDX-FileCopyrightText: 2025 shadPS4 Emulator Project
SPDX-License-Identifier: GPL-2.0-or-later
-->
# Build shadPS4 for Windows
This tutorial reads as if you have none of the prerequisites already installed. If you do, just ignore the steps regarding installation.
If you are building to contribute to the project, please omit `--depth 1` from the git invocations.
> [!WARNING]
> If you are trying to compile older builds for testing, do not provide the `--depth 1` flag in `git clone`.
> This flag omits the commit history from your clone, saving storage space while preventing you from testing older commits.
Note: **ARM64 is not supported!** As of writing, it will not build nor run. The instructions with respect to ARM64 are for developers only.
@@ -20,23 +22,6 @@ Once you are within the installer:
2. Go to "Individual Components" tab then search and select both `C++ Clang Compiler for Windows` and `MSBuild support for LLVM`
3. Continue the installation
### (Prerequisite) Download [**Qt**](https://doc.qt.io/qt-6/get-and-install-qt.html)
Beware, this requires you to create a Qt account. If you do not want to do this, please follow the MSYS2/MinGW compilation method instead.
1. Under the current, non beta version of Qt, select the option `MSVC 2022 64-bit` or similar, as well as `QT Multimedia`.
If you are on Windows on ARM / Qualcomm Snapdragon Elite X, select `MSVC 2022 ARM64` instead.
Go through the installation normally. If you know what you are doing, you may unselect individual components that eat up too much disk space.
2. Download and install [Qt Visual Studio Tools](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.QtVisualStudioTools2022)
Once you are finished, you will have to configure Qt within Visual Studio:
1. Tools -> Options -> Qt -> Versions
2. Add a new Qt version and navigate it to the correct folder. Should look like so: `C:\Qt\<QtVersion>\msvc2022_64`
3. Enable the default checkmark on the new version you just created.
### (Prerequisite) Download [**Git for Windows**](https://git-scm.com/download/win)
Go through the Git for Windows installation as normal
@@ -51,16 +36,11 @@ Go through the Git for Windows installation as normal
1. Open up Visual Studio, select `Open a local folder` and select the folder with the shadPS4 source code. The folder should contain `CMakeLists.txt`
2. Change Clang x64 Debug to Clang x64 Release if you want a regular, non-debug build.
3. If you want to build shadPS4 with the Qt Gui, simply select Clang x64 Release with Qt instead.
4. Change the project to build to shadps4.exe
5. Build -> Build All
3. Change the project to build to shadps4.exe
4. Build -> Build All
Your shadps4.exe will be in `C:\path\to\source\Build\x64-Clang-Release\`
To automatically populate the necessary files to run shadPS4.exe, run in a command prompt or terminal:
`C:\Qt\<QtVersion>\msvc2022_64\bin\windeployqt6.exe "C:\path\to\shadps4.exe"`
(Change Qt path if you've installed it to non-default path)
## Option 2: MSYS2/MinGW
> [!IMPORTANT]
@@ -77,13 +57,10 @@ Normal x86-based computers, follow:
1. Open "MSYS2 MINGW64" from your new applications
2. Run `pacman -Syu`, let it complete;
3. Run `pacman -S --needed git mingw-w64-x86_64-binutils mingw-w64-x86_64-clang mingw-w64-x86_64-cmake mingw-w64-x86_64-rapidjson mingw-w64-x86_64-ninja mingw-w64-x86_64-ffmpeg`
1. Optional (Qt only): run `pacman -S --needed mingw-w64-x86_64-qt6-base mingw-w64-x86_64-qt6-tools mingw-w64-x86_64-qt6-multimedia`
4. Run `git clone --depth 1 --recursive https://github.com/shadps4-emu/shadPS4`
5. Run `cd shadPS4`
6. Run `cmake -S . -B build -DCMAKE_C_COMPILER="clang.exe" -DCMAKE_CXX_COMPILER="clang++.exe" -DCMAKE_CXX_FLAGS="-O2 -march=native"`
1. Optional (Qt only): add `-DENABLE_QT_GUI=ON`
7. Run `cmake --build build`
1. Optional (Qt only): run `windeployqt6 build/shadps4.exe`
8. To run the finished product, run `./build/shadPS4.exe`
ARM64-based computers, follow:
@@ -91,13 +68,10 @@ ARM64-based computers, follow:
1. Open "MSYS2 CLANGARM64" from your new applications
2. Run `pacman -Syu`, let it complete;
3. Run `pacman -S --needed git mingw-w64-clang-aarch64-binutils mingw-w64-clang-aarch64-clang mingw-w64-clang-aarch64-rapidjson mingw-w64-clang-aarch64-cmake mingw-w64-clang-aarch64-ninja mingw-w64-clang-aarch64-ffmpeg`
1. Optional (Qt only): run `pacman -S --needed mingw-w64-clang-aarch64-qt6-base mingw-w64-clang-aarch64-qt6-tools mingw-w64-clang-aarch64-qt6-multimedia`
4. Run `git clone --depth 1 --recursive https://github.com/shadps4-emu/shadPS4`
5. Run `cd shadPS4`
6. Run `cmake -S . -B build -DCMAKE_C_COMPILER="clang.exe" -DCMAKE_CXX_COMPILER="clang++.exe" -DCMAKE_CXX_FLAGS="-O2 -march=native"`
1. Optional (Qt only): add `-DENABLE_QT_GUI=ON`
7. Run `cmake --build build`
1. Optional (Qt only): run `windeployqt6 build/shadps4.exe`
8. To run the finished product, run `./build/shadPS4.exe`
## Note on MSYS2 builds

View File

@@ -63,6 +63,18 @@ if (NOT TARGET SDL3::SDL3)
add_subdirectory(sdl3)
endif()
# SDL3_mixer
if (NOT TARGET SDL3_mixer::SDL3_mixer)
set(SDLMIXER_FLAC OFF)
set(SDLMIXER_OGG OFF)
set(SDLMIXER_MOD OFF)
set(SDLMIXER_MIDI OFF)
set(SDLMIXER_OPUS OFF)
set(SDLMIXER_WAVPACK OFF)
set(BUILD_SHARED_LIBS OFF)
add_subdirectory(sdl3_mixer)
endif()
# vulkan-headers
if (NOT TARGET Vulkan::Headers)
set(VULKAN_HEADERS_ENABLE_MODULE OFF)
@@ -140,7 +152,7 @@ endif()
# sirit
add_subdirectory(sirit)
if (WIN32)
target_compile_options(sirit PUBLIC "-Wno-error=unused-command-line-argument")
target_compile_options(sirit PRIVATE "-Wno-error=unused-command-line-argument")
endif()
# half
@@ -231,6 +243,8 @@ if (APPLE)
# MoltenVK
if (NOT TARGET MoltenVK)
set(MVK_EXCLUDE_SPIRV_TOOLS ON)
set(MVK_USE_METAL_PRIVATE_API ON)
add_subdirectory(MoltenVK)
endif()
@@ -238,3 +252,15 @@ if (APPLE)
add_subdirectory(epoll-shim)
endif()
endif()
#windows only
if (WIN32)
add_subdirectory(ext-wepoll)
endif()
#nlohmann json
set(JSON_BuildTests OFF CACHE INTERNAL "")
add_subdirectory(json)
# miniz
add_subdirectory(miniz)

1
externals/MoltenVK vendored Submodule

Submodule externals/MoltenVK added at f168dec059

View File

@@ -1,93 +0,0 @@
# SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
# Prepare MoltenVK Git revision
find_package(Git)
if(GIT_FOUND)
execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD
OUTPUT_VARIABLE MVK_GIT_REV
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)
endif()
set(MVK_GENERATED_INCLUDES ${CMAKE_CURRENT_BINARY_DIR}/Generated)
file(WRITE ${MVK_GENERATED_INCLUDES}/mvkGitRevDerived.h "static const char* mvkRevString = \"${MVK_GIT_REV}\";")
message(STATUS "MoltenVK revision: ${MVK_GIT_REV}")
# Prepare MoltenVK version
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK/MoltenVK/MoltenVK/API/mvk_private_api.h MVK_PRIVATE_API)
string(REGEX MATCH "#define MVK_VERSION_MAJOR [0-9]+" MVK_VERSION_MAJOR_LINE "${MVK_PRIVATE_API}")
string(REGEX MATCH "[0-9]+" MVK_VERSION_MAJOR "${MVK_VERSION_MAJOR_LINE}")
string(REGEX MATCH "#define MVK_VERSION_MINOR [0-9]+" MVK_VERSION_MINOR_LINE "${MVK_PRIVATE_API}")
string(REGEX MATCH "[0-9]+" MVK_VERSION_MINOR "${MVK_VERSION_MINOR_LINE}")
string(REGEX MATCH "#define MVK_VERSION_PATCH [0-9]+" MVK_VERSION_PATCH_LINE "${MVK_PRIVATE_API}")
string(REGEX MATCH "[0-9]+" MVK_VERSION_PATCH "${MVK_VERSION_PATCH_LINE}")
set(MVK_VERSION "${MVK_VERSION_MAJOR}.${MVK_VERSION_MINOR}.${MVK_VERSION_PATCH}")
message(STATUS "MoltenVK version: ${MVK_VERSION}")
# Find required system libraries
find_library(APPKIT_LIBRARY AppKit REQUIRED)
find_library(FOUNDATION_LIBRARY Foundation REQUIRED)
find_library(IOKIT_LIBRARY IOKit REQUIRED)
find_library(IOSURFACE_LIBRARY IOSurface REQUIRED)
find_library(METAL_LIBRARY Metal REQUIRED)
find_library(QUARTZCORE_LIBRARY QuartzCore REQUIRED)
# cereal
option(SKIP_PORTABILITY_TEST "" ON)
option(BUILD_DOC "" OFF)
option(BUILD_SANDBOX "" OFF)
option(SKIP_PERFORMANCE_COMPARISON "" ON)
option(SPIRV_CROSS_SKIP_INSTALL "" ON)
add_subdirectory(cereal)
# SPIRV-Cross
option(SPIRV_CROSS_CLI "" OFF)
option(SPIRV_CROSS_ENABLE_TESTS "" OFF)
option(SPIRV_CROSS_ENABLE_HLSL "" OFF)
option(SPIRV_CROSS_ENABLE_CPP "" OFF)
option(SPIRV_CROSS_SKIP_INSTALL "" ON)
add_subdirectory(SPIRV-Cross)
# Common
set(MVK_COMMON_DIR ${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK/Common)
file(GLOB_RECURSE MVK_COMMON_SOURCES CONFIGURE_DEPENDS
${MVK_COMMON_DIR}/*.cpp
${MVK_COMMON_DIR}/*.m
${MVK_COMMON_DIR}/*.mm)
set(MVK_COMMON_INCLUDES ${MVK_COMMON_DIR})
add_library(MoltenVKCommon STATIC ${MVK_COMMON_SOURCES})
target_include_directories(MoltenVKCommon PUBLIC ${MVK_COMMON_INCLUDES})
target_compile_options(MoltenVKCommon PRIVATE -w)
# MoltenVKShaderConverter
set(MVK_SHADER_CONVERTER_DIR ${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK/MoltenVKShaderConverter)
file(GLOB_RECURSE MVK_SHADER_CONVERTER_SOURCES CONFIGURE_DEPENDS
${MVK_SHADER_CONVERTER_DIR}/MoltenVKShaderConverter/*.cpp
${MVK_SHADER_CONVERTER_DIR}/MoltenVKShaderConverter/*.m
${MVK_SHADER_CONVERTER_DIR}/MoltenVKShaderConverter/*.mm)
set(MVK_SHADER_CONVERTER_INCLUDES ${MVK_SHADER_CONVERTER_DIR} ${MVK_SHADER_CONVERTER_DIR}/include)
add_library(MoltenVKShaderConverter STATIC ${MVK_SHADER_CONVERTER_SOURCES})
target_include_directories(MoltenVKShaderConverter PUBLIC ${MVK_SHADER_CONVERTER_INCLUDES})
target_compile_options(MoltenVKShaderConverter PRIVATE -w)
target_link_libraries(MoltenVKShaderConverter PRIVATE spirv-cross-msl spirv-cross-reflect MoltenVKCommon)
target_compile_definitions(MoltenVKShaderConverter PRIVATE MVK_EXCLUDE_SPIRV_TOOLS=1)
# MoltenVK
set(MVK_DIR ${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK/MoltenVK)
file(GLOB_RECURSE MVK_SOURCES CONFIGURE_DEPENDS
${MVK_DIR}/MoltenVK/*.cpp
${MVK_DIR}/MoltenVK/*.m
${MVK_DIR}/MoltenVK/*.mm)
file(GLOB MVK_SRC_INCLUDES LIST_DIRECTORIES ON ${MVK_DIR}/MoltenVK/*)
set(MVK_INCLUDES ${MVK_SRC_INCLUDES} ${MVK_GENERATED_INCLUDES} ${MVK_DIR}/include)
add_library(MoltenVK SHARED ${MVK_SOURCES})
target_include_directories(MoltenVK PRIVATE ${MVK_INCLUDES})
target_compile_options(MoltenVK PRIVATE -w)
target_link_libraries(MoltenVK PRIVATE
${APPKIT_LIBRARY} ${FOUNDATION_LIBRARY} ${IOKIT_LIBRARY} ${IOSURFACE_LIBRARY} ${METAL_LIBRARY} ${QUARTZCORE_LIBRARY}
Vulkan::Headers cereal::cereal spirv-cross-msl MoltenVKCommon MoltenVKShaderConverter)
target_compile_definitions(MoltenVK PRIVATE MVK_FRAMEWORK_VERSION=${MVK_VERSION} MVK_USE_METAL_PRIVATE_API=1)

1
externals/ext-wepoll vendored Submodule

Submodule externals/ext-wepoll added at d3bb810353

1
externals/json vendored Submodule

Submodule externals/json added at 55f93686c0

1
externals/miniz vendored Submodule

Submodule externals/miniz added at 174573d602

1
externals/sdl3_mixer vendored Submodule

Submodule externals/sdl3_mixer added at 4182794ea4

View File

@@ -6,54 +6,47 @@ with import (fetchTarball "https://github.com/nixos/nixpkgs/archive/cfd19cdc5468
pkgs.mkShell {
name = "shadps4-build-env";
nativeBuildInputs = [
pkgs.llvmPackages_18.clang
pkgs.cmake
pkgs.pkg-config
pkgs.git
nativeBuildInputs = with pkgs; [
llvmPackages_18.clang
cmake
pkg-config
git
util-linux
];
buildInputs = [
pkgs.alsa-lib
pkgs.libpulseaudio
pkgs.openal
pkgs.openssl
pkgs.zlib
pkgs.libedit
pkgs.udev
pkgs.libevdev
pkgs.SDL2
pkgs.jack2
pkgs.sndio
pkgs.qt6.qtbase
pkgs.qt6.qttools
pkgs.qt6.qtmultimedia
buildInputs = with pkgs; [
alsa-lib
libpulseaudio
openal
zlib
libedit
udev
libevdev
SDL2
jack2
sndio
pkgs.vulkan-headers
pkgs.vulkan-utility-libraries
pkgs.vulkan-tools
vulkan-headers
vulkan-utility-libraries
vulkan-tools
pkgs.ffmpeg
pkgs.fmt
pkgs.glslang
pkgs.libxkbcommon
pkgs.wayland
pkgs.xorg.libxcb
pkgs.xorg.xcbutil
pkgs.xorg.xcbutilkeysyms
pkgs.xorg.xcbutilwm
pkgs.sdl3
pkgs.stb
pkgs.qt6.qtwayland
pkgs.wayland-protocols
pkgs.libpng
ffmpeg
fmt
glslang
libxkbcommon
wayland
xorg.libxcb
xorg.xcbutil
xorg.xcbutilkeysyms
xorg.xcbutilwm
sdl3
stb
wayland-protocols
libpng
];
shellHook = ''
echo "Entering shadPS4 dev shell"
export QT_QPA_PLATFORM="wayland"
export QT_PLUGIN_PATH="${pkgs.qt6.qtwayland}/lib/qt-6/plugins:${pkgs.qt6.qtbase}/lib/qt-6/plugins"
export QML2_IMPORT_PATH="${pkgs.qt6.qtbase}/lib/qt-6/qml"
export CMAKE_PREFIX_PATH="${pkgs.vulkan-headers}:$CMAKE_PREFIX_PATH"
# OpenGL

View File

@@ -8,6 +8,7 @@
#include <fmt/xchar.h> // for wstring support
#include <toml.hpp>
#include "common/assert.h"
#include "common/config.h"
#include "common/logging/formatter.h"
#include "common/path_util.h"
@@ -74,18 +75,34 @@ std::optional<T> get_optional(const toml::value& v, const std::string& key) {
namespace Config {
ConfigMode config_mode = ConfigMode::Default;
void setConfigMode(ConfigMode mode) {
config_mode = mode;
}
template <typename T>
class ConfigEntry {
public:
const T default_value;
T base_value;
optional<T> game_specific_value;
ConfigEntry(const T& t = T()) : base_value(t), game_specific_value(nullopt) {}
ConfigEntry(const T& t = T()) : default_value(t), base_value(t), game_specific_value(nullopt) {}
ConfigEntry operator=(const T& t) {
base_value = t;
return *this;
}
const T get() const {
return game_specific_value.has_value() ? *game_specific_value : base_value;
switch (config_mode) {
case ConfigMode::Default:
return game_specific_value.value_or(base_value);
case ConfigMode::Global:
return base_value;
case ConfigMode::Clean:
return default_value;
default:
UNREACHABLE();
}
}
void setFromToml(const toml::value& v, const std::string& key, bool is_game_specific = false) {
if (is_game_specific) {
@@ -115,19 +132,18 @@ public:
static ConfigEntry<int> volumeSlider(100);
static ConfigEntry<bool> isNeo(false);
static ConfigEntry<bool> isDevKit(false);
static ConfigEntry<int> extraDmemInMbytes(0);
static ConfigEntry<bool> isPSNSignedIn(false);
static ConfigEntry<bool> isTrophyPopupDisabled(false);
static ConfigEntry<double> trophyNotificationDuration(6.0);
static ConfigEntry<string> logFilter("");
static ConfigEntry<string> logType("sync");
static ConfigEntry<string> userName("shadPS4");
static ConfigEntry<string> chooseHomeTab("General");
static ConfigEntry<bool> isShowSplash(false);
static ConfigEntry<string> isSideTrophy("right");
static ConfigEntry<bool> isConnectedToNetwork(false);
static bool enableDiscordRPC = false;
static bool checkCompatibilityOnStartup = false;
static bool compatibilityData = false;
static std::filesystem::path sys_modules_path = {};
// Input
static ConfigEntry<int> cursorState(HideCursorState::Idle);
@@ -161,29 +177,32 @@ static ConfigEntry<bool> isFullscreen(false);
static ConfigEntry<string> fullscreenMode("Windowed");
static ConfigEntry<string> presentMode("Mailbox");
static ConfigEntry<bool> isHDRAllowed(false);
static ConfigEntry<bool> fsrEnabled(true);
static ConfigEntry<bool> fsrEnabled(false);
static ConfigEntry<bool> rcasEnabled(true);
static ConfigEntry<int> rcasAttenuation(250);
// Vulkan
static ConfigEntry<s32> gpuId(-1);
static ConfigEntry<bool> vkValidation(false);
static ConfigEntry<bool> vkValidationCore(true);
static ConfigEntry<bool> vkValidationSync(false);
static ConfigEntry<bool> vkValidationGpu(false);
static ConfigEntry<bool> vkCrashDiagnostic(false);
static ConfigEntry<bool> vkHostMarkers(false);
static ConfigEntry<bool> vkGuestMarkers(false);
static ConfigEntry<bool> rdocEnable(false);
static ConfigEntry<bool> pipelineCacheEnable(false);
static ConfigEntry<bool> pipelineCacheArchive(false);
// Debug
static ConfigEntry<bool> isDebugDump(false);
static ConfigEntry<bool> isShaderDebug(false);
static ConfigEntry<bool> isSeparateLogFilesEnabled(false);
static ConfigEntry<bool> isFpsColor(true);
static ConfigEntry<bool> showFpsCounter(false);
static ConfigEntry<bool> logEnabled(true);
// GUI
static bool load_game_size = true;
static std::vector<GameInstallDir> settings_install_dirs = {};
std::vector<bool> install_dirs_enabled = {};
std::filesystem::path settings_addon_install_dir = {};
@@ -192,15 +211,39 @@ std::filesystem::path save_data_path = {};
// Settings
ConfigEntry<u32> m_language(1); // english
// USB Device
static ConfigEntry<int> usbDeviceBackend(UsbBackendType::Real);
// Keys
static string trophyKey = "";
// Config version, used to determine if a user's config file is outdated.
static string config_version = Common::g_scm_rev;
// These two entries aren't stored in the config
// These entries aren't stored in the config
static bool overrideControllerColor = false;
static int controllerCustomColorRGB[3] = {0, 0, 255};
static bool isGameRunning = false;
static bool load_auto_patches = true;
bool getGameRunning() {
return isGameRunning;
}
void setGameRunning(bool running) {
isGameRunning = running;
}
std::filesystem::path getSysModulesPath() {
if (sys_modules_path.empty()) {
return Common::FS::GetUserPath(Common::FS::PathType::SysModuleDir);
}
return sys_modules_path;
}
void setSysModulesPath(const std::filesystem::path& path) {
sys_modules_path = path;
}
int getVolumeSlider() {
return volumeSlider.get();
@@ -247,10 +290,6 @@ void setTrophyKey(string key) {
trophyKey = key;
}
bool GetLoadGameSizeEnabled() {
return load_game_size;
}
std::filesystem::path GetSaveDataPath() {
if (save_data_path.empty()) {
return Common::FS::GetUserPath(Common::FS::PathType::UserDir) / "savedata";
@@ -262,10 +301,6 @@ void setVolumeSlider(int volumeValue, bool is_game_specific) {
volumeSlider.set(volumeValue, is_game_specific);
}
void setLoadGameSizeEnabled(bool enable) {
load_game_size = enable;
}
bool isNeoModeConsole() {
return isNeo.get();
}
@@ -274,6 +309,16 @@ bool isDevKitConsole() {
return isDevKit.get();
}
int getExtraDmemInMbytes() {
return extraDmemInMbytes.get();
}
void setExtraDmemInMbytes(int value, bool is_game_specific) {
// Disable setting in global config
is_game_specific ? extraDmemInMbytes.game_specific_value = value
: extraDmemInMbytes.base_value = 0;
}
bool getIsFullscreen() {
return isFullscreen.get();
}
@@ -350,10 +395,6 @@ string getUserName() {
return userName.get();
}
string getChooseHomeTab() {
return chooseHomeTab.get();
}
bool getUseSpecialPad() {
return useSpecialPad.get();
}
@@ -414,10 +455,26 @@ bool isRdocEnabled() {
return rdocEnable.get();
}
bool isPipelineCacheEnabled() {
return pipelineCacheEnable.get();
}
bool isPipelineCacheArchived() {
return pipelineCacheArchive.get();
}
bool fpsColor() {
return isFpsColor.get();
}
bool getShowFpsCounter() {
return showFpsCounter.get();
}
void setShowFpsCounter(bool enable, bool is_game_specific) {
showFpsCounter.set(enable, is_game_specific);
}
bool isLoggingEnabled() {
return logEnabled.get();
}
@@ -433,6 +490,10 @@ bool vkValidationEnabled() {
return vkValidation.get();
}
bool vkValidationCoreEnabled() {
return vkValidationCore.get();
}
bool vkValidationSyncEnabled() {
return vkValidationSync.get();
}
@@ -465,14 +526,6 @@ void setVkGuestMarkersEnabled(bool enable, bool is_game_specific) {
vkGuestMarkers.set(enable, is_game_specific);
}
bool getCompatibilityEnabled() {
return compatibilityData;
}
bool getCheckCompatibilityOnStartup() {
return checkCompatibilityOnStartup;
}
bool getIsConnectedToNetwork() {
return isConnectedToNetwork.get();
}
@@ -557,10 +610,26 @@ void setVkSyncValidation(bool enable, bool is_game_specific) {
vkValidationSync.set(enable, is_game_specific);
}
void setVkCoreValidation(bool enable, bool is_game_specific) {
vkValidationCore.set(enable, is_game_specific);
}
void setVkGpuValidation(bool enable, bool is_game_specific) {
vkValidationGpu.set(enable, is_game_specific);
}
void setRdocEnabled(bool enable, bool is_game_specific) {
rdocEnable.set(enable, is_game_specific);
}
void setPipelineCacheEnabled(bool enable, bool is_game_specific) {
pipelineCacheEnable.set(enable, is_game_specific);
}
void setPipelineCacheArchived(bool enable, bool is_game_specific) {
pipelineCacheArchive.set(enable, is_game_specific);
}
void setVblankFreq(u32 value, bool is_game_specific) {
vblankFrequency.set(value, is_game_specific);
}
@@ -637,10 +706,6 @@ void setUserName(const string& name, bool is_game_specific) {
userName.set(name, is_game_specific);
}
void setChooseHomeTab(const string& type, bool is_game_specific) {
chooseHomeTab.set(type, is_game_specific);
}
void setUseSpecialPad(bool use) {
useSpecialPad.base_value = use;
}
@@ -653,14 +718,6 @@ void setIsMotionControlsEnabled(bool use, bool is_game_specific) {
isMotionControlsEnabled.set(use, is_game_specific);
}
void setCompatibilityEnabled(bool use) {
compatibilityData = use;
}
void setCheckCompatibilityOnStartup(bool use) {
checkCompatibilityOnStartup = use;
}
bool addGameInstallDir(const std::filesystem::path& dir, bool enabled) {
for (const auto& install_dir : settings_install_dirs) {
if (install_dir.path == dir) {
@@ -790,6 +847,21 @@ void setRcasAttenuation(int value, bool is_game_specific) {
rcasAttenuation.set(value, is_game_specific);
}
int getUsbDeviceBackend() {
return usbDeviceBackend.get();
}
void setUsbDeviceBackend(int value, bool is_game_specific) {
usbDeviceBackend.set(value, is_game_specific);
}
bool getLoadAutoPatches() {
return load_auto_patches;
}
void setLoadAutoPatches(bool enable) {
load_auto_patches = enable;
}
void load(const std::filesystem::path& path, bool is_game_specific) {
// If the configuration file does not exist, create it and return, unless it is game specific
std::error_code error;
@@ -818,6 +890,9 @@ void load(const std::filesystem::path& path, bool is_game_specific) {
volumeSlider.setFromToml(general, "volumeSlider", is_game_specific);
isNeo.setFromToml(general, "isPS4Pro", is_game_specific);
isDevKit.setFromToml(general, "isDevKit", is_game_specific);
if (is_game_specific) { // do not get this value from the base config
extraDmemInMbytes.setFromToml(general, "extraDmemInMbytes", is_game_specific);
}
isPSNSignedIn.setFromToml(general, "isPSNSignedIn", is_game_specific);
isTrophyPopupDisabled.setFromToml(general, "isTrophyPopupDisabled", is_game_specific);
trophyNotificationDuration.setFromToml(general, "trophyNotificationDuration",
@@ -828,13 +903,10 @@ void load(const std::filesystem::path& path, bool is_game_specific) {
userName.setFromToml(general, "userName", is_game_specific);
isShowSplash.setFromToml(general, "showSplash", is_game_specific);
isSideTrophy.setFromToml(general, "sideTrophy", is_game_specific);
compatibilityData = toml::find_or<bool>(general, "compatibilityEnabled", compatibilityData);
checkCompatibilityOnStartup = toml::find_or<bool>(general, "checkCompatibilityOnStartup",
checkCompatibilityOnStartup);
isConnectedToNetwork.setFromToml(general, "isConnectedToNetwork", is_game_specific);
chooseHomeTab.setFromToml(general, "chooseHomeTab", is_game_specific);
defaultControllerID.setFromToml(general, "defaultControllerID", is_game_specific);
sys_modules_path = toml::find_fs_path_or(general, "sysModulesPath", sys_modules_path);
}
if (data.contains("Input")) {
@@ -847,6 +919,7 @@ void load(const std::filesystem::path& path, bool is_game_specific) {
isMotionControlsEnabled.setFromToml(input, "isMotionControlsEnabled", is_game_specific);
useUnifiedInputConfig.setFromToml(input, "useUnifiedInputConfig", is_game_specific);
backgroundControllerInput.setFromToml(input, "backgroundControllerInput", is_game_specific);
usbDeviceBackend.setFromToml(input, "usbDeviceBackend", is_game_specific);
}
if (data.contains("Audio")) {
@@ -886,12 +959,15 @@ void load(const std::filesystem::path& path, bool is_game_specific) {
gpuId.setFromToml(vk, "gpuId", is_game_specific);
vkValidation.setFromToml(vk, "validation", is_game_specific);
vkValidationCore.setFromToml(vk, "validation_core", is_game_specific);
vkValidationSync.setFromToml(vk, "validation_sync", is_game_specific);
vkValidationGpu.setFromToml(vk, "validation_gpu", is_game_specific);
vkCrashDiagnostic.setFromToml(vk, "crashDiagnostic", is_game_specific);
vkHostMarkers.setFromToml(vk, "hostMarkers", is_game_specific);
vkGuestMarkers.setFromToml(vk, "guestMarkers", is_game_specific);
rdocEnable.setFromToml(vk, "rdocEnable", is_game_specific);
pipelineCacheEnable.setFromToml(vk, "pipelineCacheEnable", is_game_specific);
pipelineCacheArchive.setFromToml(vk, "pipelineCacheArchive", is_game_specific);
}
string current_version = {};
@@ -902,6 +978,7 @@ void load(const std::filesystem::path& path, bool is_game_specific) {
isSeparateLogFilesEnabled.setFromToml(debug, "isSeparateLogFilesEnabled", is_game_specific);
isShaderDebug.setFromToml(debug, "CollectShader", is_game_specific);
isFpsColor.setFromToml(debug, "FPSColor", is_game_specific);
showFpsCounter.setFromToml(debug, "showFpsCounter", is_game_specific);
logEnabled.setFromToml(debug, "logEnabled", is_game_specific);
current_version = toml::find_or<std::string>(debug, "ConfigVersion", current_version);
}
@@ -909,8 +986,6 @@ void load(const std::filesystem::path& path, bool is_game_specific) {
if (data.contains("GUI")) {
const toml::value& gui = data.at("GUI");
load_game_size = toml::find_or<bool>(gui, "loadGameSizeEnabled", load_game_size);
const auto install_dir_array =
toml::find_or<std::vector<std::u8string>>(gui, "installDirs", {});
@@ -955,8 +1030,8 @@ void load(const std::filesystem::path& path, bool is_game_specific) {
void sortTomlSections(toml::ordered_value& data) {
toml::ordered_value ordered_data;
std::vector<string> section_order = {"General", "Input", "GPU", "Vulkan",
"Debug", "Keys", "GUI", "Settings"};
std::vector<string> section_order = {"General", "Input", "Audio", "GPU", "Vulkan",
"Debug", "Keys", "GUI", "Settings"};
for (const auto& section : section_order) {
if (data.contains(section)) {
@@ -1014,11 +1089,13 @@ void save(const std::filesystem::path& path, bool is_game_specific) {
logFilter.setTomlValue(data, "General", "logFilter", is_game_specific);
logType.setTomlValue(data, "General", "logType", is_game_specific);
userName.setTomlValue(data, "General", "userName", is_game_specific);
chooseHomeTab.setTomlValue(data, "General", "chooseHomeTab", is_game_specific);
isShowSplash.setTomlValue(data, "General", "showSplash", is_game_specific);
isSideTrophy.setTomlValue(data, "General", "sideTrophy", is_game_specific);
isNeo.setTomlValue(data, "General", "isPS4Pro", is_game_specific);
isDevKit.setTomlValue(data, "General", "isDevKit", is_game_specific);
if (is_game_specific) {
extraDmemInMbytes.setTomlValue(data, "General", "extraDmemInMbytes", is_game_specific);
}
isPSNSignedIn.setTomlValue(data, "General", "isPSNSignedIn", is_game_specific);
isConnectedToNetwork.setTomlValue(data, "General", "isConnectedToNetwork", is_game_specific);
@@ -1028,6 +1105,7 @@ void save(const std::filesystem::path& path, bool is_game_specific) {
is_game_specific);
backgroundControllerInput.setTomlValue(data, "Input", "backgroundControllerInput",
is_game_specific);
usbDeviceBackend.setTomlValue(data, "Input", "usbDeviceBackend", is_game_specific);
micDevice.setTomlValue(data, "Audio", "micDevice", is_game_specific);
mainOutputDevice.setTomlValue(data, "Audio", "mainOutputDevice", is_game_specific);
@@ -1053,10 +1131,14 @@ void save(const std::filesystem::path& path, bool is_game_specific) {
gpuId.setTomlValue(data, "Vulkan", "gpuId", is_game_specific);
vkValidation.setTomlValue(data, "Vulkan", "validation", is_game_specific);
vkValidationSync.setTomlValue(data, "Vulkan", "validation_sync", is_game_specific);
vkValidationCore.setTomlValue(data, "Vulkan", "validation_core", is_game_specific);
vkValidationGpu.setTomlValue(data, "Vulkan", "validation_gpu", is_game_specific);
vkCrashDiagnostic.setTomlValue(data, "Vulkan", "crashDiagnostic", is_game_specific);
vkHostMarkers.setTomlValue(data, "Vulkan", "hostMarkers", is_game_specific);
vkGuestMarkers.setTomlValue(data, "Vulkan", "guestMarkers", is_game_specific);
rdocEnable.setTomlValue(data, "Vulkan", "rdocEnable", is_game_specific);
pipelineCacheEnable.setTomlValue(data, "Vulkan", "pipelineCacheEnable", is_game_specific);
pipelineCacheArchive.setTomlValue(data, "Vulkan", "pipelineCacheArchive", is_game_specific);
isDebugDump.setTomlValue(data, "Debug", "DebugDump", is_game_specific);
isShaderDebug.setTomlValue(data, "Debug", "CollectShader", is_game_specific);
@@ -1098,12 +1180,10 @@ void save(const std::filesystem::path& path, bool is_game_specific) {
// Non game-specific entries
data["General"]["enableDiscordRPC"] = enableDiscordRPC;
data["General"]["compatibilityEnabled"] = compatibilityData;
data["General"]["checkCompatibilityOnStartup"] = checkCompatibilityOnStartup;
data["General"]["sysModulesPath"] = string{fmt::UTF(sys_modules_path.u8string()).data};
data["GUI"]["installDirs"] = install_dirs;
data["GUI"]["installDirsEnabled"] = install_dirs_enabled;
data["GUI"]["saveDataPath"] = string{fmt::UTF(save_data_path.u8string()).data};
data["GUI"]["loadGameSizeEnabled"] = load_game_size;
data["GUI"]["addonInstallDir"] =
string{fmt::UTF(settings_addon_install_dir.u8string()).data};
data["Debug"]["ConfigVersion"] = config_version;
@@ -1117,8 +1197,8 @@ void save(const std::filesystem::path& path, bool is_game_specific) {
data["GPU"]["internalScreenWidth"] = internalScreenWidth.base_value;
data["GPU"]["internalScreenHeight"] = internalScreenHeight.base_value;
data["GPU"]["patchShaders"] = shouldPatchShaders.base_value;
data["Vulkan"]["validation_gpu"] = vkValidationGpu.base_value;
data["Debug"]["FPSColor"] = isFpsColor.base_value;
data["Debug"]["showFpsCounter"] = showFpsCounter.base_value;
}
// Sorting of TOML sections
@@ -1141,6 +1221,7 @@ void setDefaultValues(bool is_game_specific) {
isPSNSignedIn.set(false, is_game_specific);
isConnectedToNetwork.set(false, is_game_specific);
directMemoryAccessEnabled.set(false, is_game_specific);
extraDmemInMbytes.set(0, is_game_specific);
}
// Entries with game-specific settings that are in both the game-specific and global GUI
@@ -1151,7 +1232,6 @@ void setDefaultValues(bool is_game_specific) {
logFilter.set("", is_game_specific);
logType.set("sync", is_game_specific);
userName.set("shadPS4", is_game_specific);
chooseHomeTab.set("General", is_game_specific);
isShowSplash.set(false, is_game_specific);
isSideTrophy.set("right", is_game_specific);
@@ -1160,6 +1240,7 @@ void setDefaultValues(bool is_game_specific) {
cursorHideTimeout.set(5, is_game_specific);
isMotionControlsEnabled.set(true, is_game_specific);
backgroundControllerInput.set(false, is_game_specific);
usbDeviceBackend.set(UsbBackendType::Real, is_game_specific);
// GS - Audio
micDevice.set("Default Device", is_game_specific);
@@ -1182,12 +1263,15 @@ void setDefaultValues(bool is_game_specific) {
// GS - Vulkan
gpuId.set(-1, is_game_specific);
vkValidation.set(false, is_game_specific);
vkValidationCore.set(true, is_game_specific);
vkValidationSync.set(false, is_game_specific);
vkValidationGpu.set(false, is_game_specific);
vkCrashDiagnostic.set(false, is_game_specific);
vkHostMarkers.set(false, is_game_specific);
vkGuestMarkers.set(false, is_game_specific);
rdocEnable.set(false, is_game_specific);
pipelineCacheEnable.set(false, is_game_specific);
pipelineCacheArchive.set(false, is_game_specific);
// GS - Debug
isDebugDump.set(false, is_game_specific);
@@ -1203,8 +1287,6 @@ void setDefaultValues(bool is_game_specific) {
// General
enableDiscordRPC = false;
compatibilityData = false;
checkCompatibilityOnStartup = false;
// Input
useSpecialPad.base_value = false;
@@ -1223,11 +1305,9 @@ void setDefaultValues(bool is_game_specific) {
internalScreenWidth.base_value = 1280;
internalScreenHeight.base_value = 720;
// GUI
load_game_size = true;
// Debug
isFpsColor.base_value = true;
showFpsCounter.base_value = false;
}
}
@@ -1242,6 +1322,7 @@ hotkey_pause = f9
hotkey_reload_inputs = f8
hotkey_toggle_mouse_to_joystick = f7
hotkey_toggle_mouse_to_gyro = f6
hotkey_toggle_mouse_to_touchpad = delete
hotkey_quit = lctrl, lshift, end
)";
}

View File

@@ -9,6 +9,13 @@
namespace Config {
enum class ConfigMode {
Default,
Global,
Clean,
};
void setConfigMode(ConfigMode mode);
struct GameInstallDir {
std::filesystem::path path;
bool enabled;
@@ -20,6 +27,8 @@ void load(const std::filesystem::path& path, bool is_game_specific = false);
void save(const std::filesystem::path& path, bool is_game_specific = false);
void resetGameSpecificValue(std::string entry);
bool getGameRunning();
void setGameRunning(bool running);
int getVolumeSlider();
void setVolumeSlider(int volumeValue, bool is_game_specific = false);
std::string getTrophyKey();
@@ -72,6 +81,10 @@ bool vkValidationEnabled();
void setVkValidation(bool enable, bool is_game_specific = false);
bool vkValidationSyncEnabled();
void setVkSyncValidation(bool enable, bool is_game_specific = false);
bool vkValidationGpuEnabled();
void setVkGpuValidation(bool enable, bool is_game_specific = false);
bool vkValidationCoreEnabled();
void setVkCoreValidation(bool enable, bool is_game_specific = false);
bool getVkCrashDiagnosticEnabled();
void setVkCrashDiagnosticEnabled(bool enable, bool is_game_specific = false);
bool getVkHostMarkersEnabled();
@@ -81,7 +94,11 @@ void setVkGuestMarkersEnabled(bool enable, bool is_game_specific = false);
bool getEnableDiscordRPC();
void setEnableDiscordRPC(bool enable);
bool isRdocEnabled();
bool isPipelineCacheEnabled();
bool isPipelineCacheArchived();
void setRdocEnabled(bool enable, bool is_game_specific = false);
void setPipelineCacheEnabled(bool enable, bool is_game_specific = false);
void setPipelineCacheArchived(bool enable, bool is_game_specific = false);
std::string getLogType();
void setLogType(const std::string& type, bool is_game_specific = false);
std::string getLogFilter();
@@ -90,11 +107,10 @@ double getTrophyNotificationDuration();
void setTrophyNotificationDuration(double newTrophyNotificationDuration,
bool is_game_specific = false);
int getCursorHideTimeout();
void setCursorHideTimeout(int newcursorHideTimeout);
std::string getMainOutputDevice();
void setMainOutputDevice(std::string device);
void setMainOutputDevice(std::string device, bool is_game_specific = false);
std::string getPadSpkOutputDevice();
void setPadSpkOutputDevice(std::string device);
void setPadSpkOutputDevice(std::string device, bool is_game_specific = false);
std::string getMicDevice();
void setCursorHideTimeout(int newcursorHideTimeout, bool is_game_specific = false);
void setMicDevice(std::string device, bool is_game_specific = false);
@@ -110,12 +126,15 @@ bool getPSNSignedIn();
void setPSNSignedIn(bool sign, bool is_game_specific = false);
bool patchShaders(); // no set
bool fpsColor(); // no set
bool getShowFpsCounter();
void setShowFpsCounter(bool enable, bool is_game_specific = false);
bool isNeoModeConsole();
void setNeoMode(bool enable, bool is_game_specific = false);
bool isDevKitConsole();
void setDevKitConsole(bool enable, bool is_game_specific = false);
bool vkValidationGpuEnabled(); // no set
int getExtraDmemInMbytes();
void setExtraDmemInMbytes(int value, bool is_game_specific = false);
bool getIsMotionControlsEnabled();
void setIsMotionControlsEnabled(bool use, bool is_game_specific = false);
std::string getDefaultControllerID();
@@ -133,16 +152,18 @@ void setRcasAttenuation(int value, bool is_game_specific = false);
bool getIsConnectedToNetwork();
void setConnectedToNetwork(bool enable, bool is_game_specific = false);
void setUserName(const std::string& name, bool is_game_specific = false);
void setChooseHomeTab(const std::string& type, bool is_game_specific = false);
std::filesystem::path getSysModulesPath();
void setSysModulesPath(const std::filesystem::path& path);
bool getLoadAutoPatches();
void setLoadAutoPatches(bool enable);
enum UsbBackendType : int { Real, SkylandersPortal, InfinityBase, DimensionsToypad };
int getUsbDeviceBackend();
void setUsbDeviceBackend(int value, bool is_game_specific = false);
// TODO
bool GetLoadGameSizeEnabled();
std::filesystem::path GetSaveDataPath();
void setLoadGameSizeEnabled(bool enable);
bool getCompatibilityEnabled();
bool getCheckCompatibilityOnStartup();
std::string getUserName();
std::string getChooseHomeTab();
bool GetUseUnifiedInputConfig();
void SetUseUnifiedInputConfig(bool use);
bool GetOverrideControllerColor();
@@ -152,8 +173,6 @@ void SetControllerCustomColor(int r, int b, int g);
void setGameInstallDirs(const std::vector<std::filesystem::path>& dirs_config);
void setAllGameInstallDirs(const std::vector<GameInstallDir>& dirs_config);
void setSaveDataPath(const std::filesystem::path& path);
void setCompatibilityEnabled(bool use);
void setCheckCompatibilityOnStartup(bool use);
// Gui
bool addGameInstallDir(const std::filesystem::path& dir, bool enabled = true);
void removeGameInstallDir(const std::filesystem::path& dir);

View File

@@ -68,6 +68,7 @@ class ElfInfo {
std::string app_ver{};
u32 firmware_ver = 0;
u32 raw_firmware_ver = 0;
u32 sdk_ver = 0;
PSFAttributes psf_attributes{};
std::filesystem::path splash_path{};
@@ -117,6 +118,11 @@ public:
return raw_firmware_ver;
}
[[nodiscard]] u32 CompiledSdkVer() const {
ASSERT(initialized);
return sdk_ver;
}
[[nodiscard]] const PSFAttributes& GetPSFAttributes() const {
ASSERT(initialized);
return psf_attributes;

View File

@@ -40,28 +40,30 @@ namespace {
switch (mode) {
case FileAccessMode::Read:
return L"rb";
case FileAccessMode::Write:
return L"wb";
case FileAccessMode::Append:
return L"ab";
case FileAccessMode::Write:
case FileAccessMode::ReadWrite:
return L"r+b";
case FileAccessMode::ReadAppend:
return L"a+b";
case FileAccessMode::Create:
return L"wb";
}
break;
case FileType::TextFile:
switch (mode) {
case FileAccessMode::Read:
return L"r";
case FileAccessMode::Write:
return L"w";
case FileAccessMode::Append:
return L"a";
case FileAccessMode::Write:
case FileAccessMode::ReadWrite:
return L"r+";
case FileAccessMode::ReadAppend:
return L"a+";
case FileAccessMode::Create:
return L"w";
}
break;
}
@@ -91,28 +93,30 @@ namespace {
switch (mode) {
case FileAccessMode::Read:
return "rb";
case FileAccessMode::Write:
return "wb";
case FileAccessMode::Append:
return "ab";
case FileAccessMode::Write:
case FileAccessMode::ReadWrite:
return "r+b";
case FileAccessMode::ReadAppend:
return "a+b";
case FileAccessMode::Create:
return "wb";
}
break;
case FileType::TextFile:
switch (mode) {
case FileAccessMode::Read:
return "r";
case FileAccessMode::Write:
return "w";
case FileAccessMode::Append:
return "a";
case FileAccessMode::Write:
case FileAccessMode::ReadWrite:
return "r+";
case FileAccessMode::ReadAppend:
return "a+";
case FileAccessMode::Create:
return "w";
}
break;
}

View File

@@ -21,9 +21,8 @@ enum class FileAccessMode {
*/
Read = 1 << 0,
/**
* If the file at path exists, the existing contents of the file are erased.
* The empty file is then opened for writing.
* If the file at path does not exist, it creates and opens a new empty file for writing.
* If the file at path exists, it opens the file for writing.
* If the file at path does not exist, it fails to open the file.
*/
Write = 1 << 1,
/**
@@ -42,6 +41,12 @@ enum class FileAccessMode {
* reading and appending.
*/
ReadAppend = Read | Append,
/**
* If the file at path exists, the existing contents of the file are erased.
* The empty file is then opened for writing.
* If the file at path does not exist, it creates and opens a new empty file for writing.
*/
Create = 1 << 3,
};
DECLARE_ENUM_FLAG_OPERATORS(FileAccessMode);
@@ -102,6 +107,11 @@ public:
return file != nullptr;
}
bool IsWriteOnly() const {
return file_access_mode == FileAccessMode::Append ||
file_access_mode == FileAccessMode::Write;
}
uintptr_t GetFileMapping();
int Open(const std::filesystem::path& path, FileAccessMode mode,
@@ -210,7 +220,7 @@ public:
}
static size_t WriteBytes(const std::filesystem::path path, const auto& data) {
IOFile out(path, FileAccessMode::Write);
IOFile out(path, FileAccessMode::Create);
return out.Write(data);
}
std::FILE* file = nullptr;

View File

@@ -61,8 +61,9 @@ private:
*/
class FileBackend {
public:
explicit FileBackend(const std::filesystem::path& filename)
: file{filename, FS::FileAccessMode::Write, FS::FileType::TextFile} {}
explicit FileBackend(const std::filesystem::path& filename, bool should_append = false)
: file{filename, should_append ? FS::FileAccessMode::Append : FS::FileAccessMode::Create,
FS::FileType::TextFile} {}
~FileBackend() = default;
@@ -145,6 +146,11 @@ public:
initialization_in_progress_suppress_logging = false;
}
static void ResetInstance() {
initialization_in_progress_suppress_logging = true;
instance.reset();
}
static bool IsActive() {
return instance != nullptr;
}
@@ -157,6 +163,10 @@ public:
instance->StopBackendThread();
}
static void SetAppend() {
should_append = true;
}
Impl(const Impl&) = delete;
Impl& operator=(const Impl&) = delete;
@@ -172,7 +182,13 @@ public:
}
void PushEntry(Class log_class, Level log_level, const char* filename, unsigned int line_num,
const char* function, std::string message) {
const char* function, const char* format, const fmt::format_args& args) {
if (!filter.CheckMessage(log_class, log_level) || !Config::getLoggingEnabled()) {
return;
}
const auto message = fmt::vformat(format, args);
// Propagate important log messages to the profiler
if (IsProfilerConnected()) {
const auto& msg_str = fmt::format("[{}] {}", GetLogClassName(log_class), message);
@@ -191,10 +207,6 @@ public:
}
}
if (!filter.CheckMessage(log_class, log_level) || !Config::getLoggingEnabled()) {
return;
}
using std::chrono::duration_cast;
using std::chrono::microseconds;
using std::chrono::steady_clock;
@@ -218,7 +230,7 @@ public:
private:
Impl(const std::filesystem::path& file_backend_filename, const Filter& filter_)
: filter{filter_}, file_backend{file_backend_filename} {}
: filter{filter_}, file_backend{file_backend_filename, should_append} {}
~Impl() = default;
@@ -264,6 +276,7 @@ private:
}
static inline std::unique_ptr<Impl, decltype(&Deleter)> instance{nullptr, Deleter};
static inline bool should_append{false};
Filter filter;
DebuggerBackend debugger_backend{};
@@ -292,6 +305,11 @@ void Stop() {
Impl::Stop();
}
void Denitializer() {
Impl::Stop();
Impl::ResetInstance();
}
void SetGlobalFilter(const Filter& filter) {
Impl::Instance().SetGlobalFilter(filter);
}
@@ -300,12 +318,16 @@ void SetColorConsoleBackendEnabled(bool enabled) {
Impl::Instance().SetColorConsoleBackendEnabled(enabled);
}
void SetAppend() {
Impl::SetAppend();
}
void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename,
unsigned int line_num, const char* function, const char* format,
const fmt::format_args& args) {
if (!initialization_in_progress_suppress_logging) [[likely]] {
Impl::Instance().PushEntry(log_class, log_level, filename, line_num, function,
fmt::vformat(format, args));
Impl::Instance().PushEntry(log_class, log_level, filename, line_num, function, format,
args);
}
}
} // namespace Common::Log

View File

@@ -21,9 +21,14 @@ void Start();
/// Explictily stops the logger thread and flushes the buffers
void Stop();
/// Closes log files and stops the logger
void Denitializer();
/// The global filter will prevent any messages from even being processed if they are filtered.
void SetGlobalFilter(const Filter& filter);
void SetColorConsoleBackendEnabled(bool enabled);
void SetAppend();
} // namespace Common::Log

View File

@@ -104,11 +104,13 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
SUB(Lib, Move) \
SUB(Lib, NpAuth) \
SUB(Lib, NpCommon) \
SUB(Lib, NpCommerce) \
SUB(Lib, NpManager) \
SUB(Lib, NpScore) \
SUB(Lib, NpTrophy) \
SUB(Lib, NpWebApi) \
SUB(Lib, NpProfileDialog) \
SUB(Lib, NpSnsFacebookDialog) \
SUB(Lib, Screenshot) \
SUB(Lib, LibCInternal) \
SUB(Lib, AppContent) \
@@ -139,6 +141,8 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
SUB(Lib, NpParty) \
SUB(Lib, Zlib) \
SUB(Lib, Hmd) \
SUB(Lib, Font) \
SUB(Lib, FontFt) \
SUB(Lib, HmdSetupDialog) \
SUB(Lib, SigninDialog) \
SUB(Lib, Camera) \

View File

@@ -29,99 +29,103 @@ enum class Level : u8 {
* filter.cpp.
*/
enum class Class : u8 {
Log, ///< Messages about the log system itself
Common, ///< Library routines
Common_Filesystem, ///< Filesystem interface library
Common_Memory, ///< Memory mapping and management functions
Core, ///< LLE emulation core
Core_Linker, ///< The module linker
Core_Devices, ///< Devices emulation
Config, ///< Emulator configuration (including commandline)
Debug, ///< Debugging tools
Kernel, ///< The HLE implementation of the PS4 kernel.
Kernel_Pthread, ///< The pthread implementation of the kernel.
Kernel_Fs, ///< The filesystem implementation of the kernel.
Kernel_Vmm, ///< The virtual memory implementation of the kernel.
Kernel_Event, ///< The event management implementation of the kernel.
Kernel_Sce, ///< The sony specific interfaces provided by the kernel.
Lib, ///< HLE implementation of system library. Each major library
///< should have its own subclass.
Lib_LibC, ///< The LibC implementation.
Lib_LibcInternal, ///< The LibcInternal implementation.
Lib_Kernel, ///< The LibKernel implementation.
Lib_Pad, ///< The LibScePad implementation.
Lib_SystemGesture, ///< The LibSceSystemGesture implementation.
Lib_GnmDriver, ///< The LibSceGnmDriver implementation.
Lib_SystemService, ///< The LibSceSystemService implementation.
Lib_UserService, ///< The LibSceUserService implementation.
Lib_VideoOut, ///< The LibSceVideoOut implementation.
Lib_CommonDlg, ///< The LibSceCommonDialog implementation.
Lib_MsgDlg, ///< The LibSceMsgDialog implementation.
Lib_AudioOut, ///< The LibSceAudioOut implementation.
Lib_AudioIn, ///< The LibSceAudioIn implementation.
Lib_Move, ///< The LibSceMove implementation.
Lib_Net, ///< The LibSceNet implementation.
Lib_NetCtl, ///< The LibSceNetCtl implementation.
Lib_SaveData, ///< The LibSceSaveData implementation.
Lib_SaveDataDialog, ///< The LibSceSaveDataDialog implementation.
Lib_Ssl, ///< The LibSceSsl implementation.
Lib_Ssl2, ///< The LibSceSsl2 implementation.
Lib_Http, ///< The LibSceHttp implementation.
Lib_Http2, ///< The LibSceHttp2 implementation.
Lib_SysModule, ///< The LibSceSysModule implementation
Lib_NpCommon, ///< The LibSceNpCommon implementation
Lib_NpAuth, ///< The LibSceNpAuth implementation
Lib_NpManager, ///< The LibSceNpManager implementation
Lib_NpScore, ///< The LibSceNpScore implementation
Lib_NpTrophy, ///< The LibSceNpTrophy implementation
Lib_NpWebApi, ///< The LibSceWebApi implementation
Lib_NpProfileDialog, ///< The LibSceNpProfileDialog implementation
Lib_Screenshot, ///< The LibSceScreenshot implementation
Lib_LibCInternal, ///< The LibCInternal implementation.
Lib_AppContent, ///< The LibSceAppContent implementation.
Lib_Rtc, ///< The LibSceRtc implementation.
Lib_DiscMap, ///< The LibSceDiscMap implementation.
Lib_Png, ///< The LibScePng implementation.
Lib_Jpeg, ///< The LibSceJpeg implementation.
Lib_PlayGo, ///< The LibScePlayGo implementation.
Lib_PlayGoDialog, ///< The LibScePlayGoDialog implementation.
Lib_Random, ///< The LibSceRandom implementation.
Lib_Usbd, ///< The LibSceUsbd implementation.
Lib_Ajm, ///< The LibSceAjm implementation.
Lib_ErrorDialog, ///< The LibSceErrorDialog implementation.
Lib_ImeDialog, ///< The LibSceImeDialog implementation.
Lib_AvPlayer, ///< The LibSceAvPlayer implementation.
Lib_Ngs2, ///< The LibSceNgs2 implementation.
Lib_Audio3d, ///< The LibSceAudio3d implementation.
Lib_Ime, ///< The LibSceIme implementation
Lib_GameLiveStreaming, ///< The LibSceGameLiveStreaming implementation
Lib_Remoteplay, ///< The LibSceRemotePlay implementation
Lib_SharePlay, ///< The LibSceSharePlay implemenation
Lib_Fiber, ///< The LibSceFiber implementation.
Lib_Vdec2, ///< The LibSceVideodec2 implementation.
Lib_Videodec, ///< The LibSceVideodec implementation.
Lib_Voice, ///< The LibSceVoice implementation.
Lib_RazorCpu, ///< The LibRazorCpu implementation.
Lib_Mouse, ///< The LibSceMouse implementation
Lib_WebBrowserDialog, ///< The LibSceWebBrowserDialog implementation
Lib_NpParty, ///< The LibSceNpParty implementation
Lib_Zlib, ///< The LibSceZlib implementation.
Lib_Hmd, ///< The LibSceHmd implementation.
Lib_HmdSetupDialog, ///< The LibSceHmdSetupDialog implementation.
Lib_SigninDialog, ///< The LibSigninDialog implementation.
Lib_Camera, ///< The LibCamera implementation.
Lib_CompanionHttpd, ///< The LibCompanionHttpd implementation.
Lib_CompanionUtil, ///< The LibCompanionUtil implementation.
Lib_VrTracker, ///< The LibSceVrTracker implementation.
Frontend, ///< Emulator UI
Render, ///< Video Core
Render_Vulkan, ///< Vulkan backend
Render_Recompiler, ///< Shader recompiler
ImGui, ///< ImGui
Loader, ///< ROM loader
Input, ///< Input emulation
Tty, ///< Debug output from emu
Count ///< Total number of logging classes
Log, ///< Messages about the log system itself
Common, ///< Library routines
Common_Filesystem, ///< Filesystem interface library
Common_Memory, ///< Memory mapping and management functions
Core, ///< LLE emulation core
Core_Linker, ///< The module linker
Core_Devices, ///< Devices emulation
Config, ///< Emulator configuration (including commandline)
Debug, ///< Debugging tools
Kernel, ///< The HLE implementation of the PS4 kernel.
Kernel_Pthread, ///< The pthread implementation of the kernel.
Kernel_Fs, ///< The filesystem implementation of the kernel.
Kernel_Vmm, ///< The virtual memory implementation of the kernel.
Kernel_Event, ///< The event management implementation of the kernel.
Kernel_Sce, ///< The sony specific interfaces provided by the kernel.
Lib, ///< HLE implementation of system library. Each major library
///< should have its own subclass.
Lib_LibC, ///< The LibC implementation.
Lib_LibcInternal, ///< The LibcInternal implementation.
Lib_Kernel, ///< The LibKernel implementation.
Lib_Pad, ///< The LibScePad implementation.
Lib_SystemGesture, ///< The LibSceSystemGesture implementation.
Lib_GnmDriver, ///< The LibSceGnmDriver implementation.
Lib_SystemService, ///< The LibSceSystemService implementation.
Lib_UserService, ///< The LibSceUserService implementation.
Lib_VideoOut, ///< The LibSceVideoOut implementation.
Lib_CommonDlg, ///< The LibSceCommonDialog implementation.
Lib_MsgDlg, ///< The LibSceMsgDialog implementation.
Lib_AudioOut, ///< The LibSceAudioOut implementation.
Lib_AudioIn, ///< The LibSceAudioIn implementation.
Lib_Move, ///< The LibSceMove implementation.
Lib_Net, ///< The LibSceNet implementation.
Lib_NetCtl, ///< The LibSceNetCtl implementation.
Lib_SaveData, ///< The LibSceSaveData implementation.
Lib_SaveDataDialog, ///< The LibSceSaveDataDialog implementation.
Lib_Ssl, ///< The LibSceSsl implementation.
Lib_Ssl2, ///< The LibSceSsl2 implementation.
Lib_Http, ///< The LibSceHttp implementation.
Lib_Http2, ///< The LibSceHttp2 implementation.
Lib_SysModule, ///< The LibSceSysModule implementation
Lib_NpCommon, ///< The LibSceNpCommon implementation
Lib_NpCommerce, ///< The LibSceNpCommerce implementation
Lib_NpAuth, ///< The LibSceNpAuth implementation
Lib_NpManager, ///< The LibSceNpManager implementation
Lib_NpScore, ///< The LibSceNpScore implementation
Lib_NpTrophy, ///< The LibSceNpTrophy implementation
Lib_NpWebApi, ///< The LibSceWebApi implementation
Lib_NpProfileDialog, ///< The LibSceNpProfileDialog implementation
Lib_NpSnsFacebookDialog, ///< The LibSceNpSnsFacebookDialog implementation
Lib_Screenshot, ///< The LibSceScreenshot implementation
Lib_LibCInternal, ///< The LibCInternal implementation.
Lib_AppContent, ///< The LibSceAppContent implementation.
Lib_Rtc, ///< The LibSceRtc implementation.
Lib_DiscMap, ///< The LibSceDiscMap implementation.
Lib_Png, ///< The LibScePng implementation.
Lib_Jpeg, ///< The LibSceJpeg implementation.
Lib_PlayGo, ///< The LibScePlayGo implementation.
Lib_PlayGoDialog, ///< The LibScePlayGoDialog implementation.
Lib_Random, ///< The LibSceRandom implementation.
Lib_Usbd, ///< The LibSceUsbd implementation.
Lib_Ajm, ///< The LibSceAjm implementation.
Lib_ErrorDialog, ///< The LibSceErrorDialog implementation.
Lib_ImeDialog, ///< The LibSceImeDialog implementation.
Lib_AvPlayer, ///< The LibSceAvPlayer implementation.
Lib_Ngs2, ///< The LibSceNgs2 implementation.
Lib_Audio3d, ///< The LibSceAudio3d implementation.
Lib_Ime, ///< The LibSceIme implementation
Lib_GameLiveStreaming, ///< The LibSceGameLiveStreaming implementation
Lib_Remoteplay, ///< The LibSceRemotePlay implementation
Lib_SharePlay, ///< The LibSceSharePlay implemenation
Lib_Fiber, ///< The LibSceFiber implementation.
Lib_Vdec2, ///< The LibSceVideodec2 implementation.
Lib_Videodec, ///< The LibSceVideodec implementation.
Lib_Voice, ///< The LibSceVoice implementation.
Lib_RazorCpu, ///< The LibRazorCpu implementation.
Lib_Mouse, ///< The LibSceMouse implementation
Lib_WebBrowserDialog, ///< The LibSceWebBrowserDialog implementation
Lib_NpParty, ///< The LibSceNpParty implementation
Lib_Zlib, ///< The LibSceZlib implementation.
Lib_Hmd, ///< The LibSceHmd implementation.
Lib_HmdSetupDialog, ///< The LibSceHmdSetupDialog implementation.
Lib_SigninDialog, ///< The LibSigninDialog implementation.
Lib_Camera, ///< The LibCamera implementation.
Lib_CompanionHttpd, ///< The LibCompanionHttpd implementation.
Lib_CompanionUtil, ///< The LibCompanionUtil implementation.
Lib_VrTracker, ///< The LibSceVrTracker implementation.
Lib_Font, ///< The libSceFont implementation.
Lib_FontFt, ///< The libSceFontFt implementation.
Frontend, ///< Emulator UI
Render, ///< Video Core
Render_Vulkan, ///< Vulkan backend
Render_Recompiler, ///< Shader recompiler
ImGui, ///< ImGui
Loader, ///< ROM loader
Input, ///< Input emulation
Tty, ///< Debug output from emu
Count ///< Total number of logging classes
};
} // namespace Common::Log

View File

@@ -3,20 +3,12 @@
#include <algorithm>
#include <codecvt>
#include <fstream>
#include <sstream>
#include <string>
#include <nlohmann/json.hpp>
#include <pugixml.hpp>
#ifdef ENABLE_QT_GUI
#include <QDir>
#include <QFile>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QListView>
#include <QMessageBox>
#include <QString>
#include <QXmlStreamReader>
#endif
#include "common/config.h"
#include "common/elf_info.h"
#include "common/logging/log.h"
#include "common/path_util.h"
@@ -28,7 +20,7 @@ namespace MemoryPatcher {
EXPORT uintptr_t g_eboot_address;
uint64_t g_eboot_image_size;
std::string g_game_serial;
std::string patchFile;
std::string patch_file;
bool patches_applied = false;
std::vector<patchInfo> pending_patches;
@@ -122,256 +114,104 @@ std::string convertValueToHex(const std::string type, const std::string valueStr
void ApplyPendingPatches();
void OnGameLoaded() {
if (!patchFile.empty()) {
std::filesystem::path patchDir = Common::FS::GetUserPath(Common::FS::PathType::PatchesDir);
void ApplyPatchesFromXML(std::filesystem::path path) {
pugi::xml_document doc;
pugi::xml_parse_result result = doc.load_file(path.c_str());
auto filePath = (patchDir / patchFile).native();
auto* param_sfo = Common::Singleton<PSF>::Instance();
auto app_version = param_sfo->GetString("APP_VER").value_or("Unknown version");
pugi::xml_document doc;
pugi::xml_parse_result result = doc.load_file(filePath.c_str());
if (result) {
auto patchXML = doc.child("Patch");
for (pugi::xml_node_iterator it = patchXML.children().begin();
it != patchXML.children().end(); ++it) {
auto* param_sfo = Common::Singleton<PSF>::Instance();
auto app_version = param_sfo->GetString("APP_VER").value_or("Unknown version");
if (std::string(it->name()) == "Metadata") {
if (std::string(it->attribute("isEnabled").value()) == "true") {
std::string currentPatchName = it->attribute("Name").value();
std::string metadataAppVer = it->attribute("AppVer").value();
bool versionMatches = metadataAppVer == app_version;
if (result) {
auto patchXML = doc.child("Patch");
for (pugi::xml_node_iterator it = patchXML.children().begin();
it != patchXML.children().end(); ++it) {
auto patchList = it->first_child();
for (pugi::xml_node_iterator patchLineIt = patchList.children().begin();
patchLineIt != patchList.children().end(); ++patchLineIt) {
if (std::string(it->name()) == "Metadata") {
if (std::string(it->attribute("isEnabled").value()) == "true") {
std::string currentPatchName = it->attribute("Name").value();
std::string metadataAppVer = it->attribute("AppVer").value();
bool versionMatches = metadataAppVer == app_version;
std::string type = patchLineIt->attribute("Type").value();
if (!versionMatches && type != "mask" && type != "mask_jump32")
continue;
auto patchList = it->first_child();
for (pugi::xml_node_iterator patchLineIt = patchList.children().begin();
patchLineIt != patchList.children().end(); ++patchLineIt) {
std::string type = patchLineIt->attribute("Type").value();
if (!versionMatches && type != "mask" && type != "mask_jump32")
continue;
std::string currentPatchName = it->attribute("Name").value();
for (pugi::xml_node_iterator patchLineIt = patchList.children().begin();
patchLineIt != patchList.children().end(); ++patchLineIt) {
std::string type = patchLineIt->attribute("Type").value();
std::string address = patchLineIt->attribute("Address").value();
std::string patchValue = patchLineIt->attribute("Value").value();
std::string maskOffsetStr =
patchLineIt->attribute("Offset").value();
std::string targetStr = "";
std::string sizeStr = "";
if (type == "mask_jump32") {
targetStr = patchLineIt->attribute("Target").value();
sizeStr = patchLineIt->attribute("Size").value();
} else {
patchValue = convertValueToHex(type, patchValue);
}
bool littleEndian = false;
if (type == "bytes16" || type == "bytes32" || type == "bytes64") {
littleEndian = true;
}
MemoryPatcher::PatchMask patchMask = MemoryPatcher::PatchMask::None;
int maskOffsetValue = 0;
if (type == "mask")
patchMask = MemoryPatcher::PatchMask::Mask;
if (type == "mask_jump32")
patchMask = MemoryPatcher::PatchMask::Mask_Jump32;
if ((type == "mask" || type == "mask_jump32") &&
!maskOffsetStr.empty()) {
maskOffsetValue = std::stoi(maskOffsetStr, 0, 10);
}
MemoryPatcher::PatchMemory(currentPatchName, address, patchValue,
targetStr, sizeStr, false, littleEndian,
patchMask, maskOffsetValue);
}
std::string address = patchLineIt->attribute("Address").value();
std::string patchValue = patchLineIt->attribute("Value").value();
std::string maskOffsetStr = patchLineIt->attribute("Offset").value();
std::string targetStr = "";
std::string sizeStr = "";
if (type == "mask_jump32") {
targetStr = patchLineIt->attribute("Target").value();
sizeStr = patchLineIt->attribute("Size").value();
} else {
patchValue = convertValueToHex(type, patchValue);
}
bool littleEndian = false;
if (type == "bytes16" || type == "bytes32" || type == "bytes64") {
littleEndian = true;
}
MemoryPatcher::PatchMask patchMask = MemoryPatcher::PatchMask::None;
int maskOffsetValue = 0;
if (type == "mask")
patchMask = MemoryPatcher::PatchMask::Mask;
if (type == "mask_jump32")
patchMask = MemoryPatcher::PatchMask::Mask_Jump32;
if ((type == "mask" || type == "mask_jump32") && !maskOffsetStr.empty()) {
maskOffsetValue = std::stoi(maskOffsetStr, 0, 10);
}
MemoryPatcher::PatchMemory(currentPatchName, address, patchValue, targetStr,
sizeStr, false, littleEndian, patchMask,
maskOffsetValue);
}
}
}
}
} else {
LOG_ERROR(Loader, "Could not parse patch XML: {}", result.description());
}
}
void OnGameLoaded() {
std::filesystem::path patch_dir = Common::FS::GetUserPath(Common::FS::PathType::PatchesDir);
if (!patch_file.empty()) {
auto file_path = (patch_dir / patch_file).native();
if (std::filesystem::exists(patch_file)) {
ApplyPatchesFromXML(patch_file);
} else {
LOG_ERROR(Loader, "couldnt patch parse xml : {}", result.description());
ApplyPatchesFromXML(file_path);
}
} else if (Config::getLoadAutoPatches()) {
for (auto const& repo : std::filesystem::directory_iterator(patch_dir)) {
if (!repo.is_directory()) {
continue;
}
std::ifstream json_file{repo.path() / "files.json"};
nlohmann::json available_patches = nlohmann::json::parse(json_file);
std::filesystem::path game_patch_file;
for (auto const& [filename, serials] : available_patches.items()) {
if (std::find(serials.begin(), serials.end(), g_game_serial) != serials.end()) {
game_patch_file = repo.path() / filename;
break;
}
}
if (std::filesystem::exists(game_patch_file)) {
ApplyPatchesFromXML(game_patch_file);
}
}
}
ApplyPendingPatches();
#ifdef ENABLE_QT_GUI
// We use the QT headers for the xml and json parsing, this define is only true on QT builds
QString patchDir;
Common::FS::PathToQString(patchDir, Common::FS::GetUserPath(Common::FS::PathType::PatchesDir));
QDir dir(patchDir);
QStringList folders = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
for (const QString& folder : folders) {
QString filesJsonPath = patchDir + "/" + folder + "/files.json";
QFile jsonFile(filesJsonPath);
if (!jsonFile.open(QIODevice::ReadOnly)) {
LOG_ERROR(Loader, "Unable to open files.json for reading in repository {}",
folder.toStdString());
continue;
}
QByteArray jsonData = jsonFile.readAll();
jsonFile.close();
QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData);
QJsonObject jsonObject = jsonDoc.object();
QString selectedFileName;
QString serial = QString::fromStdString(g_game_serial);
for (auto it = jsonObject.constBegin(); it != jsonObject.constEnd(); ++it) {
QString filePath = it.key();
QJsonArray idsArray = it.value().toArray();
if (idsArray.contains(QJsonValue(serial))) {
selectedFileName = filePath;
break;
}
}
if (selectedFileName.isEmpty()) {
LOG_ERROR(Loader, "No patch file found for the current serial in repository {}",
folder.toStdString());
continue;
}
QString filePath = patchDir + "/" + folder + "/" + selectedFileName;
QFile file(filePath);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
LOG_ERROR(Loader, "Unable to open the file for reading.");
continue;
}
QByteArray xmlData = file.readAll();
file.close();
QString newXmlData;
QXmlStreamReader xmlReader(xmlData);
bool isEnabled = false;
std::string currentPatchName;
auto* param_sfo = Common::Singleton<PSF>::Instance();
auto app_version = param_sfo->GetString("APP_VER").value_or("Unknown version");
bool versionMatches = true;
while (!xmlReader.atEnd()) {
xmlReader.readNext();
if (xmlReader.isStartElement()) {
QJsonArray patchLines;
if (xmlReader.name() == QStringLiteral("Metadata")) {
QString name = xmlReader.attributes().value("Name").toString();
currentPatchName = name.toStdString();
QString appVer = xmlReader.attributes().value("AppVer").toString();
// Check and update the isEnabled attribute
isEnabled = false;
for (const QXmlStreamAttribute& attr : xmlReader.attributes()) {
if (attr.name() == QStringLiteral("isEnabled")) {
isEnabled = (attr.value().toString() == "true");
}
}
versionMatches = (appVer.toStdString() == app_version);
} else if (xmlReader.name() == QStringLiteral("PatchList")) {
QJsonArray linesArray;
while (!xmlReader.atEnd() &&
!(xmlReader.tokenType() == QXmlStreamReader::EndElement &&
xmlReader.name() == QStringLiteral("PatchList"))) {
xmlReader.readNext();
if (xmlReader.tokenType() == QXmlStreamReader::StartElement &&
xmlReader.name() == QStringLiteral("Line")) {
QXmlStreamAttributes attributes = xmlReader.attributes();
QJsonObject lineObject;
lineObject["Type"] = attributes.value("Type").toString();
lineObject["Address"] = attributes.value("Address").toString();
lineObject["Value"] = attributes.value("Value").toString();
lineObject["Offset"] = attributes.value("Offset").toString();
if (lineObject["Type"].toString() == "mask_jump32") {
lineObject["Target"] = attributes.value("Target").toString();
lineObject["Size"] = attributes.value("Size").toString();
}
linesArray.append(lineObject);
}
}
patchLines = linesArray;
if (isEnabled) {
foreach (const QJsonValue& value, patchLines) {
QJsonObject lineObject = value.toObject();
QString type = lineObject["Type"].toString();
if ((type != "mask" && type != "mask_jump32") && !versionMatches)
continue;
QString address = lineObject["Address"].toString();
QString patchValue = lineObject["Value"].toString();
QString maskOffsetStr = lineObject["Offset"].toString();
QString targetStr;
QString sizeStr;
if (type == "mask_jump32") {
targetStr = lineObject["Target"].toString();
sizeStr = lineObject["Size"].toString();
} else {
patchValue = QString::fromStdString(convertValueToHex(
type.toStdString(), patchValue.toStdString()));
}
bool littleEndian = false;
if (type == "bytes16" || type == "bytes32" || type == "bytes64")
littleEndian = true;
MemoryPatcher::PatchMask patchMask = MemoryPatcher::PatchMask::None;
int maskOffsetValue = 0;
if (type == "mask")
patchMask = MemoryPatcher::PatchMask::Mask;
if (type == "mask_jump32")
patchMask = MemoryPatcher::PatchMask::Mask_Jump32;
if ((type == "mask" || type == "mask_jump32") &&
!maskOffsetStr.toStdString().empty()) {
maskOffsetValue = std::stoi(maskOffsetStr.toStdString(), 0, 10);
}
MemoryPatcher::PatchMemory(
currentPatchName, address.toStdString(), patchValue.toStdString(),
targetStr.toStdString(), sizeStr.toStdString(), false, littleEndian,
patchMask, maskOffsetValue);
}
}
}
}
}
if (xmlReader.hasError()) {
LOG_ERROR(Loader, "Failed to parse XML for {}", g_game_serial);
} else {
LOG_INFO(Loader, "Patches loaded successfully, repository: {}", folder.toStdString());
}
ApplyPendingPatches();
}
#endif
}
void AddPatchToQueue(patchInfo patchToAdd) {

View File

@@ -17,7 +17,7 @@ namespace MemoryPatcher {
extern EXPORT uintptr_t g_eboot_address;
extern uint64_t g_eboot_image_size;
extern std::string g_game_serial;
extern std::string patchFile;
extern std::string patch_file;
enum PatchMask : uint8_t {
None,

View File

@@ -1,20 +1,14 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <array>
#include <half.hpp>
#include "common/number_utils.h"
#include "video_core/amdgpu/pixel_format.h"
#include "video_core/amdgpu/types.h"
#define UF11_EXPONENT_SHIFT 6
#define UF10_EXPONENT_SHIFT 5
#define RGB9E5_MANTISSA_BITS 9
#define RGB9E5_EXP_BIAS 1
#define F32_INFINITY 0x7f800000
constexpr u32 UF11_EXPONENT_SHIFT = 6;
constexpr u32 UF10_EXPONENT_SHIFT = 5;
constexpr u32 RGB9E5_MANTISSA_BITS = 9;
constexpr u32 RGB9E5_EXP_BIAS = 1;
constexpr u32 F32_INFINITY = 0x7f800000;
namespace NumberUtils {

View File

@@ -25,10 +25,6 @@
#endif
#endif
#ifdef ENABLE_QT_GUI
#include <QString>
#endif
namespace Common::FS {
namespace fs = std::filesystem;
@@ -88,13 +84,6 @@ static std::optional<std::filesystem::path> GetBundleParentDirectory() {
#endif
static auto UserPaths = [] {
#if defined(__APPLE__) && defined(ENABLE_QT_GUI)
// Set the current path to the directory containing the app bundle.
if (const auto bundle_dir = GetBundleParentDirectory()) {
std::filesystem::current_path(*bundle_dir);
}
#endif
// Try the portable user directory first.
auto user_dir = std::filesystem::current_path() / PORTABLE_DIR;
if (!std::filesystem::exists(user_dir)) {
@@ -138,6 +127,7 @@ static auto UserPaths = [] {
create_path(PathType::MetaDataDir, user_dir / METADATA_DIR);
create_path(PathType::CustomTrophy, user_dir / CUSTOM_TROPHY);
create_path(PathType::CustomConfigs, user_dir / CUSTOM_CONFIGS);
create_path(PathType::CacheDir, user_dir / CACHE_DIR);
std::ofstream notice_file(user_dir / CUSTOM_TROPHY / "Notice.txt");
if (notice_file.is_open()) {
@@ -229,22 +219,4 @@ std::optional<fs::path> FindGameByID(const fs::path& dir, const std::string& gam
return std::nullopt;
}
#ifdef ENABLE_QT_GUI
void PathToQString(QString& result, const std::filesystem::path& path) {
#ifdef _WIN32
result = QString::fromStdWString(path.wstring());
#else
result = QString::fromStdString(path.string());
#endif
}
std::filesystem::path PathFromQString(const QString& path) {
#ifdef _WIN32
return std::filesystem::path(path.toStdWString());
#else
return std::filesystem::path(path.toStdString());
#endif
}
#endif
} // namespace Common::FS

View File

@@ -7,10 +7,6 @@
#include <optional>
#include <vector>
#ifdef ENABLE_QT_GUI
class QString; // to avoid including <QString> in this header
#endif
namespace Common::FS {
enum class PathType {
@@ -28,6 +24,7 @@ enum class PathType {
MetaDataDir, // Where game metadata (e.g. trophies and menu backgrounds) is stored.
CustomTrophy, // Where custom files for trophies are stored.
CustomConfigs, // Where custom files for different games are stored.
CacheDir, // Where pipeline and shader cache is stored.
};
constexpr auto PORTABLE_DIR = "user";
@@ -46,6 +43,7 @@ constexpr auto PATCHES_DIR = "patches";
constexpr auto METADATA_DIR = "game_data";
constexpr auto CUSTOM_TROPHY = "custom_trophy";
constexpr auto CUSTOM_CONFIGS = "custom_configs";
constexpr auto CACHE_DIR = "cache";
// Filenames
constexpr auto LOG_FILE = "shad_log.txt";
@@ -99,25 +97,6 @@ constexpr auto LOG_FILE = "shad_log.txt";
*/
void SetUserPath(PathType user_path, const std::filesystem::path& new_path);
#ifdef ENABLE_QT_GUI
/**
* Converts an std::filesystem::path to a QString.
* The native underlying string of a path is wstring on Windows and string on POSIX.
*
* @param result The resulting QString
* @param path The path to convert
*/
void PathToQString(QString& result, const std::filesystem::path& path);
/**
* Converts a QString to an std::filesystem::path.
* The native underlying string of a path is wstring on Windows and string on POSIX.
*
* @param path The path to convert
*/
[[nodiscard]] std::filesystem::path PathFromQString(const QString& path);
#endif
/**
* Recursively searches for a game directory by its ID.
* Limits search depth to prevent excessive filesystem traversal.

140
src/common/serdes.h Normal file
View File

@@ -0,0 +1,140 @@
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/assert.h"
#include "common/types.h"
#include <cstddef>
namespace Serialization {
template <typename T>
concept Container = requires(T t) {
typename T::iterator;
{ t.begin() } -> std::same_as<typename T::iterator>;
{ t.end() } -> std::same_as<typename T::iterator>;
{ t.size() } -> std::convertible_to<std::size_t>;
};
struct Archive {
void Alloc(size_t size) {
container.resize(size);
}
void Grow(size_t size) {
container.resize(container.size() + size);
}
void Merge(const Archive& ar) {
container.insert(container.end(), ar.container.cbegin(), ar.container.cend());
offset = container.size();
}
[[nodiscard]] size_t SizeBytes() const {
return container.size();
}
u8* CurrPtr() {
return container.data() + offset;
}
void Advance(size_t size) {
ASSERT(offset + size <= container.size());
offset += size;
}
std::vector<u8>&& TakeOff() {
offset = 0;
return std::move(container);
}
[[nodiscard]] bool IsEoS() const {
return offset >= container.size();
}
Archive() = default;
explicit Archive(std::vector<u8>&& v) : container{v} {}
private:
u32 offset{};
std::vector<u8> container{};
friend struct Writer;
friend struct Reader;
};
struct Writer {
template <typename T>
void Write(const T* ptr, size_t size) {
if (ar.offset + size >= ar.container.size()) {
ar.Grow(size);
}
std::memcpy(ar.CurrPtr(), reinterpret_cast<const void*>(ptr), size);
ar.Advance(size);
}
template <typename T>
requires(!Container<T>)
void Write(const T& value) {
const auto size = sizeof(value);
Write(&value, size);
}
void Write(const auto& v) {
Write(v.size());
for (const auto& elem : v) {
Write(elem);
}
}
void Write(const std::string& s) {
Write(s.size());
Write(s.c_str(), s.size());
}
Writer() = delete;
explicit Writer(Archive& ar_) : ar{ar_} {}
Archive& ar;
};
struct Reader {
template <typename T>
void Read(T* ptr, size_t size) {
ASSERT(ar.offset + size <= ar.container.size());
std::memcpy(reinterpret_cast<void*>(ptr), ar.CurrPtr(), size);
ar.Advance(size);
}
template <typename T>
requires(!Container<T>)
void Read(T& value) {
const auto size = sizeof(value);
Read(&value, size);
}
void Read(auto& v) {
size_t num_elements{};
Read(num_elements);
for (int i = 0; i < num_elements; ++i) {
v.emplace_back();
Read(v.back());
}
}
void Read(std::string& s) {
size_t length{};
Read(length);
s.resize(length);
Read(s.data(), length);
}
Reader() = delete;
explicit Reader(Archive& ar_) : ar{ar_} {}
Archive& ar;
};
} // namespace Serialization

View File

@@ -2,10 +2,11 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <map>
#include <boost/icl/separate_interval_set.hpp>
#include "common/alignment.h"
#include "common/arch.h"
#include "common/assert.h"
#include "common/config.h"
#include "common/elf_info.h"
#include "common/error.h"
#include "core/address_space.h"
#include "core/libraries/kernel/memory.h"
@@ -23,22 +24,70 @@
// Reserve space for the system address space using a zerofill section.
asm(".zerofill SYSTEM_MANAGED,SYSTEM_MANAGED,__SYSTEM_MANAGED,0x7FFBFC000");
asm(".zerofill SYSTEM_RESERVED,SYSTEM_RESERVED,__SYSTEM_RESERVED,0x7C0004000");
asm(".zerofill USER_AREA,USER_AREA,__USER_AREA,0x5F9000000000");
#endif
namespace Core {
static constexpr size_t BackingSize = SCE_KERNEL_TOTAL_MEM_PRO;
// Constants used for mapping address space.
constexpr VAddr SYSTEM_MANAGED_MIN = 0x400000ULL;
constexpr VAddr SYSTEM_MANAGED_MAX = 0x7FFFFBFFFULL;
constexpr VAddr SYSTEM_RESERVED_MIN = 0x7FFFFC000ULL;
#if defined(__APPLE__) && defined(ARCH_X86_64)
// Commpage ranges from 0xFC0000000 - 0xFFFFFFFFF, so decrease the system reserved maximum.
constexpr VAddr SYSTEM_RESERVED_MAX = 0xFBFFFFFFFULL;
// GPU-reserved memory ranges from 0x1000000000 - 0x6FFFFFFFFF, so increase the user minimum.
constexpr VAddr USER_MIN = 0x7000000000ULL;
#else
constexpr VAddr SYSTEM_RESERVED_MAX = 0xFFFFFFFFFULL;
constexpr VAddr USER_MIN = 0x1000000000ULL;
#endif
#if defined(__linux__)
// Linux maps the shadPS4 executable around here, so limit the user maximum
constexpr VAddr USER_MAX = 0x54FFFFFFFFFFULL;
#else
constexpr VAddr USER_MAX = 0x5FFFFFFFFFFFULL;
#endif
// Constants for the sizes of the ranges in address space.
static constexpr u64 SystemManagedSize = SYSTEM_MANAGED_MAX - SYSTEM_MANAGED_MIN + 1;
static constexpr u64 SystemReservedSize = SYSTEM_RESERVED_MAX - SYSTEM_RESERVED_MIN + 1;
static constexpr u64 UserSize = USER_MAX - USER_MIN + 1;
// Required backing file size for mapping physical address space.
static u64 BackingSize = ORBIS_KERNEL_TOTAL_MEM_DEV_PRO;
#ifdef _WIN32
[[nodiscard]] constexpr u64 ToWindowsProt(Core::MemoryProt prot) {
if (True(prot & Core::MemoryProt::CpuReadWrite) ||
True(prot & Core::MemoryProt::GpuReadWrite)) {
return PAGE_READWRITE;
} else if (True(prot & Core::MemoryProt::CpuRead) || True(prot & Core::MemoryProt::GpuRead)) {
return PAGE_READONLY;
const bool read =
True(prot & Core::MemoryProt::CpuRead) || True(prot & Core::MemoryProt::GpuRead);
const bool write =
True(prot & Core::MemoryProt::CpuWrite) || True(prot & Core::MemoryProt::GpuWrite);
const bool execute = True(prot & Core::MemoryProt::CpuExec);
if (write && !read) {
// While write-only CPU mappings aren't possible, write-only GPU mappings are.
LOG_WARNING(Core, "Converting write-only mapping to read-write");
}
// All cases involving execute permissions have separate permissions.
if (execute) {
if (write) {
return PAGE_EXECUTE_READWRITE;
} else if (read && !write) {
return PAGE_EXECUTE_READ;
} else {
return PAGE_EXECUTE;
}
} else {
return PAGE_NOACCESS;
if (write) {
return PAGE_READWRITE;
} else if (read && !write) {
return PAGE_READONLY;
} else {
return PAGE_NOACCESS;
}
}
}
@@ -50,70 +99,108 @@ struct MemoryRegion {
struct AddressSpace::Impl {
Impl() : process{GetCurrentProcess()} {
// Allocate virtual address placeholder for our address space.
MEM_ADDRESS_REQUIREMENTS req{};
MEM_EXTENDED_PARAMETER param{};
req.LowestStartingAddress = reinterpret_cast<PVOID>(SYSTEM_MANAGED_MIN);
// The ending address must align to page boundary - 1
// https://stackoverflow.com/questions/54223343/virtualalloc2-with-memextendedparameteraddressrequirements-always-produces-error
req.HighestEndingAddress = reinterpret_cast<PVOID>(USER_MIN + UserSize - 1);
req.Alignment = 0;
param.Type = MemExtendedParameterAddressRequirements;
param.Pointer = &req;
// Determine the system's page alignment
SYSTEM_INFO sys_info{};
GetSystemInfo(&sys_info);
u64 alignment = sys_info.dwAllocationGranularity;
// Typically, lower parts of system managed area is already reserved in windows.
// If reservation fails attempt again by reducing the area size a little bit.
// System managed is about 31GB in size so also cap the number of times we can reduce it
// to a reasonable amount.
static constexpr size_t ReductionOnFail = 1_GB;
static constexpr size_t MaxReductions = 10;
// Older Windows builds have a severe performance issue with VirtualAlloc2.
// We need to get the host's Windows version, then determine if it needs a workaround.
auto ntdll_handle = GetModuleHandleW(L"ntdll.dll");
ASSERT_MSG(ntdll_handle, "Failed to retrieve ntdll handle");
size_t virtual_size = SystemManagedSize + SystemReservedSize + UserSize;
for (u32 i = 0; i < MaxReductions; i++) {
virtual_base = static_cast<u8*>(VirtualAlloc2(process, NULL, virtual_size,
MEM_RESERVE | MEM_RESERVE_PLACEHOLDER,
PAGE_NOACCESS, &param, 1));
if (virtual_base) {
break;
// Get the RtlGetVersion function
s64(WINAPI * RtlGetVersion)(LPOSVERSIONINFOW);
*(FARPROC*)&RtlGetVersion = GetProcAddress(ntdll_handle, "RtlGetVersion");
ASSERT_MSG(RtlGetVersion, "failed to retrieve function pointer for RtlGetVersion");
// Call RtlGetVersion
RTL_OSVERSIONINFOW os_version_info{};
RtlGetVersion(&os_version_info);
u64 supported_user_max = USER_MAX;
// This is the build number for Windows 11 22H2
static constexpr s32 AffectedBuildNumber = 22621;
// Higher PS4 firmware versions prevent higher address mappings too.
s32 sdk_ver = Common::ElfInfo::Instance().CompiledSdkVer();
if (os_version_info.dwBuildNumber <= AffectedBuildNumber ||
sdk_ver >= Common::ElfInfo::FW_30) {
supported_user_max = 0x10000000000ULL;
// Only log the message if we're restricting the user max due to operating system.
// Since higher compiled SDK versions also get reduced max, we don't need to log there.
if (sdk_ver < Common::ElfInfo::FW_30) {
LOG_WARNING(
Core,
"Older Windows version detected, reducing user max to {:#x} to avoid problems",
supported_user_max);
}
virtual_size -= ReductionOnFail;
}
ASSERT_MSG(virtual_base, "Unable to reserve virtual address space: {}",
Common::GetLastErrorMsg());
// Determine the free address ranges we can access.
VAddr next_addr = SYSTEM_MANAGED_MIN;
MEMORY_BASIC_INFORMATION info{};
while (next_addr <= supported_user_max) {
ASSERT_MSG(VirtualQuery(reinterpret_cast<PVOID>(next_addr), &info, sizeof(info)),
"Failed to query memory information for address {:#x}", next_addr);
// Ensure logic uses values aligned to bage boundaries.
next_addr = reinterpret_cast<VAddr>(info.BaseAddress) + info.RegionSize;
next_addr = Common::AlignUp(next_addr, alignment);
// Prevent size from going past supported_user_max
u64 size = info.RegionSize;
if (next_addr > supported_user_max) {
size -= (next_addr - supported_user_max);
}
size = Common::AlignDown(size, alignment);
// Check for free memory areas
// Restrict region size to avoid overly fragmenting the virtual memory space.
if (info.State == MEM_FREE && info.RegionSize > 0x1000000) {
VAddr addr = Common::AlignUp(reinterpret_cast<VAddr>(info.BaseAddress), alignment);
regions.emplace(addr, MemoryRegion{addr, size, false});
}
}
// Reserve all detected free regions.
for (auto region : regions) {
auto addr = static_cast<u8*>(VirtualAlloc2(
process, reinterpret_cast<PVOID>(region.second.base), region.second.size,
MEM_RESERVE | MEM_RESERVE_PLACEHOLDER, PAGE_NOACCESS, NULL, 0));
// All marked regions should reserve fine since they're free.
ASSERT_MSG(addr, "Unable to reserve virtual address space: {}",
Common::GetLastErrorMsg());
}
// Set these constants to ensure code relying on them works.
// These do not fully encapsulate the state of the address space.
system_managed_base = reinterpret_cast<u8*>(regions.begin()->first);
system_managed_size = SystemManagedSize - (regions.begin()->first - SYSTEM_MANAGED_MIN);
system_reserved_base = reinterpret_cast<u8*>(SYSTEM_RESERVED_MIN);
system_reserved_size = SystemReservedSize;
system_managed_base = virtual_base;
system_managed_size = system_reserved_base - virtual_base;
user_base = reinterpret_cast<u8*>(USER_MIN);
user_size = virtual_base + virtual_size - user_base;
user_size = supported_user_max - USER_MIN - 1;
LOG_INFO(Kernel_Vmm, "System managed virtual memory region: {} - {}",
fmt::ptr(system_managed_base),
fmt::ptr(system_managed_base + system_managed_size - 1));
LOG_INFO(Kernel_Vmm, "System reserved virtual memory region: {} - {}",
fmt::ptr(system_reserved_base),
fmt::ptr(system_reserved_base + system_reserved_size - 1));
LOG_INFO(Kernel_Vmm, "User virtual memory region: {} - {}", fmt::ptr(user_base),
fmt::ptr(user_base + user_size - 1));
// Initializer placeholder tracker
const uintptr_t system_managed_addr = reinterpret_cast<uintptr_t>(system_managed_base);
regions.emplace(system_managed_addr,
MemoryRegion{system_managed_addr, virtual_size, false});
// Increase BackingSize to account for config options.
BackingSize += Config::getExtraDmemInMbytes() * 1_MB;
// Allocate backing file that represents the total physical memory.
backing_handle =
CreateFileMapping2(INVALID_HANDLE_VALUE, nullptr, FILE_MAP_WRITE | FILE_MAP_READ,
PAGE_READWRITE, SEC_COMMIT, BackingSize, nullptr, nullptr, 0);
backing_handle = CreateFileMapping2(INVALID_HANDLE_VALUE, nullptr, FILE_MAP_ALL_ACCESS,
PAGE_EXECUTE_READWRITE, SEC_COMMIT, BackingSize,
nullptr, nullptr, 0);
ASSERT_MSG(backing_handle, "{}", Common::GetLastErrorMsg());
// Allocate a virtual memory for the backing file map as placeholder
backing_base = static_cast<u8*>(VirtualAlloc2(process, nullptr, BackingSize,
MEM_RESERVE | MEM_RESERVE_PLACEHOLDER,
PAGE_NOACCESS, nullptr, 0));
ASSERT_MSG(backing_base, "{}", Common::GetLastErrorMsg());
// Map backing placeholder. This will commit the pages
void* const ret = MapViewOfFile3(backing_handle, process, backing_base, 0, BackingSize,
MEM_REPLACE_PLACEHOLDER, PAGE_READWRITE, nullptr, 0);
void* const ret =
MapViewOfFile3(backing_handle, process, backing_base, 0, BackingSize,
MEM_REPLACE_PLACEHOLDER, PAGE_EXECUTE_READWRITE, nullptr, 0);
ASSERT_MSG(ret == backing_base, "{}", Common::GetLastErrorMsg());
}
@@ -154,7 +241,12 @@ struct AddressSpace::Impl {
ASSERT_MSG(ret, "VirtualProtect failed. {}", Common::GetLastErrorMsg());
} else {
ptr = MapViewOfFile3(backing, process, reinterpret_cast<PVOID>(virtual_addr),
phys_addr, size, MEM_REPLACE_PLACEHOLDER, prot, nullptr, 0);
phys_addr, size, MEM_REPLACE_PLACEHOLDER,
PAGE_EXECUTE_READWRITE, nullptr, 0);
ASSERT_MSG(ptr, "MapViewOfFile3 failed. {}", Common::GetLastErrorMsg());
DWORD resultvar;
bool ret = VirtualProtect(ptr, size, prot, &resultvar);
ASSERT_MSG(ret, "VirtualProtect failed. {}", Common::GetLastErrorMsg());
}
} else {
ptr =
@@ -296,17 +388,33 @@ struct AddressSpace::Impl {
void Protect(VAddr virtual_addr, size_t size, bool read, bool write, bool execute) {
DWORD new_flags{};
if (read && write && execute) {
new_flags = PAGE_EXECUTE_READWRITE;
} else if (read && write) {
new_flags = PAGE_READWRITE;
} else if (read && !write) {
new_flags = PAGE_READONLY;
} else if (execute && !read && !write) {
new_flags = PAGE_EXECUTE;
} else if (!read && !write && !execute) {
new_flags = PAGE_NOACCESS;
if (write && !read) {
// While write-only CPU protection isn't possible, write-only GPU protection is.
LOG_WARNING(Core, "Converting write-only protection to read-write");
}
// All cases involving execute permissions have separate permissions.
if (execute) {
// If there's some form of write protection requested, provide read-write permissions.
if (write) {
new_flags = PAGE_EXECUTE_READWRITE;
} else if (read && !write) {
new_flags = PAGE_EXECUTE_READ;
} else {
new_flags = PAGE_EXECUTE;
}
} else {
if (write) {
new_flags = PAGE_READWRITE;
} else if (read && !write) {
new_flags = PAGE_READONLY;
} else {
new_flags = PAGE_NOACCESS;
}
}
// If no flags are assigned, then something's gone wrong.
if (new_flags == 0) {
LOG_CRITICAL(Common_Memory,
"Unsupported protection flag combination for address {:#x}, size {}, "
"read={}, write={}, execute={}",
@@ -326,12 +434,20 @@ struct AddressSpace::Impl {
DWORD old_flags{};
if (!VirtualProtectEx(process, LPVOID(range_addr), range_size, new_flags, &old_flags)) {
UNREACHABLE_MSG(
"Failed to change virtual memory protection for address {:#x}, size {}",
"Failed to change virtual memory protection for address {:#x}, size {:#x}",
range_addr, range_size);
}
}
}
boost::icl::interval_set<VAddr> GetUsableRegions() {
boost::icl::interval_set<VAddr> reserved_regions;
for (auto region : regions) {
reserved_regions.insert({region.second.base, region.second.base + region.second.size});
}
return reserved_regions;
}
HANDLE process{};
HANDLE backing_handle{};
u8* backing_base{};
@@ -356,62 +472,73 @@ enum PosixPageProtection {
};
[[nodiscard]] constexpr PosixPageProtection ToPosixProt(Core::MemoryProt prot) {
if (True(prot & Core::MemoryProt::CpuReadWrite) ||
True(prot & Core::MemoryProt::GpuReadWrite)) {
if (True(prot & Core::MemoryProt::CpuExec)) {
const bool read =
True(prot & Core::MemoryProt::CpuRead) || True(prot & Core::MemoryProt::GpuRead);
const bool write =
True(prot & Core::MemoryProt::CpuWrite) || True(prot & Core::MemoryProt::GpuWrite);
const bool execute = True(prot & Core::MemoryProt::CpuExec);
if (write && !read) {
// While write-only CPU mappings aren't possible, write-only GPU mappings are.
LOG_WARNING(Core, "Converting write-only mapping to read-write");
}
// All cases involving execute permissions have separate permissions.
if (execute) {
if (write) {
return PAGE_EXECUTE_READWRITE;
} else {
return PAGE_READWRITE;
}
} else if (True(prot & Core::MemoryProt::CpuRead) || True(prot & Core::MemoryProt::GpuRead)) {
if (True(prot & Core::MemoryProt::CpuExec)) {
} else if (read && !write) {
return PAGE_EXECUTE_READ;
} else {
return PAGE_READONLY;
return PAGE_EXECUTE;
}
} else {
return PAGE_NOACCESS;
if (write) {
return PAGE_READWRITE;
} else if (read && !write) {
return PAGE_READONLY;
} else {
return PAGE_NOACCESS;
}
}
}
struct AddressSpace::Impl {
Impl() {
BackingSize += Config::getExtraDmemInMbytes() * 1_MB;
// Allocate virtual address placeholder for our address space.
system_managed_size = SystemManagedSize;
system_reserved_size = SystemReservedSize;
user_size = UserSize;
constexpr int protection_flags = PROT_READ | PROT_WRITE;
constexpr int base_map_flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE;
constexpr int map_flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE | MAP_FIXED;
#if defined(__APPLE__) && defined(ARCH_X86_64)
// On ARM64 Macs under Rosetta 2, we run into limitations due to the commpage from
// 0xFC0000000 - 0xFFFFFFFFF and the GPU carveout region from 0x1000000000 - 0x6FFFFFFFFF.
// We can allocate the system managed region, as well as system reserved if reduced in size
// slightly, but we cannot map the user region where we want, so we must let the OS put it
// wherever possible and hope the game won't rely on its location.
system_managed_base = reinterpret_cast<u8*>(
mmap(reinterpret_cast<void*>(SYSTEM_MANAGED_MIN), system_managed_size, protection_flags,
base_map_flags | MAP_FIXED, -1, 0));
system_reserved_base = reinterpret_cast<u8*>(
mmap(reinterpret_cast<void*>(SYSTEM_RESERVED_MIN), system_reserved_size,
protection_flags, base_map_flags | MAP_FIXED, -1, 0));
// Cannot guarantee enough space for these areas at the desired addresses, so not MAP_FIXED.
user_base = reinterpret_cast<u8*>(mmap(reinterpret_cast<void*>(USER_MIN), user_size,
protection_flags, base_map_flags, -1, 0));
// On ARM64 Macs, we run into limitations due to the commpage from 0xFC0000000 - 0xFFFFFFFFF
// and the GPU carveout region from 0x1000000000 - 0x6FFFFFFFFF. Because this creates gaps
// in the available virtual memory region, we map memory space using three distinct parts.
system_managed_base =
reinterpret_cast<u8*>(mmap(reinterpret_cast<void*>(SYSTEM_MANAGED_MIN),
system_managed_size, protection_flags, map_flags, -1, 0));
system_reserved_base =
reinterpret_cast<u8*>(mmap(reinterpret_cast<void*>(SYSTEM_RESERVED_MIN),
system_reserved_size, protection_flags, map_flags, -1, 0));
user_base = reinterpret_cast<u8*>(
mmap(reinterpret_cast<void*>(USER_MIN), user_size, protection_flags, map_flags, -1, 0));
#else
const auto virtual_size = system_managed_size + system_reserved_size + user_size;
#if defined(ARCH_X86_64)
const auto virtual_base =
reinterpret_cast<u8*>(mmap(reinterpret_cast<void*>(SYSTEM_MANAGED_MIN), virtual_size,
protection_flags, base_map_flags | MAP_FIXED, -1, 0));
protection_flags, map_flags, -1, 0));
system_managed_base = virtual_base;
system_reserved_base = reinterpret_cast<u8*>(SYSTEM_RESERVED_MIN);
user_base = reinterpret_cast<u8*>(USER_MIN);
#else
// Map memory wherever possible and instruction translation can handle offsetting to the
// base.
const auto virtual_base = reinterpret_cast<u8*>(
mmap(nullptr, virtual_size, protection_flags, base_map_flags, -1, 0));
const auto virtual_base =
reinterpret_cast<u8*>(mmap(nullptr, virtual_size, protection_flags, map_flags, -1, 0));
system_managed_base = virtual_base;
system_reserved_base = virtual_base + SYSTEM_RESERVED_MIN - SYSTEM_MANAGED_MIN;
user_base = virtual_base + USER_MIN - SYSTEM_MANAGED_MIN;
@@ -579,9 +706,9 @@ void AddressSpace::Unmap(VAddr virtual_addr, size_t size, VAddr start_in_vma, VA
// the entire allocation and remap the portions outside of the requested unmapping range.
impl->Unmap(virtual_addr, size, has_backing && !readonly_file);
// TODO: Determine if any titles require partial unmapping support for flexible allocations.
// TODO: Determine if any titles require partial unmapping support for un-backed allocations.
ASSERT_MSG(has_backing || (start_in_vma == 0 && end_in_vma == size),
"Partial unmapping of flexible allocations is not supported");
"Partial unmapping of un-backed allocations is not supported");
if (start_in_vma != 0) {
Map(virtual_addr, start_in_vma, 0, phys_base, is_exec);
@@ -602,4 +729,22 @@ void AddressSpace::Protect(VAddr virtual_addr, size_t size, MemoryPermission per
return impl->Protect(virtual_addr, size, read, write, execute);
}
boost::icl::interval_set<VAddr> AddressSpace::GetUsableRegions() {
#ifdef _WIN32
// On Windows, we need to obtain the accessible intervals from the implementation's regions.
return impl->GetUsableRegions();
#else
// On Linux and Mac, the memory space is fully represented by the three major regions
boost::icl::interval_set<VAddr> reserved_regions;
VAddr system_managed_addr = reinterpret_cast<VAddr>(system_managed_base);
VAddr system_reserved_addr = reinterpret_cast<VAddr>(system_reserved_base);
VAddr user_addr = reinterpret_cast<VAddr>(user_base);
reserved_regions.insert({system_managed_addr, system_managed_addr + system_managed_size});
reserved_regions.insert({system_reserved_addr, system_reserved_addr + system_reserved_size});
reserved_regions.insert({user_addr, user_addr + user_size});
return reserved_regions;
#endif
}
} // namespace Core

View File

@@ -4,6 +4,7 @@
#pragma once
#include <memory>
#include <boost/icl/separate_interval_set.hpp>
#include "common/arch.h"
#include "common/enum.h"
#include "common/types.h"
@@ -20,22 +21,6 @@ enum class MemoryPermission : u32 {
};
DECLARE_ENUM_FLAG_OPERATORS(MemoryPermission)
constexpr VAddr SYSTEM_MANAGED_MIN = 0x00000400000ULL;
constexpr VAddr SYSTEM_MANAGED_MAX = 0x07FFFFBFFFULL;
constexpr VAddr SYSTEM_RESERVED_MIN = 0x07FFFFC000ULL;
#if defined(__APPLE__) && defined(ARCH_X86_64)
// Can only comfortably reserve the first 0x7C0000000 of system reserved space.
constexpr VAddr SYSTEM_RESERVED_MAX = 0xFBFFFFFFFULL;
#else
constexpr VAddr SYSTEM_RESERVED_MAX = 0xFFFFFFFFFULL;
#endif
constexpr VAddr USER_MIN = 0x1000000000ULL;
constexpr VAddr USER_MAX = 0xFBFFFFFFFFULL;
static constexpr size_t SystemManagedSize = SYSTEM_MANAGED_MAX - SYSTEM_MANAGED_MIN + 1;
static constexpr size_t SystemReservedSize = SYSTEM_RESERVED_MAX - SYSTEM_RESERVED_MIN + 1;
static constexpr size_t UserSize = 1ULL << 40;
/**
* Represents the user virtual address space backed by a dmem memory block
*/
@@ -100,6 +85,9 @@ public:
void Protect(VAddr virtual_addr, size_t size, MemoryPermission perms);
// Returns an interval set containing all usable regions.
boost::icl::interval_set<VAddr> GetUsableRegions();
private:
struct Impl;
std::unique_ptr<Impl> impl;

View File

@@ -5,6 +5,7 @@
#include <memory>
#include <mutex>
#include <set>
#include <vector>
#include <Zydis/Zydis.h>
#include <xbyak/xbyak.h>
#include <xbyak/xbyak_util.h>
@@ -122,6 +123,30 @@ static void GenerateTcbAccess(void* /* address */, const ZydisDecodedOperand* op
#endif
}
static bool FilterStackCheck(const ZydisDecodedOperand* operands) {
const auto& dst_op = operands[0];
const auto& src_op = operands[1];
// Some compilers emit stack checks by starting a function with
// 'mov (64-bit register), fs:[0x28]', then checking with `xor (64-bit register), fs:[0x28]`
return src_op.type == ZYDIS_OPERAND_TYPE_MEMORY && src_op.mem.segment == ZYDIS_REGISTER_FS &&
src_op.mem.base == ZYDIS_REGISTER_NONE && src_op.mem.index == ZYDIS_REGISTER_NONE &&
src_op.mem.disp.value == 0x28 && dst_op.reg.value >= ZYDIS_REGISTER_RAX &&
dst_op.reg.value <= ZYDIS_REGISTER_R15;
}
static void GenerateStackCheck(void* /* address */, const ZydisDecodedOperand* operands,
Xbyak::CodeGenerator& c) {
const auto dst = ZydisToXbyakRegisterOperand(operands[0]);
c.xor_(dst, 0);
}
static void GenerateStackCanary(void* /* address */, const ZydisDecodedOperand* operands,
Xbyak::CodeGenerator& c) {
const auto dst = ZydisToXbyakRegisterOperand(operands[0]);
c.mov(dst, 0);
}
static bool FilterNoSSE4a(const ZydisDecodedOperand*) {
Cpu cpu;
return !cpu.has(Cpu::tSSE4a);
@@ -440,18 +465,26 @@ struct PatchInfo {
bool trampoline;
};
static const std::unordered_map<ZydisMnemonic, PatchInfo> Patches = {
static const std::unordered_map<ZydisMnemonic, std::vector<PatchInfo>> Patches = {
// SSE4a
{ZYDIS_MNEMONIC_EXTRQ, {FilterNoSSE4a, GenerateEXTRQ, true}},
{ZYDIS_MNEMONIC_INSERTQ, {FilterNoSSE4a, GenerateINSERTQ, true}},
{ZYDIS_MNEMONIC_MOVNTSS, {FilterNoSSE4a, ReplaceMOVNTSS, false}},
{ZYDIS_MNEMONIC_MOVNTSD, {FilterNoSSE4a, ReplaceMOVNTSD, false}},
{ZYDIS_MNEMONIC_EXTRQ, {{FilterNoSSE4a, GenerateEXTRQ, true}}},
{ZYDIS_MNEMONIC_INSERTQ, {{FilterNoSSE4a, GenerateINSERTQ, true}}},
{ZYDIS_MNEMONIC_MOVNTSS, {{FilterNoSSE4a, ReplaceMOVNTSS, false}}},
{ZYDIS_MNEMONIC_MOVNTSD, {{FilterNoSSE4a, ReplaceMOVNTSD, false}}},
#if !defined(__APPLE__)
// FS segment patches
// These first two patches are for accesses to the stack canary, fs:[0x28]
{ZYDIS_MNEMONIC_XOR, {{FilterStackCheck, GenerateStackCheck, false}}},
{ZYDIS_MNEMONIC_MOV,
{{FilterStackCheck, GenerateStackCanary, false},
#if defined(_WIN32)
// Windows needs a trampoline.
{ZYDIS_MNEMONIC_MOV, {FilterTcbAccess, GenerateTcbAccess, true}},
#elif !defined(__APPLE__)
{ZYDIS_MNEMONIC_MOV, {FilterTcbAccess, GenerateTcbAccess, false}},
// Windows needs a trampoline for Tcb accesses.
{FilterTcbAccess, GenerateTcbAccess, true}
#else
{FilterTcbAccess, GenerateTcbAccess, false}
#endif
}},
#endif
};
@@ -503,51 +536,53 @@ static std::pair<bool, u64> TryPatch(u8* code, PatchModule* module) {
}
if (Patches.contains(instruction.mnemonic)) {
const auto& patch_info = Patches.at(instruction.mnemonic);
bool needs_trampoline = patch_info.trampoline;
if (patch_info.filter(operands)) {
auto& patch_gen = module->patch_gen;
const auto& patches = Patches.at(instruction.mnemonic);
for (const auto& patch_info : patches) {
bool needs_trampoline = patch_info.trampoline;
if (patch_info.filter(operands)) {
auto& patch_gen = module->patch_gen;
if (needs_trampoline && instruction.length < 5) {
// Trampoline is needed but instruction is too short to patch.
// Return false and length to signal to AOT compilation that this instruction
// should be skipped and handled at runtime.
return std::make_pair(false, instruction.length);
}
if (needs_trampoline && instruction.length < 5) {
// Trampoline is needed but instruction is too short to patch.
// Return false and length to signal to AOT compilation that this instruction
// should be skipped and handled at runtime.
return std::make_pair(false, instruction.length);
}
// Reset state and move to current code position.
patch_gen.reset();
patch_gen.setSize(code - patch_gen.getCode());
// Reset state and move to current code position.
patch_gen.reset();
patch_gen.setSize(code - patch_gen.getCode());
if (needs_trampoline) {
auto& trampoline_gen = module->trampoline_gen;
const auto trampoline_ptr = trampoline_gen.getCurr();
if (needs_trampoline) {
auto& trampoline_gen = module->trampoline_gen;
const auto trampoline_ptr = trampoline_gen.getCurr();
patch_info.generator(code, operands, trampoline_gen);
patch_info.generator(code, operands, trampoline_gen);
// Return to the following instruction at the end of the trampoline.
trampoline_gen.jmp(code + instruction.length);
// Return to the following instruction at the end of the trampoline.
trampoline_gen.jmp(code + instruction.length);
// Replace instruction with near jump to the trampoline.
patch_gen.jmp(trampoline_ptr, Xbyak::CodeGenerator::LabelType::T_NEAR);
} else {
patch_info.generator(code, operands, patch_gen);
}
// Replace instruction with near jump to the trampoline.
patch_gen.jmp(trampoline_ptr, Xbyak::CodeGenerator::LabelType::T_NEAR);
} else {
patch_info.generator(code, operands, patch_gen);
}
const auto patch_size = patch_gen.getCurr() - code;
if (patch_size > 0) {
ASSERT_MSG(instruction.length >= patch_size,
"Instruction {} with length {} is too short to replace at: {}",
ZydisMnemonicGetString(instruction.mnemonic), instruction.length,
fmt::ptr(code));
const auto patch_size = patch_gen.getCurr() - code;
if (patch_size > 0) {
ASSERT_MSG(instruction.length >= patch_size,
"Instruction {} with length {} is too short to replace at: {}",
ZydisMnemonicGetString(instruction.mnemonic), instruction.length,
fmt::ptr(code));
// Fill remaining space with nops.
patch_gen.nop(instruction.length - patch_size);
// Fill remaining space with nops.
patch_gen.nop(instruction.length - patch_size);
module->patched.insert(code);
LOG_DEBUG(Core, "Patched instruction '{}' at: {}",
ZydisMnemonicGetString(instruction.mnemonic), fmt::ptr(code));
return std::make_pair(true, instruction.length);
module->patched.insert(code);
LOG_DEBUG(Core, "Patched instruction '{}' at: {}",
ZydisMnemonicGetString(instruction.mnemonic), fmt::ptr(code));
return std::make_pair(true, instruction.length);
}
}
}
}

View File

@@ -157,7 +157,7 @@ std::optional<RegDump*> DebugStateImpl::GetRegDump(uintptr_t base_addr, uintptr_
}
void DebugStateImpl::PushRegsDump(uintptr_t base_addr, uintptr_t header_addr,
const AmdGpu::Liverpool::Regs& regs) {
const AmdGpu::Regs& regs) {
std::scoped_lock lock{frame_dump_list_mutex};
auto dump = GetRegDump(base_addr, header_addr);
@@ -170,15 +170,14 @@ void DebugStateImpl::PushRegsDump(uintptr_t base_addr, uintptr_t header_addr,
for (int i = 0; i < RegDump::MaxShaderStages; i++) {
if ((*dump)->regs.stage_enable.IsStageEnabled(i)) {
auto stage = (*dump)->regs.ProgramForStage(i);
if (stage->address_lo != 0) {
const auto& info = AmdGpu::Liverpool::SearchBinaryInfo(stage->Address<u32*>());
auto code = stage->Code();
if (stage->address) {
const auto params = AmdGpu::GetParams(*stage);
(*dump)->stages[i] = PipelineShaderProgramDump{
.name = Vulkan::PipelineCache::GetShaderName(Shader::StageFromIndex(i),
info.shader_hash),
.hash = info.shader_hash,
params.hash),
.hash = params.hash,
.user_data = *stage,
.code = std::vector<u32>{code.begin(), code.end()},
.code = std::vector<u32>{params.code.begin(), params.code.end()},
};
}
}
@@ -198,12 +197,12 @@ void DebugStateImpl::PushRegsDumpCompute(uintptr_t base_addr, uintptr_t header_a
auto& cs = (*dump)->regs.cs_program;
cs = cs_state;
const auto& info = AmdGpu::Liverpool::SearchBinaryInfo(cs.Address<u32*>());
const auto params = AmdGpu::GetParams(cs);
(*dump)->cs_data = PipelineComputerProgramDump{
.name = Vulkan::PipelineCache::GetShaderName(Shader::Stage::Compute, info.shader_hash),
.hash = info.shader_hash,
.name = Vulkan::PipelineCache::GetShaderName(Shader::Stage::Compute, params.hash),
.hash = params.hash,
.cs_program = cs,
.code = std::vector<u32>{cs.Code().begin(), cs.Code().end()},
.code = std::vector<u32>{params.code.begin(), params.code.end()},
};
}

View File

@@ -11,7 +11,9 @@
#include <queue>
#include "common/types.h"
#include "video_core/renderer_vulkan/vk_graphics_pipeline.h"
#include "shader_recompiler/runtime_info.h"
#include "video_core/amdgpu/regs.h"
#include "video_core/renderer_vulkan/vk_common.h"
#ifdef _WIN32
#ifndef WIN32_LEAN_AND_MEAN
@@ -54,21 +56,21 @@ struct QueueDump {
struct PipelineShaderProgramDump {
std::string name;
u64 hash;
Vulkan::Liverpool::ShaderProgram user_data{};
AmdGpu::ShaderProgram user_data{};
std::vector<u32> code{};
};
struct PipelineComputerProgramDump {
std::string name;
u64 hash;
Vulkan::Liverpool::ComputeProgram cs_program{};
AmdGpu::ComputeProgram cs_program{};
std::vector<u32> code{};
};
struct RegDump {
bool is_compute{false};
static constexpr size_t MaxShaderStages = 5;
Vulkan::Liverpool::Regs regs{};
AmdGpu::Regs regs;
std::array<PipelineShaderProgramDump, MaxShaderStages> stages{};
PipelineComputerProgramDump cs_data{};
};
@@ -219,9 +221,8 @@ public:
void PushQueueDump(QueueDump dump);
void PushRegsDump(uintptr_t base_addr, uintptr_t header_addr,
const AmdGpu::Liverpool::Regs& regs);
using CsState = AmdGpu::Liverpool::ComputeProgram;
void PushRegsDump(uintptr_t base_addr, uintptr_t header_addr, const AmdGpu::Regs& regs);
using CsState = AmdGpu::ComputeProgram;
void PushRegsDumpCompute(uintptr_t base_addr, uintptr_t header_addr, const CsState& cs_state);
void CollectShader(const std::string& name, Shader::LogicalStage l_stage,

99
src/core/debugger.cpp Normal file
View File

@@ -0,0 +1,99 @@
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "debugger.h"
#include <iostream>
#include <thread>
#if defined(_WIN32)
#include <Windows.h>
#include <debugapi.h>
#elif defined(__linux__)
#include <filesystem>
#include <fstream>
#elif defined(__APPLE__)
#include <errno.h>
#include <signal.h>
#include <sys/sysctl.h>
#include <sys/types.h>
#include <unistd.h>
#endif
bool Core::Debugger::IsDebuggerAttached() {
#if defined(_WIN32)
return IsDebuggerPresent();
#elif defined(__linux__)
std::ifstream status_file("/proc/self/status");
std::string line;
while (std::getline(status_file, line)) {
if (line.starts_with("TracerPid:")) {
std::string tracer_pid = line.substr(10);
tracer_pid.erase(0, tracer_pid.find_first_not_of(" \t"));
return tracer_pid != "0";
}
}
return false;
#elif defined(__APPLE__)
int mib[4];
struct kinfo_proc info;
size_t size = sizeof(info);
mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
mib[2] = KERN_PROC_PID;
mib[3] = getpid();
if (sysctl(mib, 4, &info, &size, nullptr, 0) == 0) {
return (info.kp_proc.p_flag & P_TRACED) != 0;
}
return false;
#else
#error "Unsupported platform"
#endif
}
void Core::Debugger::WaitForDebuggerAttach() {
int count = 0;
while (!IsDebuggerAttached()) {
std::this_thread::sleep_for(std::chrono::milliseconds(200));
if (--count <= 0) {
count = 10;
std::cerr << "Waiting for debugger to attach..." << std::endl;
}
}
}
int Core::Debugger::GetCurrentPid() {
#if defined(_WIN32)
return GetCurrentProcessId();
#elif defined(__APPLE__) || defined(__linux__)
return getpid();
#else
#error "Unsupported platform"
#endif
}
void Core::Debugger::WaitForPid(int pid) {
#if defined(_WIN32)
HANDLE process_handle = OpenProcess(SYNCHRONIZE, FALSE, pid);
if (process_handle != nullptr) {
std::cerr << "Waiting for process " << pid << " to exit..." << std::endl;
WaitForSingleObject(process_handle, INFINITE);
CloseHandle(process_handle);
}
#elif defined(__linux__)
std::string proc_path = "/proc/" + std::to_string(pid);
while (std::filesystem::exists(proc_path)) {
std::this_thread::sleep_for(std::chrono::milliseconds(500));
std::cerr << "Waiting for process " << pid << " to exit..." << std::endl;
}
#elif defined(__APPLE__)
while (kill(pid, 0) == 0) {
std::this_thread::sleep_for(std::chrono::milliseconds(500));
std::cerr << "Waiting for process " << pid << " to exit..." << std::endl;
}
#else
#error "Unsupported platform"
#endif
}

16
src/core/debugger.h Normal file
View File

@@ -0,0 +1,16 @@
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
namespace Core::Debugger {
bool IsDebuggerAttached();
void WaitForDebuggerAttach();
int GetCurrentPid();
void WaitForPid(int pid);
} // namespace Core::Debugger

View File

@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "layer.h"
@@ -311,6 +311,7 @@ static void LoadSettings(const char* line) {
void L::SetupSettings() {
frame_graph.is_open = true;
show_simple_fps = Config::getShowFpsCounter();
using SettingLoader = void (*)(const char*);
@@ -460,12 +461,12 @@ void L::Draw() {
}
void L::TextCentered(const std::string& text) {
float window_width = ImGui::GetWindowSize().x;
float text_width = ImGui::CalcTextSize(text.c_str()).x;
float window_width = GetWindowSize().x;
float text_width = CalcTextSize(text.c_str()).x;
float text_indentation = (window_width - text_width) * 0.5f;
ImGui::SameLine(text_indentation);
ImGui::Text("%s", text.c_str());
SameLine(text_indentation);
Text("%s", text.c_str());
}
namespace Overlay {
@@ -475,6 +476,11 @@ void ToggleSimpleFps() {
visibility_toggled = true;
}
void SetSimpleFps(bool enabled) {
show_simple_fps = enabled;
visibility_toggled = true;
}
void ToggleQuitWindow() {
show_quit_window = !show_quit_window;
}

View File

@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
@@ -9,18 +9,20 @@
namespace Core::Devtools {
class Layer final : public ImGui::Layer {
static void DrawMenuBar();
static void DrawAdvanced();
static void DrawSimple();
public:
static void SetupSettings();
void Draw() override;
void TextCentered(const std::string& text);
// Must be inside a window
static void DrawNullGpuNotice();
private:
static void DrawMenuBar();
static void DrawAdvanced();
static void DrawSimple();
static void TextCentered(const std::string& text);
};
} // namespace Core::Devtools
@@ -28,6 +30,7 @@ public:
namespace Overlay {
void ToggleSimpleFps();
void SetSimpleFps(bool enabled);
void ToggleQuitWindow();
} // namespace Overlay

View File

@@ -0,0 +1,95 @@
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "layer.h"
#include "imgui/imgui_std.h"
#include <imgui.h>
#include <imgui_internal.h>
#include <cmath>
#include <numbers>
namespace Core::Devtools {
void Layer::DrawNullGpuNotice() {
auto* window = ImGui::GetCurrentWindow();
if (window->SkipItems) {
return;
}
constexpr std::string_view mainNotice = "Null GPU is enabled";
constexpr std::string_view detailsNotice =
"Disable the nullGpu config to show the game display";
auto displaySize = window->Size;
ImVec2 targetSize = displaySize * 0.7f;
float minFontSize = 1.0f;
float maxFontSize = 200.0f;
float optimalFontSize = minFontSize;
static auto lastSize = ImVec2(-1, -1);
static float lastFontSize = -1.0f;
auto* font = ImGui::GetIO().Fonts->Fonts[IMGUI_FONT_TEXT_BIG];
if (lastSize != targetSize) {
while (maxFontSize - minFontSize > 0.1f) {
float testFontSize = (minFontSize + maxFontSize) / 2.0f;
ImVec2 textSize = font->CalcTextSizeA(testFontSize, FLT_MAX, 0.0f, &mainNotice.front(),
&mainNotice.back() + 1);
if (textSize.x <= targetSize.x && textSize.y <= targetSize.y) {
optimalFontSize = testFontSize;
minFontSize = testFontSize;
} else {
maxFontSize = testFontSize;
}
}
lastSize = targetSize;
lastFontSize = optimalFontSize;
} else {
optimalFontSize = lastFontSize;
}
ImVec2 textSize = font->CalcTextSizeA(optimalFontSize, FLT_MAX, 0.0f, &mainNotice.front(),
&mainNotice.back() + 1);
ImVec2 textPos = (displaySize - textSize) * 0.5f + window->Pos;
const float scale = optimalFontSize / font->FontSize;
double timeAnim = -std::numbers::pi * ImGui::GetTime();
int i = 0;
for (auto ch : mainNotice) {
double colorTime = sin(timeAnim + i * std::numbers::pi / 6.0) / 2.0 + 0.5;
int color = (int)(200 * colorTime) + 55;
double posTime = sin(timeAnim + i * std::numbers::pi / 15.0) / 2.0 + 0.5;
auto pos = textPos;
pos.y += 10.0 * (posTime < 0.5 ? std::pow(2.0, 20.0 * posTime - 10.0) / 2.0
: (2.0 - std::pow(2.0, -20.0 * posTime + 10.0)) / 2.0);
window->DrawList->AddText(font, optimalFontSize, pos, IM_COL32(color, color, color, 255),
&ch, &ch + 1);
textPos.x += font->FindGlyph(ch)->AdvanceX * scale;
i++;
}
font = ImGui::GetIO().Fonts->Fonts[IMGUI_FONT_TEXT];
textPos.y += textSize.y + 1.0;
optimalFontSize *= 0.2;
textSize = font->CalcTextSizeA(optimalFontSize, FLT_MAX, 0.0f, &detailsNotice.front(),
&detailsNotice.back() + 1);
textPos.x = window->Pos.x + (window->Size.x - textSize.x) * 0.5f;
window->DrawList->AddText(font, optimalFontSize, textPos, IM_COL32(200, 200, 200, 255),
&detailsNotice.front(), &detailsNotice.back() + 1);
}
} // namespace Core::Devtools

View File

@@ -65,7 +65,7 @@ static HdrType GetNext(HdrType this_pm4, uint32_t n) {
}
void ParsePolygonControl(u32 value, bool begin_table) {
auto const reg = reinterpret_cast<AmdGpu::Liverpool::PolygonControl const&>(value);
auto const reg = reinterpret_cast<AmdGpu::PolygonControl const&>(value);
if (!begin_table ||
BeginTable("PA_SU_SC_MODE_CNTL", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
@@ -73,80 +73,80 @@ void ParsePolygonControl(u32 value, bool begin_table) {
TableSetColumnIndex(0);
Text("CULL_FRONT");
TableSetColumnIndex(1);
Text("%X", reg.cull_front.Value());
Text("%X", reg.cull_front);
TableNextRow();
TableSetColumnIndex(0);
Text("CULL_BACK");
TableSetColumnIndex(1);
Text("%X", reg.cull_back.Value());
Text("%X", reg.cull_back);
TableNextRow();
TableSetColumnIndex(0);
Text("FACE");
TableSetColumnIndex(1);
Text("%s", enum_name(reg.front_face.Value()).data());
Text("%s", enum_name(reg.front_face).data());
TableNextRow();
TableSetColumnIndex(0);
Text("POLY_MODE");
TableSetColumnIndex(1);
Text("%X", reg.enable_polygon_mode.Value());
Text("%X", reg.enable_polygon_mode);
TableNextRow();
TableSetColumnIndex(0);
Text("POLYMODE_FRONT_PTYPE");
TableSetColumnIndex(1);
Text("%s", enum_name(reg.polygon_mode_front.Value()).data());
Text("%s", enum_name(reg.polygon_mode_front).data());
TableNextRow();
TableSetColumnIndex(0);
Text("POLYMODE_BACK_PTYPE");
TableSetColumnIndex(1);
Text("%s", enum_name(reg.polygon_mode_back.Value()).data());
Text("%s", enum_name(reg.polygon_mode_back).data());
TableNextRow();
TableSetColumnIndex(0);
Text("POLY_OFFSET_FRONT_ENABLE");
TableSetColumnIndex(1);
Text("%X", reg.enable_polygon_offset_front.Value());
Text("%X", reg.enable_polygon_offset_front);
TableNextRow();
TableSetColumnIndex(0);
Text("POLY_OFFSET_BACK_ENABLE");
TableSetColumnIndex(1);
Text("%X", reg.enable_polygon_offset_back.Value());
Text("%X", reg.enable_polygon_offset_back);
TableNextRow();
TableSetColumnIndex(0);
Text("POLY_OFFSET_PARA_ENABLE");
TableSetColumnIndex(1);
Text("%X", reg.enable_polygon_offset_para.Value());
Text("%X", reg.enable_polygon_offset_para);
TableNextRow();
TableSetColumnIndex(0);
Text("VTX_WINDOW_OFFSET_ENABLE");
TableSetColumnIndex(1);
Text("%X", reg.enable_window_offset.Value());
Text("%X", reg.enable_window_offset);
TableNextRow();
TableSetColumnIndex(0);
Text("PROVOKING_VTX_LAST");
TableSetColumnIndex(1);
Text("%X (%s)", (u32)reg.provoking_vtx_last.Value(),
enum_name(reg.provoking_vtx_last.Value()).data());
Text("%X (%s)", static_cast<u32>(reg.provoking_vtx_last),
enum_name(reg.provoking_vtx_last).data());
TableNextRow();
TableSetColumnIndex(0);
Text("PERSP_CORR_DIS");
TableSetColumnIndex(1);
Text("%X", reg.persp_corr_dis.Value());
Text("%X", reg.persp_corr_dis);
TableNextRow();
TableSetColumnIndex(0);
Text("MULTI_PRIM_IB_ENA");
TableSetColumnIndex(1);
Text("%X", reg.multi_prim_ib_ena.Value());
Text("%X", reg.multi_prim_ib_ena);
if (begin_table) {
EndTable();
@@ -155,7 +155,7 @@ void ParsePolygonControl(u32 value, bool begin_table) {
}
void ParseAaConfig(u32 value, bool begin_table) {
auto const reg = reinterpret_cast<Liverpool::AaConfig const&>(value);
auto const reg = reinterpret_cast<AmdGpu::AaConfig const&>(value);
if (!begin_table ||
BeginTable("PA_SC_AA_CONFIG", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
@@ -163,31 +163,31 @@ void ParseAaConfig(u32 value, bool begin_table) {
TableSetColumnIndex(0);
Text("MSAA_NUM_SAMPLES");
TableSetColumnIndex(1);
Text("%X", reg.msaa_num_samples.Value());
Text("%X", reg.msaa_num_samples);
TableNextRow();
TableSetColumnIndex(0);
Text("AA_MASK_CENTROID_DTMN");
TableSetColumnIndex(1);
Text("%X", reg.aa_mask_centroid_dtmn.Value());
Text("%X", reg.aa_mask_centroid_dtmn);
TableNextRow();
TableSetColumnIndex(0);
Text("MAX_SAMPLE_DIST");
TableSetColumnIndex(1);
Text("%X", reg.max_sample_dst.Value());
Text("%X", reg.max_sample_dst);
TableNextRow();
TableSetColumnIndex(0);
Text("MSAA_EXPOSED_SAMPLES");
TableSetColumnIndex(1);
Text("%X", reg.msaa_exposed_samples.Value());
Text("%X", reg.msaa_exposed_samples);
TableNextRow();
TableSetColumnIndex(0);
Text("DETAIL_TO_EXPOSED_MODE");
TableSetColumnIndex(1);
Text("%X", reg.detail_to_exposed_mode.Value());
Text("%X", reg.detail_to_exposed_mode);
if (begin_table) {
EndTable();
@@ -196,7 +196,7 @@ void ParseAaConfig(u32 value, bool begin_table) {
}
void ParseViewportControl(u32 value, bool begin_table) {
auto const reg = reinterpret_cast<Liverpool::ViewportControl const&>(value);
auto const reg = reinterpret_cast<AmdGpu::ViewportControl const&>(value);
if (!begin_table ||
BeginTable("PA_CL_VTE_CNTL", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
@@ -204,61 +204,61 @@ void ParseViewportControl(u32 value, bool begin_table) {
TableSetColumnIndex(0);
Text("VPORT_X_SCALE_ENA");
TableSetColumnIndex(1);
Text("%X", reg.xscale_enable.Value());
Text("%X", reg.xscale_enable);
TableNextRow();
TableSetColumnIndex(0);
Text("VPORT_X_OFFSET_ENA");
TableSetColumnIndex(1);
Text("%X", reg.yoffset_enable.Value());
Text("%X", reg.yoffset_enable);
TableNextRow();
TableSetColumnIndex(0);
Text("VPORT_Y_SCALE_ENA");
TableSetColumnIndex(1);
Text("%X", reg.yscale_enable.Value());
Text("%X", reg.yscale_enable);
TableNextRow();
TableSetColumnIndex(0);
Text("VPORT_Y_OFFSET_ENA");
TableSetColumnIndex(1);
Text("%X", reg.yoffset_enable.Value());
Text("%X", reg.yoffset_enable);
TableNextRow();
TableSetColumnIndex(0);
Text("VPORT_Z_SCALE_ENA");
TableSetColumnIndex(1);
Text("%X", reg.zscale_enable.Value());
Text("%X", reg.zscale_enable);
TableNextRow();
TableSetColumnIndex(0);
Text("VPORT_Z_OFFSET_ENA");
TableSetColumnIndex(1);
Text("%X", reg.zoffset_enable.Value());
Text("%X", reg.zoffset_enable);
TableNextRow();
TableSetColumnIndex(0);
Text("VTX_XY_FMT");
TableSetColumnIndex(1);
Text("%X", reg.xy_transformed.Value());
Text("%X", reg.xy_transformed);
TableNextRow();
TableSetColumnIndex(0);
Text("VTX_Z_FMT");
TableSetColumnIndex(1);
Text("%X", reg.z_transformed.Value());
Text("%X", reg.z_transformed);
TableNextRow();
TableSetColumnIndex(0);
Text("VTX_W0_FMT");
TableSetColumnIndex(1);
Text("%X", reg.w_transformed.Value());
Text("%X", reg.w_transformed);
TableNextRow();
TableSetColumnIndex(0);
Text("PERFCOUNTER_REF");
TableSetColumnIndex(1);
Text("%X", reg.perfcounter_ref.Value());
Text("%X", reg.perfcounter_ref);
if (begin_table) {
EndTable();
@@ -267,7 +267,7 @@ void ParseViewportControl(u32 value, bool begin_table) {
}
void ParseColorControl(u32 value, bool begin_table) {
auto const reg = reinterpret_cast<Liverpool::ColorControl const&>(value);
auto const reg = reinterpret_cast<AmdGpu::ColorControl const&>(value);
if (!begin_table ||
BeginTable("CB_COLOR_CONTROL", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
@@ -275,25 +275,25 @@ void ParseColorControl(u32 value, bool begin_table) {
TableSetColumnIndex(0);
Text("DISABLE_DUAL_QUAD__VI");
TableSetColumnIndex(1);
Text("%X", reg.disable_dual_quad.Value());
Text("%X", reg.disable_dual_quad);
TableNextRow();
TableSetColumnIndex(0);
Text("DEGAMMA_ENABLE");
TableSetColumnIndex(1);
Text("%X", reg.degamma_enable.Value());
Text("%X", reg.degamma_enable);
TableNextRow();
TableSetColumnIndex(0);
Text("MODE");
TableSetColumnIndex(1);
Text("%X (%s)", (u32)reg.mode.Value(), enum_name(reg.mode.Value()).data());
Text("%X (%s)", static_cast<u32>(reg.mode), enum_name(reg.mode).data());
TableNextRow();
TableSetColumnIndex(0);
Text("ROP3");
TableSetColumnIndex(1);
Text("%X", static_cast<u32>(reg.rop3.Value()));
Text("%X", static_cast<u32>(reg.rop3));
if (begin_table) {
EndTable();
@@ -302,7 +302,7 @@ void ParseColorControl(u32 value, bool begin_table) {
}
void ParseColor0Info(u32 value, bool begin_table) {
auto const reg = reinterpret_cast<Liverpool::ColorBuffer::Color0Info const&>(value);
auto const reg = reinterpret_cast<AmdGpu::ColorBuffer::Color0Info const&>(value);
if (!begin_table ||
BeginTable("CB_COLOR_INFO", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
@@ -310,109 +310,109 @@ void ParseColor0Info(u32 value, bool begin_table) {
TableSetColumnIndex(0);
Text("ENDIAN");
TableSetColumnIndex(1);
Text("%s", enum_name(reg.endian.Value()).data());
Text("%s", enum_name(reg.endian).data());
TableNextRow();
TableSetColumnIndex(0);
Text("FORMAT");
TableSetColumnIndex(1);
Text("%s", enum_name(reg.format.Value()).data());
Text("%s", enum_name(AmdGpu::DataFormat(reg.format)).data());
TableNextRow();
TableSetColumnIndex(0);
Text("LINEAR_GENERAL");
TableSetColumnIndex(1);
Text("%X", reg.linear_general.Value());
Text("%X", reg.linear_general);
TableNextRow();
TableSetColumnIndex(0);
Text("NUMBER_TYPE");
TableSetColumnIndex(1);
Text("%s", enum_name(reg.number_type.Value()).data());
Text("%s", enum_name(AmdGpu::NumberFormat(reg.number_type)).data());
TableNextRow();
TableSetColumnIndex(0);
Text("COMP_SWAP");
TableSetColumnIndex(1);
Text("%s", enum_name(reg.comp_swap.Value()).data());
Text("%s", enum_name(reg.comp_swap).data());
TableNextRow();
TableSetColumnIndex(0);
Text("FAST_CLEAR");
TableSetColumnIndex(1);
Text("%X", reg.fast_clear.Value());
Text("%X", reg.fast_clear);
TableNextRow();
TableSetColumnIndex(0);
Text("COMPRESSION");
TableSetColumnIndex(1);
Text("%X", reg.compression.Value());
Text("%X", reg.compression);
TableNextRow();
TableSetColumnIndex(0);
Text("BLEND_CLAMP");
TableSetColumnIndex(1);
Text("%X", reg.blend_clamp.Value());
Text("%X", reg.blend_clamp);
TableNextRow();
TableSetColumnIndex(0);
Text("BLEND_BYPASS");
TableSetColumnIndex(1);
Text("%X", reg.blend_bypass.Value());
Text("%X", reg.blend_bypass);
TableNextRow();
TableSetColumnIndex(0);
Text("SIMPLE_FLOAT");
TableSetColumnIndex(1);
Text("%X", reg.simple_float.Value());
Text("%X", reg.simple_float);
TableNextRow();
TableSetColumnIndex(0);
Text("ROUND_MODE");
TableSetColumnIndex(1);
Text("%X (%s)", (u32)reg.round_mode.Value(), enum_name(reg.round_mode.Value()).data());
Text("%X (%s)", static_cast<u32>(reg.round_mode), enum_name(reg.round_mode).data());
TableNextRow();
TableSetColumnIndex(0);
Text("CMASK_IS_LINEAR");
TableSetColumnIndex(1);
Text("%X", reg.cmask_is_linear.Value());
Text("%X", reg.cmask_is_linear);
TableNextRow();
TableSetColumnIndex(0);
Text("BLEND_OPT_DONT_RD_DST");
TableSetColumnIndex(1);
Text("%X", reg.blend_opt_dont_rd_dst.Value());
Text("%X", reg.blend_opt_dont_rd_dst);
TableNextRow();
TableSetColumnIndex(0);
Text("BLEND_OPT_DISCARD_PIXEL");
TableSetColumnIndex(1);
Text("%X", reg.blend_opt_discard_pixel.Value());
Text("%X", reg.blend_opt_discard_pixel);
TableNextRow();
TableSetColumnIndex(0);
Text("FMASK_COMPRESSION_DISABLE__CI__VI");
TableSetColumnIndex(1);
Text("%X", reg.fmask_compression_disable_ci.Value());
Text("%X", reg.fmask_compression_disable_ci);
TableNextRow();
TableSetColumnIndex(0);
Text("FMASK_COMPRESS_1FRAG_ONLY__VI");
TableSetColumnIndex(1);
Text("%X", reg.fmask_compress_1frag_only.Value());
Text("%X", reg.fmask_compress_1frag_only);
TableNextRow();
TableSetColumnIndex(0);
Text("DCC_ENABLE__VI");
TableSetColumnIndex(1);
Text("%X", reg.dcc_enable.Value());
Text("%X", reg.dcc_enable);
TableNextRow();
TableSetColumnIndex(0);
Text("CMASK_ADDR_TYPE__VI");
TableSetColumnIndex(1);
Text("%X", reg.cmask_addr_type.Value());
Text("%X", reg.cmask_addr_type);
if (begin_table) {
EndTable();
@@ -421,7 +421,7 @@ void ParseColor0Info(u32 value, bool begin_table) {
}
void ParseColor0Attrib(u32 value, bool begin_table) {
auto const reg = reinterpret_cast<Liverpool::ColorBuffer::Color0Attrib const&>(value);
auto const reg = reinterpret_cast<AmdGpu::ColorBuffer::Color0Attrib const&>(value);
if (!begin_table ||
BeginTable("CB_COLOR_ATTRIB", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
@@ -429,37 +429,37 @@ void ParseColor0Attrib(u32 value, bool begin_table) {
TableSetColumnIndex(0);
Text("TILE_MODE_INDEX");
TableSetColumnIndex(1);
Text("%s", enum_name(reg.tile_mode_index.Value()).data());
Text("%s", enum_name(reg.tile_mode_index).data());
TableNextRow();
TableSetColumnIndex(0);
Text("FMASK_TILE_MODE_INDEX");
TableSetColumnIndex(1);
Text("%X", reg.fmask_tile_mode_index.Value());
Text("%X", reg.fmask_tile_mode_index);
TableNextRow();
TableSetColumnIndex(0);
Text("FMASK_BANK_HEIGHT");
TableSetColumnIndex(1);
Text("%X", reg.fmask_bank_height.Value());
Text("%X", reg.fmask_bank_height);
TableNextRow();
TableSetColumnIndex(0);
Text("NUM_SAMPLES");
TableSetColumnIndex(1);
Text("%X", reg.num_samples_log2.Value());
Text("%X", reg.num_samples_log2);
TableNextRow();
TableSetColumnIndex(0);
Text("NUM_FRAGMENTS");
TableSetColumnIndex(1);
Text("%X", reg.num_fragments_log2.Value());
Text("%X", reg.num_fragments_log2);
TableNextRow();
TableSetColumnIndex(0);
Text("FORCE_DST_ALPHA_1");
TableSetColumnIndex(1);
Text("%X", reg.force_dst_alpha_1.Value());
Text("%X", reg.force_dst_alpha_1);
if (begin_table) {
EndTable();
@@ -468,7 +468,7 @@ void ParseColor0Attrib(u32 value, bool begin_table) {
}
void ParseBlendControl(u32 value, bool begin_table) {
auto const reg = reinterpret_cast<Liverpool::BlendControl const&>(value);
auto const reg = reinterpret_cast<AmdGpu::BlendControl const&>(value);
if (!begin_table ||
BeginTable("CB_BLEND_CONTROL", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
@@ -476,59 +476,59 @@ void ParseBlendControl(u32 value, bool begin_table) {
TableSetColumnIndex(0);
Text("COLOR_SRCBLEND");
TableSetColumnIndex(1);
Text("%X (%s)", (u32)reg.color_src_factor.Value(),
enum_name(reg.color_src_factor.Value()).data());
Text("%X (%s)", static_cast<u32>(reg.color_src_factor),
enum_name(reg.color_src_factor).data());
TableNextRow();
TableSetColumnIndex(0);
Text("COLOR_COMB_FCN");
TableSetColumnIndex(1);
Text("%X (%s)", (u32)reg.color_func.Value(), enum_name(reg.color_func.Value()).data());
Text("%X (%s)", static_cast<u32>(reg.color_func), enum_name(reg.color_func).data());
TableNextRow();
TableSetColumnIndex(0);
Text("COLOR_DESTBLEND");
TableSetColumnIndex(1);
Text("%X (%s)", (u32)reg.color_dst_factor.Value(),
enum_name(reg.color_dst_factor.Value()).data());
Text("%X (%s)", static_cast<u32>(reg.color_dst_factor),
enum_name(reg.color_dst_factor).data());
TableNextRow();
TableSetColumnIndex(0);
Text("ALPHA_SRCBLEND");
TableSetColumnIndex(1);
Text("%X (%s)", (u32)reg.alpha_src_factor.Value(),
enum_name(reg.alpha_src_factor.Value()).data());
Text("%X (%s)", static_cast<u32>(reg.alpha_src_factor),
enum_name(reg.alpha_src_factor).data());
TableNextRow();
TableSetColumnIndex(0);
Text("ALPHA_COMB_FCN");
TableSetColumnIndex(1);
Text("%X (%s)", (u32)reg.alpha_func.Value(), enum_name(reg.alpha_func.Value()).data());
Text("%X (%s)", static_cast<u32>(reg.alpha_func), enum_name(reg.alpha_func).data());
TableNextRow();
TableSetColumnIndex(0);
Text("ALPHA_DESTBLEND");
TableSetColumnIndex(1);
Text("%X (%s)", (u32)reg.alpha_dst_factor.Value(),
enum_name(reg.alpha_dst_factor.Value()).data());
Text("%X (%s)", static_cast<u32>(reg.alpha_dst_factor),
enum_name(reg.alpha_dst_factor).data());
TableNextRow();
TableSetColumnIndex(0);
Text("SEPARATE_ALPHA_BLEND");
TableSetColumnIndex(1);
Text("%X", reg.separate_alpha_blend.Value());
Text("%X", reg.separate_alpha_blend);
TableNextRow();
TableSetColumnIndex(0);
Text("ENABLE");
TableSetColumnIndex(1);
Text("%X", reg.enable.Value());
Text("%X", reg.enable);
TableNextRow();
TableSetColumnIndex(0);
Text("DISABLE_ROP3");
TableSetColumnIndex(1);
Text("%X", reg.disable_rop3.Value());
Text("%X", reg.disable_rop3);
if (begin_table) {
EndTable();
@@ -537,7 +537,7 @@ void ParseBlendControl(u32 value, bool begin_table) {
}
void ParseDepthRenderControl(u32 value, bool begin_table) {
auto const reg = reinterpret_cast<Liverpool::DepthRenderControl const&>(value);
auto const reg = reinterpret_cast<AmdGpu::DepthRenderControl const&>(value);
if (!begin_table ||
BeginTable("DB_RENDER_CONTROL", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
@@ -545,61 +545,61 @@ void ParseDepthRenderControl(u32 value, bool begin_table) {
TableSetColumnIndex(0);
Text("DEPTH_CLEAR_ENABLE");
TableSetColumnIndex(1);
Text("%X", reg.depth_clear_enable.Value());
Text("%X", reg.depth_clear_enable);
TableNextRow();
TableSetColumnIndex(0);
Text("STENCIL_CLEAR_ENABLE");
TableSetColumnIndex(1);
Text("%X", reg.stencil_clear_enable.Value());
Text("%X", reg.stencil_clear_enable);
TableNextRow();
TableSetColumnIndex(0);
Text("DEPTH_COPY");
TableSetColumnIndex(1);
Text("%X", reg.depth_clear_enable.Value());
Text("%X", reg.depth_clear_enable);
TableNextRow();
TableSetColumnIndex(0);
Text("STENCIL_COPY");
TableSetColumnIndex(1);
Text("%X", reg.stencil_copy.Value());
Text("%X", reg.stencil_copy);
TableNextRow();
TableSetColumnIndex(0);
Text("RESUMMARIZE_ENABLE");
TableSetColumnIndex(1);
Text("%X", reg.resummarize_enable.Value());
Text("%X", reg.resummarize_enable);
TableNextRow();
TableSetColumnIndex(0);
Text("STENCIL_COMPRESS_DISABLE");
TableSetColumnIndex(1);
Text("%X", reg.stencil_compress_disable.Value());
Text("%X", reg.stencil_compress_disable);
TableNextRow();
TableSetColumnIndex(0);
Text("DEPTH_COMPRESS_DISABLE");
TableSetColumnIndex(1);
Text("%X", reg.depth_compress_disable.Value());
Text("%X", reg.depth_compress_disable);
TableNextRow();
TableSetColumnIndex(0);
Text("COPY_CENTROID");
TableSetColumnIndex(1);
Text("%X", reg.copy_centroid.Value());
Text("%X", reg.copy_centroid);
TableNextRow();
TableSetColumnIndex(0);
Text("COPY_SAMPLE");
TableSetColumnIndex(1);
Text("%X", reg.copy_sample.Value());
Text("%X", reg.copy_sample);
TableNextRow();
TableSetColumnIndex(0);
Text("DECOMPRESS_ENABLE__VI");
TableSetColumnIndex(1);
Text("%X", reg.decompress_enable.Value());
Text("%X", reg.decompress_enable);
if (begin_table) {
EndTable();
@@ -608,7 +608,7 @@ void ParseDepthRenderControl(u32 value, bool begin_table) {
}
void ParseDepthControl(u32 value, bool begin_table) {
auto const reg = reinterpret_cast<Liverpool::DepthControl const&>(value);
auto const reg = reinterpret_cast<AmdGpu::DepthControl const&>(value);
if (!begin_table ||
BeginTable("DB_DEPTH_CONTROL", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
@@ -616,63 +616,63 @@ void ParseDepthControl(u32 value, bool begin_table) {
TableSetColumnIndex(0);
Text("STENCIL_ENABLE");
TableSetColumnIndex(1);
Text("%X", reg.stencil_enable.Value());
Text("%X", reg.stencil_enable);
TableNextRow();
TableSetColumnIndex(0);
Text("Z_ENABLE");
TableSetColumnIndex(1);
Text("%X", reg.depth_enable.Value());
Text("%X", reg.depth_enable);
TableNextRow();
TableSetColumnIndex(0);
Text("Z_WRITE_ENABLE");
TableSetColumnIndex(1);
Text("%X", reg.depth_write_enable.Value());
Text("%X", reg.depth_write_enable);
TableNextRow();
TableSetColumnIndex(0);
Text("DEPTH_BOUNDS_ENABLE");
TableSetColumnIndex(1);
Text("%X", reg.depth_bounds_enable.Value());
Text("%X", reg.depth_bounds_enable);
TableNextRow();
TableSetColumnIndex(0);
Text("ZFUNC");
TableSetColumnIndex(1);
Text("%X (%s)", (u32)reg.depth_func.Value(), enum_name(reg.depth_func.Value()).data());
Text("%X (%s)", static_cast<u32>(reg.depth_func), enum_name(reg.depth_func).data());
TableNextRow();
TableSetColumnIndex(0);
Text("BACKFACE_ENABLE");
TableSetColumnIndex(1);
Text("%X", reg.backface_enable.Value());
Text("%X", reg.backface_enable);
TableNextRow();
TableSetColumnIndex(0);
Text("STENCILFUNC");
TableSetColumnIndex(1);
Text("%X (%s)", (u32)reg.stencil_ref_func.Value(),
enum_name(reg.stencil_ref_func.Value()).data());
Text("%X (%s)", static_cast<u32>(reg.stencil_ref_func),
enum_name(reg.stencil_ref_func).data());
TableNextRow();
TableSetColumnIndex(0);
Text("STENCILFUNC_BF");
TableSetColumnIndex(1);
Text("%X (%s)", (u32)reg.stencil_bf_func.Value(),
enum_name(reg.stencil_bf_func.Value()).data());
Text("%X (%s)", static_cast<u32>(reg.stencil_bf_func),
enum_name(reg.stencil_bf_func).data());
TableNextRow();
TableSetColumnIndex(0);
Text("ENABLE_COLOR_WRITES_ON_DEPTH_FAIL");
TableSetColumnIndex(1);
Text("%X", reg.enable_color_writes_on_depth_fail.Value());
Text("%X", reg.enable_color_writes_on_depth_fail);
TableNextRow();
TableSetColumnIndex(0);
Text("DISABLE_COLOR_WRITES_ON_DEPTH_PASS");
TableSetColumnIndex(1);
Text("%X", reg.disable_color_writes_on_depth_pass.Value());
Text("%X", reg.disable_color_writes_on_depth_pass);
if (begin_table) {
EndTable();
@@ -681,7 +681,7 @@ void ParseDepthControl(u32 value, bool begin_table) {
}
void ParseEqaa(u32 value, bool begin_table) {
auto const reg = reinterpret_cast<Liverpool::Eqaa const&>(value);
auto const reg = reinterpret_cast<AmdGpu::Eqaa const&>(value);
if (!begin_table ||
BeginTable("DB_DEPTH_CONTROL", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
@@ -689,73 +689,73 @@ void ParseEqaa(u32 value, bool begin_table) {
TableSetColumnIndex(0);
Text("MAX_ANCHOR_SAMPLES");
TableSetColumnIndex(1);
Text("%X", reg.max_anchor_samples.Value());
Text("%X", reg.max_anchor_samples);
TableNextRow();
TableSetColumnIndex(0);
Text("PS_ITER_SAMPLES");
TableSetColumnIndex(1);
Text("%X", reg.ps_iter_samples.Value());
Text("%X", reg.ps_iter_samples);
TableNextRow();
TableSetColumnIndex(0);
Text("MASK_EXPORT_NUM_SAMPLES");
TableSetColumnIndex(1);
Text("%X", reg.mask_export_num_samples.Value());
Text("%X", reg.mask_export_num_samples);
TableNextRow();
TableSetColumnIndex(0);
Text("ALPHA_TO_MASK_NUM_SAMPLES");
TableSetColumnIndex(1);
Text("%X", reg.alpha_to_mask_num_samples.Value());
Text("%X", reg.alpha_to_mask_num_samples);
TableNextRow();
TableSetColumnIndex(0);
Text("HIGH_QUALITY_INTERSECTIONS");
TableSetColumnIndex(1);
Text("%X", reg.high_quality_intersections.Value());
Text("%X", reg.high_quality_intersections);
TableNextRow();
TableSetColumnIndex(0);
Text("INCOHERENT_EQAA_READS");
TableSetColumnIndex(1);
Text("%X", reg.incoherent_eqaa_reads.Value());
Text("%X", reg.incoherent_eqaa_reads);
TableNextRow();
TableSetColumnIndex(0);
Text("INTERPOLATE_COMP_Z");
TableSetColumnIndex(1);
Text("%X", reg.interpolate_comp_z.Value());
Text("%X", reg.interpolate_comp_z);
TableNextRow();
TableSetColumnIndex(0);
Text("INTERPOLATE_SRC_Z");
TableSetColumnIndex(1);
Text("%X", reg.interpolate_src_z.Value());
Text("%X", reg.interpolate_src_z);
TableNextRow();
TableSetColumnIndex(0);
Text("STATIC_ANCHOR_ASSOCIATIONS");
TableSetColumnIndex(1);
Text("%X", reg.static_anchor_associations.Value());
Text("%X", reg.static_anchor_associations);
TableNextRow();
TableSetColumnIndex(0);
Text("ALPHA_TO_MASK_EQAA_DISABLE");
TableSetColumnIndex(1);
Text("%X", reg.alpha_to_mask_eqaa_disable.Value());
Text("%X", reg.alpha_to_mask_eqaa_disable);
TableNextRow();
TableSetColumnIndex(0);
Text("OVERRASTERIZATION_AMOUNT");
TableSetColumnIndex(1);
Text("%X", reg.overrasterization_amount.Value());
Text("%X", reg.overrasterization_amount);
TableNextRow();
TableSetColumnIndex(0);
Text("ENABLE_POSTZ_OVERRASTERIZATION");
TableSetColumnIndex(1);
Text("%X", reg.enable_postz_overrasterization.Value());
Text("%X", reg.enable_postz_overrasterization);
if (begin_table) {
EndTable();
@@ -764,7 +764,7 @@ void ParseEqaa(u32 value, bool begin_table) {
}
void ParseZInfo(u32 value, bool begin_table) {
auto const reg = reinterpret_cast<Liverpool::DepthBuffer::ZInfo const&>(value);
auto const reg = reinterpret_cast<AmdGpu::DepthBuffer::ZInfo const&>(value);
if (!begin_table ||
BeginTable("DB_DEPTH_CONTROL", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
@@ -772,61 +772,61 @@ void ParseZInfo(u32 value, bool begin_table) {
TableSetColumnIndex(0);
Text("FORMAT");
TableSetColumnIndex(1);
Text("%X (%s)", (u32)reg.format.Value(), enum_name(reg.format.Value()).data());
Text("%X (%s)", static_cast<u32>(reg.format), enum_name(reg.format).data());
TableNextRow();
TableSetColumnIndex(0);
Text("NUM_SAMPLES");
TableSetColumnIndex(1);
Text("%X", reg.num_samples.Value());
Text("%X", reg.num_samples);
TableNextRow();
TableSetColumnIndex(0);
Text("TILE_SPLIT__CI__VI");
TableSetColumnIndex(1);
Text("%X", reg.tile_split.Value());
Text("%X", reg.tile_split);
TableNextRow();
TableSetColumnIndex(0);
Text("TILE_MODE_INDEX");
TableSetColumnIndex(1);
Text("%X", static_cast<u32>(reg.tile_mode_index.Value()));
Text("%X", static_cast<u32>(reg.tile_mode_index));
TableNextRow();
TableSetColumnIndex(0);
Text("DECOMPRESS_ON_N_ZPLANES__VI");
TableSetColumnIndex(1);
Text("%X", reg.decompress_on_n_zplanes.Value());
Text("%X", reg.decompress_on_n_zplanes);
TableNextRow();
TableSetColumnIndex(0);
Text("ALLOW_EXPCLEAR");
TableSetColumnIndex(1);
Text("%X", reg.allow_expclear.Value());
Text("%X", reg.allow_expclear);
TableNextRow();
TableSetColumnIndex(0);
Text("READ_SIZE");
TableSetColumnIndex(1);
Text("%X", reg.read_size.Value());
Text("%X", reg.read_size);
TableNextRow();
TableSetColumnIndex(0);
Text("TILE_SURFACE_ENABLE");
TableSetColumnIndex(1);
Text("%X", reg.tile_surface_en.Value());
Text("%X", reg.tile_surface_enable);
TableNextRow();
TableSetColumnIndex(0);
Text("CLEAR_DISALLOWED__VI");
TableSetColumnIndex(1);
Text("%X", reg.clear_disallowed.Value());
Text("%X", reg.clear_disallowed);
TableNextRow();
TableSetColumnIndex(0);
Text("ZRANGE_PRECISION");
TableSetColumnIndex(1);
Text("%X", reg.zrange_precision.Value());
Text("%X", reg.zrange_precision);
if (begin_table) {
EndTable();
@@ -1515,4 +1515,4 @@ void CmdListViewer::Draw(bool only_batches_view, CmdListFilter& filter) {
PopID();
}
} // namespace Core::Devtools::Widget
} // namespace Core::Devtools::Widget

View File

@@ -5,14 +5,13 @@
#pragma once
#include <memory>
#include <vector>
#include <imgui.h>
#include "common.h"
#include "common/types.h"
#include "imgui_memory_editor.h"
#include "reg_view.h"
#include "core/devtools/widget/imgui_memory_editor.h"
#include "core/devtools/widget/reg_view.h"
namespace AmdGpu {
union PM4Type3Header;

View File

@@ -152,7 +152,7 @@ inline std::string RunDisassembler(const std::string& disassembler_cli, const T&
}
} else {
cli.replace(pos, src_arg.size(), "\"" + bin_path.string() + "\"");
Common::FS::IOFile file(bin_path, Common::FS::FileAccessMode::Write);
Common::FS::IOFile file(bin_path, Common::FS::FileAccessMode::Create);
file.Write(shader_code);
file.Close();

View File

@@ -118,11 +118,12 @@ void FrameDumpViewer::Draw() {
SameLine();
BeginDisabled(selected_cmd == -1);
if (SmallButton("Dump cmd")) {
auto now_time = fmt::localtime(std::time(nullptr));
auto time = std::time(nullptr);
auto now_time = *std::localtime(&time);
const auto fname = fmt::format("{:%F %H-%M-%S} {}_{}_{}.bin", now_time,
magic_enum::enum_name(selected_queue_type),
selected_submit_num, selected_queue_num2);
Common::FS::IOFile file(fname, Common::FS::FileAccessMode::Write);
Common::FS::IOFile file(fname, Common::FS::FileAccessMode::Create);
const auto& data = frame_dump->queues[selected_cmd].data;
if (file.IsOpen()) {
DebugState.ShowDebugMessage(fmt::format("Dumping cmd as {}", fname));

View File

@@ -44,7 +44,7 @@ bool MemoryMapViewer::Iterator::DrawLine() {
return false;
}
auto m = dmem.it->second;
if (m.is_free) {
if (m.dma_type == DMAType::Free) {
++dmem.it;
return DrawLine();
}
@@ -56,7 +56,7 @@ bool MemoryMapViewer::Iterator::DrawLine() {
auto type = static_cast<::Libraries::Kernel::MemoryTypes>(m.memory_type);
Text("%s", magic_enum::enum_name(type).data());
TableNextColumn();
Text("%d", m.is_pooled);
Text("%d", m.dma_type == DMAType::Pooled || m.dma_type == DMAType::Committed);
++dmem.it;
return true;
}

View File

@@ -8,6 +8,7 @@
#include <mutex>
#include <string>
#include <vector>
#include "common/config.h"
#include "common/elf_info.h"
#include "common/path_util.h"
@@ -22,7 +23,7 @@ public:
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 sys_modules_path = Config::getSysModulesPath();
const auto abs_path = std::filesystem::absolute(path).lexically_normal();
const auto abs_sys_path = std::filesystem::absolute(sys_modules_path).lexically_normal();

View File

@@ -16,7 +16,7 @@ using magic_enum::enum_name;
namespace Core::Devtools::Widget {
void RegPopup::DrawColorBuffer(const AmdGpu::Liverpool::ColorBuffer& buffer) {
void RegPopup::DrawColorBuffer(const AmdGpu::ColorBuffer& buffer) {
if (BeginTable("COLOR_BUFFER", 2, ImGuiTableFlags_Borders)) {
TableNextRow();
@@ -36,7 +36,7 @@ void RegPopup::DrawColorBuffer(const AmdGpu::Liverpool::ColorBuffer& buffer) {
if (TreeNode("Color0Info")) {
TableNextRow();
TableNextColumn();
ParseColor0Info(buffer.info.u32all, false);
ParseColor0Info(buffer.info.raw, false);
TreePop();
}
@@ -45,7 +45,7 @@ void RegPopup::DrawColorBuffer(const AmdGpu::Liverpool::ColorBuffer& buffer) {
if (TreeNode("Color0Attrib")) {
TableNextRow();
TableNextColumn();
ParseColor0Attrib(buffer.attrib.u32all, false);
ParseColor0Attrib(buffer.attrib.raw, false);
TreePop();
}
@@ -75,9 +75,8 @@ void RegPopup::DrawColorBuffer(const AmdGpu::Liverpool::ColorBuffer& buffer) {
}
}
void RegPopup::DrawDepthBuffer(const DepthBuffer& depth_data) {
const auto& [depth_buffer, depth_control] = depth_data;
void RegPopup::DrawDepthBuffer(const AmdGpu::DepthBuffer& buffer,
const AmdGpu::DepthControl control) {
SeparatorText("Depth buffer");
if (BeginTable("DEPTH_BUFFER", 2, ImGuiTableFlags_Borders)) {
@@ -85,31 +84,31 @@ void RegPopup::DrawDepthBuffer(const DepthBuffer& depth_data) {
// clang-format off
DrawValueRowList(
"Z_INFO.FORMAT", depth_buffer.z_info.format,
"Z_INFO.NUM_SAMPLES", depth_buffer.z_info.num_samples,
"Z_INFO.TILE_SPLIT", depth_buffer.z_info.tile_split,
"Z_INFO.TILE_MODE_INDEX", depth_buffer.z_info.tile_mode_index,
"Z_INFO.DECOMPRESS_ON_N_ZPLANES", depth_buffer.z_info.decompress_on_n_zplanes,
"Z_INFO.ALLOW_EXPCLEAR", depth_buffer.z_info.allow_expclear,
"Z_INFO.READ_SIZE", depth_buffer.z_info.read_size,
"Z_INFO.TILE_SURFACE_EN", depth_buffer.z_info.tile_surface_en,
"Z_INFO.CLEAR_DISALLOWED", depth_buffer.z_info.clear_disallowed,
"Z_INFO.ZRANGE_PRECISION", depth_buffer.z_info.zrange_precision,
"STENCIL_INFO.FORMAT", depth_buffer.stencil_info.format,
"Z_READ_BASE", depth_buffer.z_read_base,
"STENCIL_READ_BASE", depth_buffer.stencil_read_base,
"Z_WRITE_BASE", depth_buffer.z_write_base,
"STENCIL_WRITE_BASE", depth_buffer.stencil_write_base,
"DEPTH_SIZE.PITCH_TILE_MAX", depth_buffer.depth_size.pitch_tile_max,
"DEPTH_SIZE.HEIGHT_TILE_MAX", depth_buffer.depth_size.height_tile_max,
"DEPTH_SLICE.TILE_MAX", depth_buffer.depth_slice.tile_max,
"Pitch()", depth_buffer.Pitch(),
"Height()", depth_buffer.Height(),
"DepthAddress()", depth_buffer.DepthAddress(),
"StencilAddress()", depth_buffer.StencilAddress(),
"NumSamples()", depth_buffer.NumSamples(),
"NumBits()", depth_buffer.NumBits(),
"GetDepthSliceSize()", depth_buffer.GetDepthSliceSize()
"Z_INFO.FORMAT", buffer.z_info.format,
"Z_INFO.NUM_SAMPLES", buffer.z_info.num_samples,
"Z_INFO.TILE_SPLIT", buffer.z_info.tile_split,
"Z_INFO.TILE_MODE_INDEX", buffer.z_info.tile_mode_index,
"Z_INFO.DECOMPRESS_ON_N_ZPLANES", buffer.z_info.decompress_on_n_zplanes,
"Z_INFO.ALLOW_EXPCLEAR", buffer.z_info.allow_expclear,
"Z_INFO.READ_SIZE", buffer.z_info.read_size,
"Z_INFO.TILE_SURFACE_ENABLE", buffer.z_info.tile_surface_enable,
"Z_INFO.CLEAR_DISALLOWED", buffer.z_info.clear_disallowed,
"Z_INFO.ZRANGE_PRECISION", buffer.z_info.zrange_precision,
"STENCIL_INFO.FORMAT", buffer.stencil_info.format,
"Z_READ_BASE", buffer.z_read_base,
"STENCIL_READ_BASE", buffer.stencil_read_base,
"Z_WRITE_BASE", buffer.z_write_base,
"STENCIL_WRITE_BASE", buffer.stencil_write_base,
"DEPTH_SIZE.PITCH_TILE_MAX", buffer.depth_size.pitch_tile_max,
"DEPTH_SIZE.HEIGHT_TILE_MAX", buffer.depth_size.height_tile_max,
"DEPTH_SLICE.TILE_MAX", buffer.depth_slice.tile_max,
"Pitch()", buffer.Pitch(),
"Height()", buffer.Height(),
"DepthAddress()", buffer.DepthAddress(),
"StencilAddress()", buffer.StencilAddress(),
"NumSamples()", buffer.NumSamples(),
"NumBits()", buffer.NumBits(),
"GetDepthSliceSize()", buffer.GetDepthSliceSize()
);
// clang-format on
@@ -121,16 +120,16 @@ void RegPopup::DrawDepthBuffer(const DepthBuffer& depth_data) {
// clang-format off
DrawValueRowList(
"STENCIL_ENABLE", depth_control.stencil_enable,
"DEPTH_ENABLE", depth_control.depth_enable,
"DEPTH_WRITE_ENABLE", depth_control.depth_write_enable,
"DEPTH_BOUNDS_ENABLE", depth_control.depth_bounds_enable,
"DEPTH_FUNC", depth_control.depth_func,
"BACKFACE_ENABLE", depth_control.backface_enable,
"STENCIL_FUNC", depth_control.stencil_ref_func,
"STENCIL_FUNC_BF", depth_control.stencil_bf_func,
"ENABLE_COLOR_WRITES_ON_DEPTH_FAIL", depth_control.enable_color_writes_on_depth_fail,
"DISABLE_COLOR_WRITES_ON_DEPTH_PASS", depth_control.disable_color_writes_on_depth_pass
"STENCIL_ENABLE", control.stencil_enable,
"DEPTH_ENABLE", control.depth_enable,
"DEPTH_WRITE_ENABLE", control.depth_write_enable,
"DEPTH_BOUNDS_ENABLE", control.depth_bounds_enable,
"DEPTH_FUNC", control.depth_func,
"BACKFACE_ENABLE", control.backface_enable,
"STENCIL_FUNC", control.stencil_ref_func,
"STENCIL_FUNC_BF", control.stencil_bf_func,
"ENABLE_COLOR_WRITES_ON_DEPTH_FAIL", control.enable_color_writes_on_depth_fail,
"DISABLE_COLOR_WRITES_ON_DEPTH_PASS", control.disable_color_writes_on_depth_pass
);
// clang-format on
@@ -143,15 +142,17 @@ RegPopup::RegPopup() {
id = unique_id++;
}
void RegPopup::SetData(const std::string& base_title, AmdGpu::Liverpool::ColorBuffer color_buffer,
u32 cb_id) {
this->data = color_buffer;
void RegPopup::SetData(const std::string& base_title, AmdGpu::ColorBuffer color_buffer, u32 cb_id) {
this->type = DataType::Color;
this->color = color_buffer;
this->title = fmt::format("{}/CB #{}", base_title, cb_id);
}
void RegPopup::SetData(const std::string& base_title, AmdGpu::Liverpool::DepthBuffer depth_buffer,
AmdGpu::Liverpool::DepthControl depth_control) {
this->data = std::make_tuple(depth_buffer, depth_control);
void RegPopup::SetData(const std::string& base_title, AmdGpu::DepthBuffer depth_buffer,
AmdGpu::DepthControl depth_control) {
this->type = DataType::Depth;
this->depth.buffer = depth_buffer;
this->depth.control = depth_control;
this->title = fmt::format("{}/Depth", base_title);
}
@@ -161,10 +162,10 @@ void RegPopup::SetPos(ImVec2 pos, bool auto_resize) {
Begin(name, &open, flags);
SetWindowPos(pos);
if (auto_resize) {
if (std::holds_alternative<AmdGpu::Liverpool::ColorBuffer>(data)) {
if (type == DataType::Color) {
SetWindowSize({365.0f, 520.0f});
KeepWindowInside();
} else if (std::holds_alternative<DepthBuffer>(data)) {
} else if (type == DataType::Depth) {
SetWindowSize({404.0f, 543.0f});
KeepWindowInside();
}
@@ -182,10 +183,10 @@ void RegPopup::Draw() {
moved = true;
}
if (const auto* buffer = std::get_if<AmdGpu::Liverpool::ColorBuffer>(&data)) {
DrawColorBuffer(*buffer);
} else if (const auto* depth_data = std::get_if<DepthBuffer>(&data)) {
DrawDepthBuffer(*depth_data);
if (type == DataType::Color) {
DrawColorBuffer(color);
} else if (type == DataType::Depth) {
DrawDepthBuffer(depth.buffer, depth.control);
}
}
End();

View File

@@ -3,12 +3,10 @@
#pragma once
#include <variant>
#include <imgui.h>
#include "common/types.h"
#include "video_core/renderer_vulkan/liverpool_to_vk.h"
#include "video_core/amdgpu/regs_color.h"
#include "video_core/amdgpu/regs_depth.h"
namespace Core::Devtools::Widget {
@@ -16,15 +14,24 @@ class RegPopup {
int id;
ImGuiWindowFlags flags{ImGuiWindowFlags_NoSavedSettings};
using DepthBuffer = std::tuple<AmdGpu::Liverpool::DepthBuffer, AmdGpu::Liverpool::DepthControl>;
ImVec2 last_pos;
std::variant<AmdGpu::Liverpool::ColorBuffer, DepthBuffer> data;
AmdGpu::ColorBuffer color;
struct {
AmdGpu::DepthBuffer buffer;
AmdGpu::DepthControl control;
} depth;
enum class DataType {
None = 0,
Color = 1,
Depth = 2,
};
DataType type{};
std::string title{};
static void DrawColorBuffer(const AmdGpu::Liverpool::ColorBuffer& buffer);
static void DrawColorBuffer(const AmdGpu::ColorBuffer& buffer);
static void DrawDepthBuffer(const DepthBuffer& depth_data);
static void DrawDepthBuffer(const AmdGpu::DepthBuffer& buffer,
const AmdGpu::DepthControl control);
public:
bool open = false;
@@ -32,11 +39,10 @@ public:
RegPopup();
void SetData(const std::string& base_title, AmdGpu::Liverpool::ColorBuffer color_buffer,
u32 cb_id);
void SetData(const std::string& base_title, AmdGpu::ColorBuffer color_buffer, u32 cb_id);
void SetData(const std::string& base_title, AmdGpu::Liverpool::DepthBuffer depth_buffer,
AmdGpu::Liverpool::DepthControl depth_control);
void SetData(const std::string& base_title, AmdGpu::DepthBuffer depth_buffer,
AmdGpu::DepthControl depth_control);
void SetPos(ImVec2 pos, bool auto_resize = false);

View File

@@ -29,7 +29,7 @@ namespace Core::Devtools::Widget {
void RegView::ProcessShader(int shader_id) {
std::vector<u32> shader_code;
Vulkan::Liverpool::UserData user_data;
AmdGpu::UserData user_data;
if (data.is_compute) {
shader_code = data.cs_data.code;
user_data = data.cs_data.cs_program.user_data;
@@ -129,7 +129,7 @@ void RegView::DrawGraphicsRegs() {
}
};
for (int cb = 0; cb < AmdGpu::Liverpool::NumColorBuffers; ++cb) {
for (int cb = 0; cb < AmdGpu::NUM_COLOR_BUFFERS; ++cb) {
PushID(cb);
TableNextRow();
@@ -246,8 +246,7 @@ void RegView::SetData(DebugStateType::RegDump _data, const std::string& base_tit
default_reg_popup.SetData(title, regs.depth_buffer, regs.depth_control);
default_reg_popup.open = true;
}
} else if (last_selected_cb >= 0 &&
last_selected_cb < AmdGpu::Liverpool::NumColorBuffers) {
} else if (last_selected_cb >= 0 && last_selected_cb < AmdGpu::NUM_COLOR_BUFFERS) {
const auto& buffer = regs.color_buffers[last_selected_cb];
const bool has_cb = buffer && regs.color_target_mask.GetMask(last_selected_cb);
if (has_cb) {
@@ -348,7 +347,7 @@ void RegView::Draw() {
} else {
shader->hex_view.DrawContents(shader->user_data.data(),
shader->user_data.size() *
sizeof(Vulkan::Liverpool::UserData::value_type));
sizeof(AmdGpu::UserData::value_type));
}
}
End();
@@ -392,4 +391,4 @@ void RegView::Draw() {
}
}
} // namespace Core::Devtools::Widget
} // namespace Core::Devtools::Widget

View File

@@ -2,17 +2,18 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/debug_state.h"
#include "imgui_memory_editor.h"
#include "reg_popup.h"
#include "text_editor.h"
#include "core/devtools/widget/imgui_memory_editor.h"
#include "core/devtools/widget/reg_popup.h"
#include "core/devtools/widget/text_editor.h"
namespace Core::Devtools::Widget {
struct ShaderCache {
MemoryEditor hex_view;
TextEditor dis_view;
Vulkan::Liverpool::UserData user_data;
AmdGpu::UserData user_data;
};
class RegView {
@@ -54,4 +55,4 @@ public:
void Draw();
};
} // namespace Core::Devtools::Widget
} // namespace Core::Devtools::Widget

View File

@@ -36,6 +36,7 @@ bool PSF::Open(const std::filesystem::path& filepath) {
}
const u64 psfSize = file.GetSize();
ASSERT_MSG(psfSize != 0, "SFO file at {} is empty!", filepath.string());
std::vector<u8> psf(psfSize);
file.Seek(0);
file.Read(psf);
@@ -99,7 +100,7 @@ bool PSF::Open(const std::vector<u8>& psf_buffer) {
}
bool PSF::Encode(const std::filesystem::path& filepath) const {
Common::FS::IOFile file(filepath, Common::FS::FileAccessMode::Write);
Common::FS::IOFile file(filepath, Common::FS::FileAccessMode::Create);
if (!file.IsOpen()) {
return false;
}

View File

@@ -65,7 +65,7 @@ bool TRP::Extract(const std::filesystem::path& trophyPath, const std::string tit
const auto user_key_str = Config::getTrophyKey();
if (user_key_str.size() != 32) {
LOG_CRITICAL(Common_Filesystem, "Trophy decryption key is not specified");
LOG_INFO(Common_Filesystem, "Trophy decryption key is not specified");
return false;
}
@@ -105,7 +105,7 @@ bool TRP::Extract(const std::filesystem::path& trophyPath, const std::string tit
TrpEntry entry;
file.Read(entry);
std::string_view name(entry.entry_name);
if (entry.flag == 0 && name.find("TROP") != std::string::npos) { // PNG
if (entry.flag == 0) { // PNG
if (!file.Seek(entry.entry_pos)) {
LOG_CRITICAL(Common_Filesystem, "Failed to seek to TRP entry offset");
return false;

View File

@@ -1,7 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "base_device.h"
#include "core/file_sys/devices/base_device.h"
namespace Core::Devices {

View File

@@ -3,9 +3,9 @@
#pragma once
#include <core/libraries/kernel/orbis_error.h>
#include "common/types.h"
#include "common/va_ctx.h"
#include "core/libraries/kernel/orbis_error.h"
namespace Libraries::Kernel {
struct OrbisKernelStat;
@@ -20,27 +20,27 @@ public:
virtual ~BaseDevice() = 0;
virtual int ioctl(u64 cmd, Common::VaCtx* args) {
virtual s32 ioctl(u64 cmd, Common::VaCtx* args) {
return ORBIS_KERNEL_ERROR_ENOTTY;
}
virtual s64 write(const void* buf, size_t nbytes) {
virtual s64 write(const void* buf, u64 nbytes) {
return ORBIS_KERNEL_ERROR_EBADF;
}
virtual size_t readv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) {
virtual s64 readv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) {
return ORBIS_KERNEL_ERROR_EBADF;
}
virtual size_t writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) {
virtual s64 writev(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) {
return ORBIS_KERNEL_ERROR_EBADF;
}
virtual s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt, u64 offset) {
virtual s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt, s64 offset) {
return ORBIS_KERNEL_ERROR_EBADF;
}
virtual size_t pwritev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt, u64 offset) {
virtual s64 pwritev(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt, s64 offset) {
return ORBIS_KERNEL_ERROR_EBADF;
}
@@ -48,11 +48,11 @@ public:
return ORBIS_KERNEL_ERROR_EBADF;
}
virtual s64 read(void* buf, size_t nbytes) {
virtual s64 read(void* buf, u64 nbytes) {
return ORBIS_KERNEL_ERROR_EBADF;
}
virtual int fstat(Libraries::Kernel::OrbisKernelStat* sb) {
virtual s32 fstat(Libraries::Kernel::OrbisKernelStat* sb) {
return ORBIS_KERNEL_ERROR_EBADF;
}
@@ -60,15 +60,15 @@ public:
return ORBIS_KERNEL_ERROR_EBADF;
}
virtual int ftruncate(s64 length) {
virtual s32 ftruncate(s64 length) {
return ORBIS_KERNEL_ERROR_EBADF;
}
virtual int getdents(void* buf, u32 nbytes, s64* basep) {
virtual s64 getdents(void* buf, u32 nbytes, s64* basep) {
return ORBIS_KERNEL_ERROR_EBADF;
}
virtual s64 pwrite(const void* buf, size_t nbytes, u64 offset) {
virtual s64 pwrite(const void* buf, u64 nbytes, s64 offset) {
return ORBIS_KERNEL_ERROR_EBADF;
}
};

View File

@@ -2,72 +2,71 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
#include "console_device.h"
#include "core/file_sys/devices/console_device.h"
namespace Core::Devices {
std::shared_ptr<BaseDevice> ConsoleDevice::Create(u32 handle, const char*, int, u16) {
return std::shared_ptr<BaseDevice>(
reinterpret_cast<Devices::BaseDevice*>(new ConsoleDevice(handle)));
std::shared_ptr<BaseDevice> ConsoleDevice::Create(u32 handle, const char*, s32, u16) {
return std::static_pointer_cast<BaseDevice>(std::make_shared<ConsoleDevice>(handle));
}
int ConsoleDevice::ioctl(u64 cmd, Common::VaCtx* args) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s32 ConsoleDevice::ioctl(u64 cmd, Common::VaCtx* args) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called, cmd = {:#x}", cmd);
return 0;
}
s64 ConsoleDevice::write(const void* buf, size_t nbytes) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s64 ConsoleDevice::write(const void* buf, u64 nbytes) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
size_t ConsoleDevice::writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s64 ConsoleDevice::writev(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
size_t ConsoleDevice::readv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s64 ConsoleDevice::readv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
s64 ConsoleDevice::preadv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt, u64 offset) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s64 ConsoleDevice::preadv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt, s64 offset) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
s64 ConsoleDevice::lseek(s64 offset, int whence) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s64 ConsoleDevice::lseek(s64 offset, s32 whence) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
s64 ConsoleDevice::read(void* buf, size_t nbytes) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s64 ConsoleDevice::read(void* buf, u64 nbytes) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
int ConsoleDevice::fstat(Libraries::Kernel::OrbisKernelStat* sb) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s32 ConsoleDevice::fstat(Libraries::Kernel::OrbisKernelStat* sb) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
s32 ConsoleDevice::fsync() {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
int ConsoleDevice::ftruncate(s64 length) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s32 ConsoleDevice::ftruncate(s64 length) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
int ConsoleDevice::getdents(void* buf, u32 nbytes, s64* basep) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s64 ConsoleDevice::getdents(void* buf, u32 nbytes, s64* basep) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
s64 ConsoleDevice::pwrite(const void* buf, size_t nbytes, u64 offset) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s64 ConsoleDevice::pwrite(const void* buf, u64 nbytes, s64 offset) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}

View File

@@ -3,31 +3,31 @@
#pragma once
#include <memory>
#include "base_device.h"
#include "core/file_sys/devices/base_device.h"
namespace Core::Devices {
class ConsoleDevice final : BaseDevice {
class ConsoleDevice final : public BaseDevice {
u32 handle;
public:
static std::shared_ptr<BaseDevice> Create(u32 handle, const char*, int, u16);
static std::shared_ptr<BaseDevice> Create(u32 handle, const char*, s32, u16);
explicit ConsoleDevice(u32 handle) : handle(handle) {}
~ConsoleDevice() override = default;
int ioctl(u64 cmd, Common::VaCtx* args) override;
s64 write(const void* buf, size_t nbytes) override;
size_t readv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override;
size_t writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override;
s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt, u64 offset) override;
s64 lseek(s64 offset, int whence) override;
s64 read(void* buf, size_t nbytes) override;
int fstat(Libraries::Kernel::OrbisKernelStat* sb) override;
s32 ioctl(u64 cmd, Common::VaCtx* args) override;
s64 write(const void* buf, u64 nbytes) override;
s64 readv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) override;
s64 writev(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) override;
s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt, s64 offset) override;
s64 lseek(s64 offset, s32 whence) override;
s64 read(void* buf, u64 nbytes) override;
s32 fstat(Libraries::Kernel::OrbisKernelStat* sb) override;
s32 fsync() override;
int ftruncate(s64 length) override;
int getdents(void* buf, u32 nbytes, s64* basep) override;
s64 pwrite(const void* buf, size_t nbytes, u64 offset) override;
s32 ftruncate(s64 length) override;
s64 getdents(void* buf, u32 nbytes, s64* basep) override;
s64 pwrite(const void* buf, u64 nbytes, s64 offset) override;
};
} // namespace Core::Devices

View File

@@ -2,72 +2,71 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
#include "deci_tty6_device.h"
#include "core/file_sys/devices/deci_tty6_device.h"
namespace Core::Devices {
std::shared_ptr<BaseDevice> DeciTty6Device::Create(u32 handle, const char*, int, u16) {
return std::shared_ptr<BaseDevice>(
reinterpret_cast<Devices::BaseDevice*>(new DeciTty6Device(handle)));
std::shared_ptr<BaseDevice> DeciTty6Device::Create(u32 handle, const char*, s32, u16) {
return std::static_pointer_cast<BaseDevice>(std::make_shared<DeciTty6Device>(handle));
}
int DeciTty6Device::ioctl(u64 cmd, Common::VaCtx* args) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s32 DeciTty6Device::ioctl(u64 cmd, Common::VaCtx* args) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called, cmd = {:#x}", cmd);
return 0;
}
s64 DeciTty6Device::write(const void* buf, size_t nbytes) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s64 DeciTty6Device::write(const void* buf, u64 nbytes) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
size_t DeciTty6Device::writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s64 DeciTty6Device::writev(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
size_t DeciTty6Device::readv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s64 DeciTty6Device::readv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
s64 DeciTty6Device::preadv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt, u64 offset) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s64 DeciTty6Device::preadv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt, s64 offset) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
s64 DeciTty6Device::lseek(s64 offset, int whence) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s64 DeciTty6Device::lseek(s64 offset, s32 whence) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
s64 DeciTty6Device::read(void* buf, size_t nbytes) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s64 DeciTty6Device::read(void* buf, u64 nbytes) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
int DeciTty6Device::fstat(Libraries::Kernel::OrbisKernelStat* sb) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s32 DeciTty6Device::fstat(Libraries::Kernel::OrbisKernelStat* sb) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
s32 DeciTty6Device::fsync() {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
int DeciTty6Device::ftruncate(s64 length) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s32 DeciTty6Device::ftruncate(s64 length) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
int DeciTty6Device::getdents(void* buf, u32 nbytes, s64* basep) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s64 DeciTty6Device::getdents(void* buf, u32 nbytes, s64* basep) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
s64 DeciTty6Device::pwrite(const void* buf, size_t nbytes, u64 offset) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s64 DeciTty6Device::pwrite(const void* buf, u64 nbytes, s64 offset) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}

View File

@@ -3,31 +3,31 @@
#pragma once
#include <memory>
#include "base_device.h"
#include "core/file_sys/devices/base_device.h"
namespace Core::Devices {
class DeciTty6Device final : BaseDevice {
class DeciTty6Device final : public BaseDevice {
u32 handle;
public:
static std::shared_ptr<BaseDevice> Create(u32 handle, const char*, int, u16);
static std::shared_ptr<BaseDevice> Create(u32 handle, const char*, s32, u16);
explicit DeciTty6Device(u32 handle) : handle(handle) {}
~DeciTty6Device() override = default;
int ioctl(u64 cmd, Common::VaCtx* args) override;
s64 write(const void* buf, size_t nbytes) override;
size_t readv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override;
size_t writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override;
s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt, u64 offset) override;
s64 lseek(s64 offset, int whence) override;
s64 read(void* buf, size_t nbytes) override;
int fstat(Libraries::Kernel::OrbisKernelStat* sb) override;
s32 ioctl(u64 cmd, Common::VaCtx* args) override;
s64 write(const void* buf, u64 nbytes) override;
s64 readv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) override;
s64 writev(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) override;
s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt, s64 offset) override;
s64 lseek(s64 offset, s32 whence) override;
s64 read(void* buf, u64 nbytes) override;
s32 fstat(Libraries::Kernel::OrbisKernelStat* sb) override;
s32 fsync() override;
int ftruncate(s64 length) override;
int getdents(void* buf, u32 nbytes, s64* basep) override;
s64 pwrite(const void* buf, size_t nbytes, u64 offset) override;
s32 ftruncate(s64 length) override;
s64 getdents(void* buf, u32 nbytes, s64* basep) override;
s64 pwrite(const void* buf, u64 nbytes, s64 offset) override;
};
} // namespace Core::Devices

View File

@@ -2,8 +2,8 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
#include "core/file_sys/devices/logger.h"
#include "core/libraries/kernel/file_system.h"
#include "logger.h"
namespace Core::Devices {
@@ -11,13 +11,13 @@ Logger::Logger(std::string prefix, bool is_err) : prefix(std::move(prefix)), is_
Logger::~Logger() = default;
s64 Logger::write(const void* buf, size_t nbytes) {
s64 Logger::write(const void* buf, u64 nbytes) {
log(static_cast<const char*>(buf), nbytes);
return nbytes;
}
size_t Logger::writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) {
size_t total_written = 0;
s64 Logger::writev(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) {
u64 total_written = 0;
for (int i = 0; i < iovcnt; i++) {
log(static_cast<const char*>(iov[i].iov_base), iov[i].iov_len);
total_written += iov[i].iov_len;
@@ -25,7 +25,7 @@ size_t Logger::writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt
return total_written;
}
s64 Logger::pwrite(const void* buf, size_t nbytes, u64 offset) {
s64 Logger::pwrite(const void* buf, u64 nbytes, s64 offset) {
log(static_cast<const char*>(buf), nbytes);
return nbytes;
}
@@ -35,7 +35,7 @@ s32 Logger::fsync() {
return 0;
}
void Logger::log(const char* buf, size_t nbytes) {
void Logger::log(const char* buf, u64 nbytes) {
std::scoped_lock lock{mtx};
const char* end = buf + nbytes;
for (const char* it = buf; it < end; ++it) {

View File

@@ -3,7 +3,7 @@
#pragma once
#include "base_device.h"
#include "core/file_sys/devices/base_device.h"
#include <mutex>
#include <string>
@@ -23,14 +23,14 @@ public:
~Logger() override;
s64 write(const void* buf, size_t nbytes) override;
size_t writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override;
s64 pwrite(const void* buf, size_t nbytes, u64 offset) override;
s64 write(const void* buf, u64 nbytes) override;
s64 writev(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) override;
s64 pwrite(const void* buf, u64 nbytes, s64 offset) override;
s32 fsync() override;
private:
void log(const char* buf, size_t nbytes);
void log(const char* buf, u64 nbytes);
void log_flush();
};

View File

@@ -2,7 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "base_device.h"
#include "core/file_sys/devices/base_device.h"
namespace Core::Devices {
@@ -14,35 +14,35 @@ public:
~NopDevice() override = default;
int ioctl(u64 cmd, Common::VaCtx* args) override {
s32 ioctl(u64 cmd, Common::VaCtx* args) override {
return 0;
}
s64 write(const void* buf, size_t nbytes) override {
s64 write(const void* buf, u64 nbytes) override {
return 0;
}
size_t readv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override {
s64 readv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) override {
return 0;
}
size_t writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override {
s64 writev(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) override {
return 0;
}
s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt, u64 offset) override {
s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt, s64 offset) override {
return 0;
}
s64 lseek(s64 offset, int whence) override {
s64 lseek(s64 offset, s32 whence) override {
return 0;
}
s64 read(void* buf, size_t nbytes) override {
s64 read(void* buf, u64 nbytes) override {
return 0;
}
int fstat(Libraries::Kernel::OrbisKernelStat* sb) override {
s32 fstat(Libraries::Kernel::OrbisKernelStat* sb) override {
return 0;
}
@@ -50,15 +50,15 @@ public:
return 0;
}
int ftruncate(s64 length) override {
s32 ftruncate(s64 length) override {
return 0;
}
int getdents(void* buf, u32 nbytes, s64* basep) override {
s64 getdents(void* buf, u32 nbytes, s64* basep) override {
return 0;
}
s64 pwrite(const void* buf, size_t nbytes, u64 offset) override {
s64 pwrite(const void* buf, u64 nbytes, s64 offset) override {
return 0;
}
};

View File

@@ -4,75 +4,75 @@
#include <cstdlib>
#include <ctime>
#include "common/logging/log.h"
#include "random_device.h"
#include "core/file_sys/devices/random_device.h"
namespace Core::Devices {
std::shared_ptr<BaseDevice> RandomDevice::Create(u32 handle, const char*, int, u16) {
std::shared_ptr<BaseDevice> RandomDevice::Create(u32 handle, const char*, s32, u16) {
std::srand(std::time(nullptr));
return std::shared_ptr<BaseDevice>(
reinterpret_cast<Devices::BaseDevice*>(new RandomDevice(handle)));
return std::static_pointer_cast<BaseDevice>(std::make_shared<RandomDevice>(handle));
}
int RandomDevice::ioctl(u64 cmd, Common::VaCtx* args) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s32 RandomDevice::ioctl(u64 cmd, Common::VaCtx* args) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called, cmd = {:#x}", cmd);
return 0;
}
s64 RandomDevice::write(const void* buf, size_t nbytes) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s64 RandomDevice::write(const void* buf, u64 nbytes) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
size_t RandomDevice::writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s64 RandomDevice::writev(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
size_t RandomDevice::readv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s64 RandomDevice::readv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
s64 RandomDevice::preadv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt, u64 offset) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s64 RandomDevice::preadv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt, s64 offset) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
s64 RandomDevice::lseek(s64 offset, int whence) {
s64 RandomDevice::lseek(s64 offset, s32 whence) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
s64 RandomDevice::read(void* buf, size_t nbytes) {
auto rbuf = static_cast<char*>(buf);
for (size_t i = 0; i < nbytes; i++) {
s64 RandomDevice::read(void* buf, u64 nbytes) {
auto rbuf = static_cast<s8*>(buf);
for (u64 i = 0; i < nbytes; i++) {
rbuf[i] = std::rand() & 0xFF;
}
return nbytes;
}
int RandomDevice::fstat(Libraries::Kernel::OrbisKernelStat* sb) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s32 RandomDevice::fstat(Libraries::Kernel::OrbisKernelStat* sb) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
s32 RandomDevice::fsync() {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
int RandomDevice::ftruncate(s64 length) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s32 RandomDevice::ftruncate(s64 length) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
int RandomDevice::getdents(void* buf, u32 nbytes, s64* basep) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s64 RandomDevice::getdents(void* buf, u32 nbytes, s64* basep) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
s64 RandomDevice::pwrite(const void* buf, size_t nbytes, u64 offset) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s64 RandomDevice::pwrite(const void* buf, u64 nbytes, s64 offset) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}

View File

@@ -3,31 +3,31 @@
#pragma once
#include <memory>
#include "base_device.h"
#include "core/file_sys/devices/base_device.h"
namespace Core::Devices {
class RandomDevice final : BaseDevice {
class RandomDevice final : public BaseDevice {
u32 handle;
public:
static std::shared_ptr<BaseDevice> Create(u32 handle, const char*, int, u16);
static std::shared_ptr<BaseDevice> Create(u32 handle, const char*, s32, u16);
explicit RandomDevice(u32 handle) : handle(handle) {}
~RandomDevice() override = default;
int ioctl(u64 cmd, Common::VaCtx* args) override;
s64 write(const void* buf, size_t nbytes) override;
size_t readv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override;
size_t writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override;
s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt, u64 offset) override;
s64 lseek(s64 offset, int whence) override;
s64 read(void* buf, size_t nbytes) override;
int fstat(Libraries::Kernel::OrbisKernelStat* sb) override;
s32 ioctl(u64 cmd, Common::VaCtx* args) override;
s64 write(const void* buf, u64 nbytes) override;
s64 readv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) override;
s64 writev(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) override;
s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt, s64 offset) override;
s64 lseek(s64 offset, s32 whence) override;
s64 read(void* buf, u64 nbytes) override;
s32 fstat(Libraries::Kernel::OrbisKernelStat* sb) override;
s32 fsync() override;
int ftruncate(s64 length) override;
int getdents(void* buf, u32 nbytes, s64* basep) override;
s64 pwrite(const void* buf, size_t nbytes, u64 offset) override;
s32 ftruncate(s64 length) override;
s64 getdents(void* buf, u32 nbytes, s64* basep) override;
s64 pwrite(const void* buf, u64 nbytes, s64 offset) override;
};
} // namespace Core::Devices

View File

@@ -0,0 +1,87 @@
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <cstdlib>
#include <ctime>
#include "common/logging/log.h"
#include "core/file_sys/devices/rng_device.h"
namespace Core::Devices {
std::shared_ptr<BaseDevice> RngDevice::Create(u32 handle, const char*, s32, u16) {
std::srand(std::time(nullptr));
return std::static_pointer_cast<BaseDevice>(std::make_shared<RngDevice>(handle));
}
s32 RngDevice::ioctl(u64 cmd, Common::VaCtx* args) {
LOG_INFO(Kernel_Pthread, "called, cmd = {:#x}", cmd);
// Both commands are for generating a random number
if (cmd == 0x40445301 || cmd == 0x40445302) {
auto& data = *vaArgPtr<GetRandomArgs>(&args->va_list);
data.result = 0;
for (u64 i = 0; i < 64; i++) {
data.buf[i] = std::rand();
}
} else {
// ENOIOCTL
return -3;
}
return 0;
}
s64 RngDevice::write(const void* buf, u64 nbytes) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
s64 RngDevice::writev(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
s64 RngDevice::readv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
s64 RngDevice::preadv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt, s64 offset) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
s64 RngDevice::lseek(s64 offset, s32 whence) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
s64 RngDevice::read(void* buf, u64 nbytes) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
s32 RngDevice::fstat(Libraries::Kernel::OrbisKernelStat* sb) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
s32 RngDevice::fsync() {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
s32 RngDevice::ftruncate(s64 length) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
s64 RngDevice::getdents(void* buf, u32 nbytes, s64* basep) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
s64 RngDevice::pwrite(const void* buf, u64 nbytes, s64 offset) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
} // namespace Core::Devices

View File

@@ -0,0 +1,39 @@
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <memory>
#include "core/file_sys/devices/base_device.h"
namespace Core::Devices {
class RngDevice final : public BaseDevice {
u32 handle;
public:
static std::shared_ptr<BaseDevice> Create(u32 handle, const char*, s32, u16);
explicit RngDevice(u32 handle) : handle(handle) {}
~RngDevice() override = default;
s32 ioctl(u64 cmd, Common::VaCtx* args) override;
s64 write(const void* buf, u64 nbytes) override;
s64 readv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) override;
s64 writev(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) override;
s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt, s64 offset) override;
s64 lseek(s64 offset, s32 whence) override;
s64 read(void* buf, u64 nbytes) override;
s32 fstat(Libraries::Kernel::OrbisKernelStat* sb) override;
s32 fsync() override;
s32 ftruncate(s64 length) override;
s64 getdents(void* buf, u32 nbytes, s64* basep) override;
s64 pwrite(const void* buf, u64 nbytes, s64 offset) override;
private:
struct GetRandomArgs {
s32 result;
s8 buf[64];
};
};
} // namespace Core::Devices

View File

@@ -4,76 +4,75 @@
#include <cstdlib>
#include <ctime>
#include "common/logging/log.h"
#include "srandom_device.h"
#include "core/file_sys/devices/srandom_device.h"
namespace Core::Devices {
std::shared_ptr<BaseDevice> SRandomDevice::Create(u32 handle, const char*, int, u16) {
std::shared_ptr<BaseDevice> SRandomDevice::Create(u32 handle, const char*, s32, u16) {
std::srand(std::time(nullptr));
return std::shared_ptr<BaseDevice>(
reinterpret_cast<Devices::BaseDevice*>(new SRandomDevice(handle)));
return std::static_pointer_cast<BaseDevice>(std::make_shared<SRandomDevice>(handle));
}
int SRandomDevice::ioctl(u64 cmd, Common::VaCtx* args) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s32 SRandomDevice::ioctl(u64 cmd, Common::VaCtx* args) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called, cmd = {:#x}", cmd);
return 0;
}
s64 SRandomDevice::write(const void* buf, size_t nbytes) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s64 SRandomDevice::write(const void* buf, u64 nbytes) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
size_t SRandomDevice::writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s64 SRandomDevice::writev(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
size_t SRandomDevice::readv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s64 SRandomDevice::readv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
s64 SRandomDevice::preadv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt, u64 offset) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s64 SRandomDevice::preadv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt, s64 offset) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
s64 SRandomDevice::lseek(s64 offset, int whence) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s64 SRandomDevice::lseek(s64 offset, s32 whence) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
s64 SRandomDevice::read(void* buf, size_t nbytes) {
auto rbuf = static_cast<char*>(buf);
for (size_t i = 0; i < nbytes; i++) {
s64 SRandomDevice::read(void* buf, u64 nbytes) {
auto rbuf = static_cast<s8*>(buf);
for (u64 i = 0; i < nbytes; i++) {
rbuf[i] = std::rand();
}
return nbytes;
}
int SRandomDevice::fstat(Libraries::Kernel::OrbisKernelStat* sb) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s32 SRandomDevice::fstat(Libraries::Kernel::OrbisKernelStat* sb) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
s32 SRandomDevice::fsync() {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
return s32();
}
int SRandomDevice::ftruncate(s64 length) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
int SRandomDevice::getdents(void* buf, u32 nbytes, s64* basep) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s32 SRandomDevice::ftruncate(s64 length) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
s64 SRandomDevice::pwrite(const void* buf, size_t nbytes, u64 offset) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s64 SRandomDevice::getdents(void* buf, u32 nbytes, s64* basep) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
s64 SRandomDevice::pwrite(const void* buf, u64 nbytes, s64 offset) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}

View File

@@ -3,31 +3,31 @@
#pragma once
#include <memory>
#include "base_device.h"
#include "core/file_sys/devices/base_device.h"
namespace Core::Devices {
class SRandomDevice final : BaseDevice {
class SRandomDevice final : public BaseDevice {
u32 handle;
public:
static std::shared_ptr<BaseDevice> Create(u32 handle, const char*, int, u16);
static std::shared_ptr<BaseDevice> Create(u32 handle, const char*, s32, u16);
explicit SRandomDevice(u32 handle) : handle(handle) {}
~SRandomDevice() override = default;
int ioctl(u64 cmd, Common::VaCtx* args) override;
s64 write(const void* buf, size_t nbytes) override;
size_t readv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override;
size_t writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override;
s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt, u64 offset) override;
s64 lseek(s64 offset, int whence) override;
s64 read(void* buf, size_t nbytes) override;
int fstat(Libraries::Kernel::OrbisKernelStat* sb) override;
s32 ioctl(u64 cmd, Common::VaCtx* args) override;
s64 write(const void* buf, u64 nbytes) override;
s64 readv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) override;
s64 writev(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) override;
s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt, s64 offset) override;
s64 lseek(s64 offset, s32 whence) override;
s64 read(void* buf, u64 nbytes) override;
s32 fstat(Libraries::Kernel::OrbisKernelStat* sb) override;
s32 fsync() override;
int ftruncate(s64 length) override;
int getdents(void* buf, u32 nbytes, s64* basep) override;
s64 pwrite(const void* buf, size_t nbytes, u64 offset) override;
s32 ftruncate(s64 length) override;
s64 getdents(void* buf, u32 nbytes, s64* basep) override;
s64 pwrite(const void* buf, u64 nbytes, s64 offset) override;
};
} // namespace Core::Devices

View File

@@ -4,76 +4,75 @@
#include <cstdlib>
#include <ctime>
#include "common/logging/log.h"
#include "urandom_device.h"
#include "core/file_sys/devices/urandom_device.h"
namespace Core::Devices {
std::shared_ptr<BaseDevice> URandomDevice::Create(u32 handle, const char*, int, u16) {
std::shared_ptr<BaseDevice> URandomDevice::Create(u32 handle, const char*, s32, u16) {
std::srand(std::time(nullptr));
return std::shared_ptr<BaseDevice>(
reinterpret_cast<Devices::BaseDevice*>(new URandomDevice(handle)));
return std::static_pointer_cast<BaseDevice>(std::make_shared<URandomDevice>(handle));
}
int URandomDevice::ioctl(u64 cmd, Common::VaCtx* args) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s32 URandomDevice::ioctl(u64 cmd, Common::VaCtx* args) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called, cmd = {:#x}", cmd);
return 0;
}
s64 URandomDevice::write(const void* buf, size_t nbytes) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s64 URandomDevice::write(const void* buf, u64 nbytes) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
size_t URandomDevice::writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s64 URandomDevice::writev(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
size_t URandomDevice::readv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s64 URandomDevice::readv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
s64 URandomDevice::preadv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt, u64 offset) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s64 URandomDevice::preadv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt, s64 offset) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
s64 URandomDevice::lseek(s64 offset, int whence) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s64 URandomDevice::lseek(s64 offset, s32 whence) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
s64 URandomDevice::read(void* buf, size_t nbytes) {
auto rbuf = static_cast<char*>(buf);
for (size_t i = 0; i < nbytes; i++) {
s64 URandomDevice::read(void* buf, u64 nbytes) {
auto rbuf = static_cast<s8*>(buf);
for (u64 i = 0; i < nbytes; i++) {
rbuf[i] = std::rand() & 0xFF;
}
return nbytes;
}
int URandomDevice::fstat(Libraries::Kernel::OrbisKernelStat* sb) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s32 URandomDevice::fstat(Libraries::Kernel::OrbisKernelStat* sb) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
s32 URandomDevice::fsync() {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
int URandomDevice::ftruncate(s64 length) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s32 URandomDevice::ftruncate(s64 length) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
int URandomDevice::getdents(void* buf, u32 nbytes, s64* basep) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s64 URandomDevice::getdents(void* buf, u32 nbytes, s64* basep) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}
s64 URandomDevice::pwrite(const void* buf, size_t nbytes, u64 offset) {
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
s64 URandomDevice::pwrite(const void* buf, u64 nbytes, s64 offset) {
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
return 0;
}

View File

@@ -3,31 +3,31 @@
#pragma once
#include <memory>
#include "base_device.h"
#include "core/file_sys/devices/base_device.h"
namespace Core::Devices {
class URandomDevice final : BaseDevice {
class URandomDevice final : public BaseDevice {
u32 handle;
public:
static std::shared_ptr<BaseDevice> Create(u32 handle, const char*, int, u16);
static std::shared_ptr<BaseDevice> Create(u32 handle, const char*, s32, u16);
explicit URandomDevice(u32 handle) : handle(handle) {}
~URandomDevice() override = default;
int ioctl(u64 cmd, Common::VaCtx* args) override;
s64 write(const void* buf, size_t nbytes) override;
size_t readv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override;
size_t writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override;
s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt, u64 offset) override;
s64 lseek(s64 offset, int whence) override;
s64 read(void* buf, size_t nbytes) override;
int fstat(Libraries::Kernel::OrbisKernelStat* sb) override;
s32 ioctl(u64 cmd, Common::VaCtx* args) override;
s64 write(const void* buf, u64 nbytes) override;
s64 readv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) override;
s64 writev(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) override;
s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt, s64 offset) override;
s64 lseek(s64 offset, s32 whence) override;
s64 read(void* buf, u64 nbytes) override;
s32 fstat(Libraries::Kernel::OrbisKernelStat* sb) override;
s32 fsync() override;
int ftruncate(s64 length) override;
int getdents(void* buf, u32 nbytes, s64* basep) override;
s64 pwrite(const void* buf, size_t nbytes, u64 offset) override;
s32 ftruncate(s64 length) override;
s64 getdents(void* buf, u32 nbytes, s64* basep) override;
s64 pwrite(const void* buf, u64 nbytes, s64 offset) override;
};
} // namespace Core::Devices

View File

@@ -36,6 +36,18 @@ public:
return ORBIS_KERNEL_ERROR_EBADF;
}
virtual s64 write(const void* buf, u64 nbytes) {
return ORBIS_KERNEL_ERROR_EBADF;
}
virtual s64 writev(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) {
return ORBIS_KERNEL_ERROR_EBADF;
}
virtual s64 pwritev(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt, s64 offset) {
return ORBIS_KERNEL_ERROR_EBADF;
}
virtual s64 lseek(s64 offset, s32 whence) {
return ORBIS_KERNEL_ERROR_EBADF;
}

View File

@@ -235,6 +235,30 @@ File* HandleTable::GetSocket(int d) {
return file;
}
File* HandleTable::GetEpoll(int d) {
std::scoped_lock lock{m_mutex};
if (d < 0 || d >= m_files.size()) {
return nullptr;
}
auto file = m_files.at(d);
if (file->type != Core::FileSys::FileType::Epoll) {
return nullptr;
}
return file;
}
File* HandleTable::GetResolver(int d) {
std::scoped_lock lock{m_mutex};
if (d < 0 || d >= m_files.size()) {
return nullptr;
}
auto file = m_files.at(d);
if (file->type != Core::FileSys::FileType::Resolver) {
return nullptr;
}
return file;
}
File* HandleTable::GetFile(const std::filesystem::path& host_name) {
for (auto* file : m_files) {
if (file != nullptr && file->m_host_name == host_name) {

View File

@@ -15,7 +15,9 @@
namespace Libraries::Net {
struct Socket;
}
struct Epoll;
struct Resolver;
} // namespace Libraries::Net
namespace Core::FileSys {
@@ -78,6 +80,8 @@ enum class FileType {
Directory,
Device,
Socket,
Epoll,
Resolver
};
struct File {
@@ -90,6 +94,8 @@ struct File {
std::shared_ptr<Directories::BaseDirectory> directory; // only valid for type == Directory
std::shared_ptr<Devices::BaseDevice> device; // only valid for type == Device
std::shared_ptr<Libraries::Net::Socket> socket; // only valid for type == Socket
std::shared_ptr<Libraries::Net::Epoll> epoll; // only valid for type == Epoll
std::shared_ptr<Libraries::Net::Resolver> resolver; // only valid for type == Resolver
};
class HandleTable {
@@ -101,6 +107,8 @@ public:
void DeleteHandle(int d);
File* GetFile(int d);
File* GetSocket(int d);
File* GetEpoll(int d);
File* GetResolver(int d);
File* GetFile(const std::filesystem::path& host_name);
int GetFileDescriptor(File* file);

View File

@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "ipc.h"
@@ -8,12 +8,19 @@
#include <SDL3/SDL.h>
#include "common/config.h"
#include "common/memory_patcher.h"
#include "common/thread.h"
#include "common/types.h"
#include "core/debug_state.h"
#include "core/debugger.h"
#include "core/libraries/audio/audioout.h"
#include "input/input_handler.h"
#include "sdl_window.h"
#include "src/core/libraries/usbd/usbd.h"
#include "video_core/renderer_vulkan/vk_presenter.h"
extern std::unique_ptr<Vulkan::Presenter> presenter;
/**
* Protocol summary:
@@ -40,6 +47,7 @@
* Command list:
* - CAPABILITIES:
* - ENABLE_MEMORY_PATCH: enables PATCH_MEMORY command
* - ENABLE_EMU_CONTROL: enables PAUSE, RESUME, STOP, TOGGLE_FULLSCREEN commands
* - INPUT CMD:
* - RUN: start the emulator execution
* - START: start the game execution
@@ -53,7 +61,7 @@
* - STOP: stop and quit the emulator
* - TOGGLE_FULLSCREEN: enable / disable fullscreen
* - OUTPUT CMD:
* - N/A
* - RESTART(argn: number, argv: ...string): Request restart of the emulator, must call STOP
**/
void IPC::Init() {
@@ -63,6 +71,8 @@ void IPC::Init() {
return;
}
Config::setLoadAutoPatches(false);
input_thread = std::jthread([this] {
Common::SetCurrentThreadName("IPC Read thread");
this->InputLoop();
@@ -81,6 +91,15 @@ void IPC::Init() {
}
}
void IPC::SendRestart(const std::vector<std::string>& args) {
std::cerr << ";RESTART\n";
std::cerr << ";" << args.size() << "\n";
for (const auto& arg : args) {
std::cerr << ";" << arg << "\n";
}
std::cerr.flush();
}
void IPC::InputLoop() {
auto next_str = [&] -> const std::string& {
static std::string line_buffer;
@@ -130,8 +149,70 @@ void IPC::InputLoop() {
SDL_memset(&event, 0, sizeof(event));
event.type = SDL_EVENT_TOGGLE_FULLSCREEN;
SDL_PushEvent(&event);
} else if (cmd == "ADJUST_VOLUME") {
int value = static_cast<int>(next_u64());
bool is_game_specific = next_u64() != 0;
Config::setVolumeSlider(value, is_game_specific);
Libraries::AudioOut::AdjustVol();
} else if (cmd == "SET_FSR") {
bool use_fsr = next_u64() != 0;
if (presenter) {
presenter->GetFsrSettingsRef().enable = use_fsr;
}
} else if (cmd == "SET_RCAS") {
bool use_rcas = next_u64() != 0;
if (presenter) {
presenter->GetFsrSettingsRef().use_rcas = use_rcas;
}
} else if (cmd == "SET_RCAS_ATTENUATION") {
int value = static_cast<int>(next_u64());
if (presenter) {
presenter->GetFsrSettingsRef().rcas_attenuation =
static_cast<float>(value / 1000.0f);
}
} else if (cmd == "USB_LOAD_FIGURE") {
const auto ref = Libraries::Usbd::usb_backend->GetImplRef();
if (ref) {
ref->LoadFigure(next_str(), next_u64(), next_u64());
}
} else if (cmd == "USB_REMOVE_FIGURE") {
const auto ref = Libraries::Usbd::usb_backend->GetImplRef();
if (ref) {
ref->RemoveFigure(next_u64(), next_u64(), next_u64() != 0);
}
} else if (cmd == "USB_MOVE_FIGURE") {
const auto ref = Libraries::Usbd::usb_backend->GetImplRef();
if (ref) {
const u8 new_pad = next_u64();
const u8 new_index = next_u64();
const u8 old_pad = next_u64();
const u8 old_index = next_u64();
ref->MoveFigure(new_pad, new_index, old_pad, old_index);
}
} else if (cmd == "USB_TEMP_REMOVE_FIGURE") {
const auto ref = Libraries::Usbd::usb_backend->GetImplRef();
if (ref) {
const u8 index = next_u64();
ref->TempRemoveFigure(index);
}
} else if (cmd == "USB_CANCEL_REMOVE_FIGURE") {
const auto ref = Libraries::Usbd::usb_backend->GetImplRef();
if (ref) {
const u8 index = next_u64();
ref->CancelRemoveFigure(index);
}
} else if (cmd == "RELOAD_INPUTS") {
std::string config = next_str();
Input::ParseInputConfig(config);
} else if (cmd == "SET_ACTIVE_CONTROLLER") {
std::string active_controller = next_str();
GamepadSelect::SetSelectedGamepad(active_controller);
SDL_Event checkGamepad;
SDL_memset(&checkGamepad, 0, sizeof(checkGamepad));
checkGamepad.type = SDL_EVENT_CHANGE_CONTROLLER;
SDL_PushEvent(&checkGamepad);
} else {
std::cerr << ";UNKNOWN CMD: " << cmd << std::endl;
}
}
}
}

View File

@@ -6,7 +6,9 @@
#include "common/singleton.h"
#include <semaphore>
#include <string>
#include <thread>
#include <vector>
class IPC {
bool enabled{false};
@@ -34,6 +36,8 @@ public:
start_semaphore.acquire();
}
void SendRestart(const std::vector<std::string>& args);
private:
[[noreturn]] void InputLoop();
};

View File

@@ -10,15 +10,51 @@ extern "C" {
#include <libatrac9.h>
}
#include <vector>
namespace Libraries::Ajm {
struct ChunkHeader {
u32 tag;
u32 length;
};
static_assert(sizeof(ChunkHeader) == 8);
struct AudioFormat {
u16 fmt_type;
u16 num_channels;
u32 avg_sample_rate;
u32 avg_byte_rate;
u16 block_align;
u16 bits_per_sample;
u16 ext_size;
union {
u16 valid_bits_per_sample;
u16 samples_per_block;
u16 reserved;
};
u32 channel_mask;
u8 guid[16];
u32 version;
u8 config_data[4];
u32 reserved2;
};
static_assert(sizeof(AudioFormat) == 52);
struct SampleData {
u32 sample_length;
u32 encoder_delay;
u32 encoder_delay2;
};
static_assert(sizeof(SampleData) == 12);
struct RIFFHeader {
u32 riff;
u32 size;
u32 wave;
};
static_assert(sizeof(RIFFHeader) == 12);
AjmAt9Decoder::AjmAt9Decoder(AjmFormatEncoding format, AjmAt9CodecFlags flags)
: m_format(format), m_flags(flags), m_handle(Atrac9GetHandle()) {
ASSERT_MSG(m_handle, "Atrac9GetHandle failed");
AjmAt9Decoder::Reset();
}
: m_format(format), m_flags(flags), m_handle(Atrac9GetHandle()) {}
AjmAt9Decoder::~AjmAt9Decoder() {
Atrac9ReleaseHandle(m_handle);
@@ -42,6 +78,7 @@ void AjmAt9Decoder::Initialize(const void* buffer, u32 buffer_size) {
AjmAt9Decoder::Reset();
m_pcm_buffer.resize(m_codec_info.frameSamples * m_codec_info.channels * GetPCMSize(m_format),
0);
m_is_initialized = true;
}
void AjmAt9Decoder::GetInfo(void* out_info) const {
@@ -52,8 +89,64 @@ void AjmAt9Decoder::GetInfo(void* out_info) const {
info->next_frame_size = static_cast<Atrac9Handle*>(m_handle)->Config.FrameBytes;
}
std::tuple<u32, u32> AjmAt9Decoder::ProcessData(std::span<u8>& in_buf, SparseOutputBuffer& output,
AjmInstanceGapless& gapless) {
u8 g_at9_guid[] = {0xD2, 0x42, 0xE1, 0x47, 0xBA, 0x36, 0x8D, 0x4D,
0x88, 0xFC, 0x61, 0x65, 0x4F, 0x8C, 0x83, 0x6C};
void AjmAt9Decoder::ParseRIFFHeader(std::span<u8>& in_buf, AjmInstanceGapless& gapless) {
auto* header = reinterpret_cast<RIFFHeader*>(in_buf.data());
in_buf = in_buf.subspan(sizeof(RIFFHeader));
ASSERT(header->riff == 'FFIR');
ASSERT(header->wave == 'EVAW');
auto* chunk = reinterpret_cast<ChunkHeader*>(in_buf.data());
in_buf = in_buf.subspan(sizeof(ChunkHeader));
while (chunk->tag != 'atad') {
switch (chunk->tag) {
case ' tmf': {
ASSERT(chunk->length == sizeof(AudioFormat));
auto* fmt = reinterpret_cast<AudioFormat*>(in_buf.data());
ASSERT(fmt->fmt_type == 0xFFFE);
ASSERT(memcmp(fmt->guid, g_at9_guid, 16) == 0);
AjmDecAt9InitializeParameters init_params = {};
std::memcpy(init_params.config_data, fmt->config_data, ORBIS_AT9_CONFIG_DATA_SIZE);
Initialize(&init_params, sizeof(init_params));
break;
}
case 'tcaf': {
ASSERT(chunk->length == sizeof(SampleData));
auto* samples = reinterpret_cast<SampleData*>(in_buf.data());
gapless.init.total_samples = samples->sample_length;
gapless.init.skip_samples = samples->encoder_delay;
gapless.Reset();
break;
}
default:
break;
}
in_buf = in_buf.subspan(chunk->length);
chunk = reinterpret_cast<ChunkHeader*>(in_buf.data());
in_buf = in_buf.subspan(sizeof(ChunkHeader));
}
}
std::tuple<u32, u32, bool> AjmAt9Decoder::ProcessData(std::span<u8>& in_buf,
SparseOutputBuffer& output,
AjmInstanceGapless& gapless) {
bool is_reset = false;
if (True(m_flags & AjmAt9CodecFlags::ParseRiffHeader) &&
*reinterpret_cast<u32*>(in_buf.data()) == 'FFIR') {
ParseRIFFHeader(in_buf, gapless);
is_reset = true;
}
if (!m_is_initialized) {
return {0, 0, is_reset};
}
int ret = 0;
int bytes_used = 0;
switch (m_format) {
@@ -118,7 +211,7 @@ std::tuple<u32, u32> AjmAt9Decoder::ProcessData(std::span<u8>& in_buf, SparseOut
m_num_frames = 0;
}
return {1, samples_written};
return {1, m_codec_info.frameSamples, is_reset};
}
AjmSidebandFormat AjmAt9Decoder::GetFormat() const {
@@ -134,12 +227,13 @@ AjmSidebandFormat AjmAt9Decoder::GetFormat() const {
}
u32 AjmAt9Decoder::GetNextFrameSize(const AjmInstanceGapless& gapless) const {
const auto max_samples =
const auto skip_samples =
std::min<u32>(gapless.current.skip_samples, m_codec_info.frameSamples);
const auto samples =
gapless.init.total_samples != 0
? std::min(gapless.current.total_samples, u32(m_codec_info.frameSamples))
? std::min<u32>(gapless.current.total_samples, m_codec_info.frameSamples - skip_samples)
: m_codec_info.frameSamples;
const auto skip_samples = std::min(u32(gapless.current.skip_samples), max_samples);
return (max_samples - skip_samples) * m_codec_info.channels * GetPCMSize(m_format);
return samples * m_codec_info.channels * GetPCMSize(m_format);
}
} // namespace Libraries::Ajm

View File

@@ -9,6 +9,7 @@
#include "libatrac9.h"
#include <span>
#include <vector>
namespace Libraries::Ajm {
@@ -36,8 +37,8 @@ struct AjmAt9Decoder final : AjmCodec {
void GetInfo(void* out_info) const override;
AjmSidebandFormat GetFormat() const override;
u32 GetNextFrameSize(const AjmInstanceGapless& gapless) const override;
std::tuple<u32, u32> ProcessData(std::span<u8>& input, SparseOutputBuffer& output,
AjmInstanceGapless& gapless) override;
std::tuple<u32, u32, bool> ProcessData(std::span<u8>& input, SparseOutputBuffer& output,
AjmInstanceGapless& gapless) override;
private:
template <class T>
@@ -49,8 +50,12 @@ private:
return output.Write(pcm_data.subspan(0, pcm_size));
}
void ParseRIFFHeader(std::span<u8>& input, AjmInstanceGapless& gapless);
const AjmFormatEncoding m_format;
const AjmAt9CodecFlags m_flags;
bool m_is_initialized{};
void* m_handle{};
u8 m_config_data[ORBIS_AT9_CONFIG_DATA_SIZE]{};
u32 m_superframe_bytes_remain{};

View File

@@ -52,21 +52,22 @@ AjmInstance::AjmInstance(AjmCodecType codec_type, AjmInstanceFlags flags) : m_fl
}
}
void AjmInstance::Reset() {
m_total_samples = 0;
m_gapless.Reset();
m_codec->Reset();
}
void AjmInstance::ExecuteJob(AjmJob& job) {
const auto control_flags = job.flags.control_flags;
if (True(control_flags & AjmJobControlFlags::Reset)) {
LOG_TRACE(Lib_Ajm, "Resetting instance {}", job.instance_id);
m_format = {};
m_gapless = {};
m_resample_parameters = {};
m_total_samples = 0;
m_codec->Reset();
Reset();
}
if (job.input.init_params.has_value()) {
LOG_TRACE(Lib_Ajm, "Initializing instance {}", job.instance_id);
auto& params = job.input.init_params.value();
m_codec->Initialize(&params, sizeof(params));
is_initialized = true;
}
if (job.input.resample_parameters.has_value()) {
LOG_ERROR(Lib_Ajm, "Unimplemented: resample parameters");
@@ -78,20 +79,37 @@ void AjmInstance::ExecuteJob(AjmJob& job) {
}
if (job.input.gapless_decode.has_value()) {
auto& params = job.input.gapless_decode.value();
if (params.total_samples != 0) {
const auto max = std::max(params.total_samples, m_gapless.init.total_samples);
m_gapless.current.total_samples += max - m_gapless.init.total_samples;
m_gapless.init.total_samples = max;
}
if (params.skip_samples != 0) {
const auto max = std::max(params.skip_samples, m_gapless.init.skip_samples);
m_gapless.current.skip_samples += max - m_gapless.init.skip_samples;
m_gapless.init.skip_samples = max;
}
}
if (!is_initialized) {
return;
const auto samples_processed =
m_gapless.init.total_samples - m_gapless.current.total_samples;
if (params.total_samples != 0 || params.skip_samples == 0) {
if (params.total_samples >= samples_processed) {
const auto sample_difference =
s64(m_gapless.init.total_samples) - params.total_samples;
m_gapless.init.total_samples = params.total_samples;
m_gapless.current.total_samples -= sample_difference;
} else {
LOG_WARNING(Lib_Ajm, "ORBIS_AJM_RESULT_INVALID_PARAMETER");
job.output.p_result->result = ORBIS_AJM_RESULT_INVALID_PARAMETER;
return;
}
}
const auto samples_skipped = m_gapless.init.skip_samples - m_gapless.current.skip_samples;
if (params.skip_samples != 0 || params.total_samples == 0) {
if (params.skip_samples >= samples_skipped) {
const auto sample_difference =
s32(m_gapless.init.skip_samples) - params.skip_samples;
m_gapless.init.skip_samples = params.skip_samples;
m_gapless.current.skip_samples -= sample_difference;
} else {
LOG_WARNING(Lib_Ajm, "ORBIS_AJM_RESULT_INVALID_PARAMETER");
job.output.p_result->result = ORBIS_AJM_RESULT_INVALID_PARAMETER;
return;
}
}
}
if (!job.input.buffer.empty() && !job.output.buffers.empty()) {
@@ -104,12 +122,23 @@ void AjmInstance::ExecuteJob(AjmJob& job) {
while (!in_buf.empty() && !out_buf.IsEmpty() && !m_gapless.IsEnd()) {
if (!HasEnoughSpace(out_buf)) {
if (job.output.p_mframe == nullptr || frames_decoded == 0) {
LOG_WARNING(Lib_Ajm, "ORBIS_AJM_RESULT_NOT_ENOUGH_ROOM ({} < {})",
out_buf.Size(), m_codec->GetNextFrameSize(m_gapless));
job.output.p_result->result = ORBIS_AJM_RESULT_NOT_ENOUGH_ROOM;
break;
}
}
const auto [nframes, nsamples] = m_codec->ProcessData(in_buf, out_buf, m_gapless);
const auto [nframes, nsamples, reset] =
m_codec->ProcessData(in_buf, out_buf, m_gapless);
if (reset) {
m_total_samples = 0;
}
if (!nframes) {
LOG_WARNING(Lib_Ajm, "ORBIS_AJM_RESULT_NOT_INITIALIZED");
job.output.p_result->result = ORBIS_AJM_RESULT_NOT_INITIALIZED;
break;
}
frames_decoded += nframes;
m_total_samples += nsamples;
@@ -118,10 +147,10 @@ void AjmInstance::ExecuteJob(AjmJob& job) {
}
}
if (m_gapless.IsEnd()) {
const auto total_decoded_samples = m_total_samples;
if (m_flags.gapless_loop && m_gapless.IsEnd()) {
in_buf = in_buf.subspan(in_buf.size());
m_gapless.current.total_samples = m_gapless.init.total_samples;
m_gapless.current.skip_samples = m_gapless.init.skip_samples;
m_gapless.Reset();
m_codec->Reset();
}
if (job.output.p_mframe) {
@@ -130,7 +159,7 @@ void AjmInstance::ExecuteJob(AjmJob& job) {
if (job.output.p_stream) {
job.output.p_stream->input_consumed = in_size - in_buf.size();
job.output.p_stream->output_written = out_size - out_buf.Size();
job.output.p_stream->total_decoded_samples = m_total_samples;
job.output.p_stream->total_decoded_samples = total_decoded_samples;
}
}

View File

@@ -65,6 +65,12 @@ struct AjmInstanceGapless {
bool IsEnd() const {
return init.total_samples != 0 && current.total_samples == 0;
}
void Reset() {
current.total_samples = init.total_samples;
current.skip_samples = init.skip_samples;
current.skipped_samples = 0;
}
};
class AjmCodec {
@@ -76,8 +82,8 @@ public:
virtual void GetInfo(void* out_info) const = 0;
virtual AjmSidebandFormat GetFormat() const = 0;
virtual u32 GetNextFrameSize(const AjmInstanceGapless& gapless) const = 0;
virtual std::tuple<u32, u32> ProcessData(std::span<u8>& input, SparseOutputBuffer& output,
AjmInstanceGapless& gapless) = 0;
virtual std::tuple<u32, u32, bool> ProcessData(std::span<u8>& input, SparseOutputBuffer& output,
AjmInstanceGapless& gapless) = 0;
};
class AjmInstance {
@@ -89,6 +95,7 @@ public:
private:
bool HasEnoughSpace(const SparseOutputBuffer& output) const;
std::optional<u32> GetNumRemainingSamples() const;
void Reset();
AjmInstanceFlags m_flags{};
AjmSidebandFormat m_format{};
@@ -96,7 +103,6 @@ private:
AjmSidebandResampleParameters m_resample_parameters{};
u32 m_total_samples{};
std::unique_ptr<AjmCodec> m_codec;
bool is_initialized = false;
};
} // namespace Libraries::Ajm

View File

@@ -138,8 +138,9 @@ void AjmMp3Decoder::GetInfo(void* out_info) const {
}
}
std::tuple<u32, u32> AjmMp3Decoder::ProcessData(std::span<u8>& in_buf, SparseOutputBuffer& output,
AjmInstanceGapless& gapless) {
std::tuple<u32, u32, bool> AjmMp3Decoder::ProcessData(std::span<u8>& in_buf,
SparseOutputBuffer& output,
AjmInstanceGapless& gapless) {
AVPacket* pkt = av_packet_alloc();
if ((!m_header.has_value() || m_frame_samples == 0) && in_buf.size() >= 4) {
@@ -155,7 +156,7 @@ std::tuple<u32, u32> AjmMp3Decoder::ProcessData(std::span<u8>& in_buf, SparseOut
in_buf = in_buf.subspan(ret);
u32 frames_decoded = 0;
u32 samples_written = 0;
u32 samples_decoded = 0;
if (pkt->size) {
// Send the packet with the compressed data to the decoder
@@ -176,6 +177,7 @@ std::tuple<u32, u32> AjmMp3Decoder::ProcessData(std::span<u8>& in_buf, SparseOut
UNREACHABLE_MSG("Error during decoding");
}
frame = ConvertAudioFrame(frame);
samples_decoded += u32(frame->nb_samples);
frames_decoded += 1;
u32 skip_samples = 0;
@@ -205,7 +207,6 @@ std::tuple<u32, u32> AjmMp3Decoder::ProcessData(std::span<u8>& in_buf, SparseOut
}
const auto samples = pcm_written / m_codec_context->ch_layout.nb_channels;
samples_written += samples;
gapless.current.skipped_samples += frame->nb_samples - samples;
if (gapless.init.total_samples != 0) {
gapless.current.total_samples -= samples;
@@ -217,7 +218,7 @@ std::tuple<u32, u32> AjmMp3Decoder::ProcessData(std::span<u8>& in_buf, SparseOut
av_packet_free(&pkt);
return {frames_decoded, samples_written};
return {frames_decoded, samples_decoded, false};
}
u32 AjmMp3Decoder::GetNextFrameSize(const AjmInstanceGapless& gapless) const {

View File

@@ -71,8 +71,8 @@ public:
void GetInfo(void* out_info) const override;
AjmSidebandFormat GetFormat() const override;
u32 GetNextFrameSize(const AjmInstanceGapless& gapless) const override;
std::tuple<u32, u32> ProcessData(std::span<u8>& input, SparseOutputBuffer& output,
AjmInstanceGapless& gapless) override;
std::tuple<u32, u32, bool> ProcessData(std::span<u8>& input, SparseOutputBuffer& output,
AjmInstanceGapless& gapless) override;
static int ParseMp3Header(const u8* buf, u32 stream_size, int parse_ofl,
AjmDecMp3ParseFrame* frame);

View File

@@ -301,7 +301,7 @@ static void AudioOutputThread(PortOut* port, const std::stop_token& stop) {
timer.Start();
{
std::unique_lock lock{port->mutex};
if (port->output_cv.wait(lock, stop, [&] { return port->output_ready; })) {
if (port->output_ready) {
port->impl->Output(port->output_buffer);
port->output_ready = false;
}
@@ -413,7 +413,6 @@ s32 PS4_SYSV_ABI sceAudioOutOutput(s32 handle, void* ptr) {
samples_sent = port.buffer_frames * port.format_info.num_channels;
}
}
port.output_cv.notify_one();
return samples_sent;
}

View File

@@ -9,23 +9,22 @@
namespace Libraries::AvPlayer {
s32 PS4_SYSV_ABI sceAvPlayerAddSource(SceAvPlayerHandle handle, const char* filename) {
s32 PS4_SYSV_ABI sceAvPlayerAddSource(AvPlayerHandle handle, const char* filename) {
LOG_TRACE(Lib_AvPlayer, "filename = {}", filename);
if (handle == nullptr) {
return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS;
}
const auto res = handle->AddSource(filename);
LOG_TRACE(Lib_AvPlayer, "returning {}", res);
return res;
return handle->AddSource(filename);
}
s32 PS4_SYSV_ABI sceAvPlayerAddSourceEx(SceAvPlayerHandle handle, SceAvPlayerUriType uriType,
SceAvPlayerSourceDetails* sourceDetails) {
LOG_ERROR(Lib_AvPlayer, "(STUBBED) called");
if (handle == nullptr) {
s32 PS4_SYSV_ABI sceAvPlayerAddSourceEx(AvPlayerHandle handle, AvPlayerUriType uri_type,
AvPlayerSourceDetails* source_details) {
LOG_TRACE(Lib_AvPlayer, "called");
if (handle == nullptr || uri_type != AvPlayerUriType::Source) {
return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS;
}
return ORBIS_OK;
const auto path = std::string_view(source_details->uri.name, source_details->uri.length);
return handle->AddSourceEx(path, source_details->source_type);
}
int PS4_SYSV_ABI sceAvPlayerChangeStream() {
@@ -33,28 +32,24 @@ int PS4_SYSV_ABI sceAvPlayerChangeStream() {
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceAvPlayerClose(SceAvPlayerHandle handle) {
s32 PS4_SYSV_ABI sceAvPlayerClose(AvPlayerHandle handle) {
LOG_TRACE(Lib_AvPlayer, "called");
if (handle == nullptr) {
LOG_TRACE(Lib_AvPlayer, "returning ORBIS_AVPLAYER_ERROR_INVALID_PARAMS");
return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS;
}
delete handle;
LOG_TRACE(Lib_AvPlayer, "returning ORBIS_OK");
return ORBIS_OK;
}
u64 PS4_SYSV_ABI sceAvPlayerCurrentTime(SceAvPlayerHandle handle) {
u64 PS4_SYSV_ABI sceAvPlayerCurrentTime(AvPlayerHandle handle) {
LOG_TRACE(Lib_AvPlayer, "called");
if (handle == nullptr) {
return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS;
}
const auto res = handle->CurrentTime();
LOG_TRACE(Lib_AvPlayer, "returning {}", res);
return res;
return handle->CurrentTime();
}
s32 PS4_SYSV_ABI sceAvPlayerDisableStream(SceAvPlayerHandle handle, u32 stream_id) {
s32 PS4_SYSV_ABI sceAvPlayerDisableStream(AvPlayerHandle handle, u32 stream_id) {
LOG_ERROR(Lib_AvPlayer, "(STUBBED) called");
if (handle == nullptr) {
return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS;
@@ -62,60 +57,49 @@ s32 PS4_SYSV_ABI sceAvPlayerDisableStream(SceAvPlayerHandle handle, u32 stream_i
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceAvPlayerEnableStream(SceAvPlayerHandle handle, u32 stream_id) {
s32 PS4_SYSV_ABI sceAvPlayerEnableStream(AvPlayerHandle handle, u32 stream_id) {
LOG_TRACE(Lib_AvPlayer, "stream_id = {}", stream_id);
if (handle == nullptr) {
return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS;
}
const auto res = handle->EnableStream(stream_id);
LOG_TRACE(Lib_AvPlayer, "returning {}", res);
return res;
return handle->EnableStream(stream_id);
}
bool PS4_SYSV_ABI sceAvPlayerGetAudioData(SceAvPlayerHandle handle, SceAvPlayerFrameInfo* p_info) {
bool PS4_SYSV_ABI sceAvPlayerGetAudioData(AvPlayerHandle handle, AvPlayerFrameInfo* p_info) {
LOG_TRACE(Lib_AvPlayer, "called");
if (handle == nullptr || p_info == nullptr) {
return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS;
return false;
}
const auto res = handle->GetAudioData(*p_info);
LOG_TRACE(Lib_AvPlayer, "returning {}", res);
return res;
return handle->GetAudioData(*p_info);
}
s32 PS4_SYSV_ABI sceAvPlayerGetStreamInfo(SceAvPlayerHandle handle, u32 stream_id,
SceAvPlayerStreamInfo* p_info) {
s32 PS4_SYSV_ABI sceAvPlayerGetStreamInfo(AvPlayerHandle handle, u32 stream_id,
AvPlayerStreamInfo* p_info) {
LOG_TRACE(Lib_AvPlayer, "stream_id = {}", stream_id);
if (handle == nullptr || p_info == nullptr) {
return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS;
}
const auto res = handle->GetStreamInfo(stream_id, *p_info);
LOG_TRACE(Lib_AvPlayer, "returning {}", res);
return res;
return handle->GetStreamInfo(stream_id, *p_info);
}
bool PS4_SYSV_ABI sceAvPlayerGetVideoData(SceAvPlayerHandle handle,
SceAvPlayerFrameInfo* video_info) {
bool PS4_SYSV_ABI sceAvPlayerGetVideoData(AvPlayerHandle handle, AvPlayerFrameInfo* video_info) {
LOG_TRACE(Lib_AvPlayer, "called");
if (handle == nullptr || video_info == nullptr) {
return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS;
return false;
}
const auto res = handle->GetVideoData(*video_info);
LOG_TRACE(Lib_AvPlayer, "returning {}", res);
return res;
return handle->GetVideoData(*video_info);
}
bool PS4_SYSV_ABI sceAvPlayerGetVideoDataEx(SceAvPlayerHandle handle,
SceAvPlayerFrameInfoEx* video_info) {
bool PS4_SYSV_ABI sceAvPlayerGetVideoDataEx(AvPlayerHandle handle,
AvPlayerFrameInfoEx* video_info) {
LOG_TRACE(Lib_AvPlayer, "called");
if (handle == nullptr || video_info == nullptr) {
return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS;
return false;
}
const auto res = handle->GetVideoData(*video_info);
LOG_TRACE(Lib_AvPlayer, "returning {}", res);
return res;
return handle->GetVideoData(*video_info);
}
SceAvPlayerHandle PS4_SYSV_ABI sceAvPlayerInit(SceAvPlayerInitData* data) {
AvPlayerHandle PS4_SYSV_ABI sceAvPlayerInit(AvPlayerInitData* data) {
LOG_TRACE(Lib_AvPlayer, "called");
if (data == nullptr) {
return nullptr;
@@ -125,15 +109,14 @@ SceAvPlayerHandle PS4_SYSV_ABI sceAvPlayerInit(SceAvPlayerInitData* data) {
data->memory_replacement.allocate_texture == nullptr ||
data->memory_replacement.deallocate == nullptr ||
data->memory_replacement.deallocate_texture == nullptr) {
LOG_ERROR(Lib_AvPlayer, "All allocators are required for AVPlayer Initialisation.");
LOG_ERROR(Lib_AvPlayer, "All allocators are required for AvPlayer Initialisation.");
return nullptr;
}
return new AvPlayer(*data);
}
s32 PS4_SYSV_ABI sceAvPlayerInitEx(const SceAvPlayerInitDataEx* p_data,
SceAvPlayerHandle* p_player) {
s32 PS4_SYSV_ABI sceAvPlayerInitEx(const AvPlayerInitDataEx* p_data, AvPlayerHandle* p_player) {
LOG_TRACE(Lib_AvPlayer, "called");
if (p_data == nullptr || p_player == nullptr) {
return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS;
@@ -143,11 +126,11 @@ s32 PS4_SYSV_ABI sceAvPlayerInitEx(const SceAvPlayerInitDataEx* p_data,
p_data->memory_replacement.allocate_texture == nullptr ||
p_data->memory_replacement.deallocate == nullptr ||
p_data->memory_replacement.deallocate_texture == nullptr) {
LOG_ERROR(Lib_AvPlayer, "All allocators are required for AVPlayer Initialisation.");
LOG_ERROR(Lib_AvPlayer, "All allocators are required for AvPlayer Initialisation.");
return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS;
}
SceAvPlayerInitData data = {};
AvPlayerInitData data = {};
data.memory_replacement = p_data->memory_replacement;
data.file_replacement = p_data->file_replacement;
data.event_replacement = p_data->event_replacement;
@@ -159,18 +142,15 @@ s32 PS4_SYSV_ABI sceAvPlayerInitEx(const SceAvPlayerInitDataEx* p_data,
return ORBIS_OK;
}
bool PS4_SYSV_ABI sceAvPlayerIsActive(SceAvPlayerHandle handle) {
bool PS4_SYSV_ABI sceAvPlayerIsActive(AvPlayerHandle handle) {
LOG_TRACE(Lib_AvPlayer, "called");
if (handle == nullptr) {
LOG_TRACE(Lib_AvPlayer, "returning false");
return false;
}
const auto res = handle->IsActive();
LOG_TRACE(Lib_AvPlayer, "returning {}", res);
return res;
return handle->IsActive();
}
s32 PS4_SYSV_ABI sceAvPlayerJumpToTime(SceAvPlayerHandle handle, uint64_t time) {
s32 PS4_SYSV_ABI sceAvPlayerJumpToTime(AvPlayerHandle handle, uint64_t time) {
LOG_ERROR(Lib_AvPlayer, "(STUBBED) called, time (msec) = {}", time);
if (handle == nullptr) {
return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS;
@@ -178,22 +158,20 @@ s32 PS4_SYSV_ABI sceAvPlayerJumpToTime(SceAvPlayerHandle handle, uint64_t time)
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceAvPlayerPause(SceAvPlayerHandle handle) {
LOG_ERROR(Lib_AvPlayer, "(STUBBED) called");
s32 PS4_SYSV_ABI sceAvPlayerPause(AvPlayerHandle handle) {
LOG_TRACE(Lib_AvPlayer, "called");
if (handle == nullptr) {
return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS;
}
return ORBIS_OK;
return handle->Pause();
}
s32 PS4_SYSV_ABI sceAvPlayerPostInit(SceAvPlayerHandle handle, SceAvPlayerPostInitData* data) {
s32 PS4_SYSV_ABI sceAvPlayerPostInit(AvPlayerHandle handle, AvPlayerPostInitData* data) {
LOG_TRACE(Lib_AvPlayer, "called");
if (handle == nullptr || data == nullptr) {
return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS;
}
const auto res = handle->PostInit(*data);
LOG_TRACE(Lib_AvPlayer, "returning {}", res);
return res;
return handle->PostInit(*data);
}
s32 PS4_SYSV_ABI sceAvPlayerPrintf(const char* format, ...) {
@@ -201,29 +179,28 @@ s32 PS4_SYSV_ABI sceAvPlayerPrintf(const char* format, ...) {
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceAvPlayerResume(SceAvPlayerHandle handle) {
LOG_ERROR(Lib_AvPlayer, "(STUBBED) called");
s32 PS4_SYSV_ABI sceAvPlayerResume(AvPlayerHandle handle) {
LOG_TRACE(Lib_AvPlayer, "called");
if (handle == nullptr) {
return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS;
}
return ORBIS_OK;
return handle->Resume();
}
s32 PS4_SYSV_ABI sceAvPlayerSetAvSyncMode(SceAvPlayerHandle handle,
SceAvPlayerAvSyncMode sync_mode) {
LOG_ERROR(Lib_AvPlayer, "(STUBBED) called");
s32 PS4_SYSV_ABI sceAvPlayerSetAvSyncMode(AvPlayerHandle handle, AvPlayerAvSyncMode sync_mode) {
LOG_TRACE(Lib_AvPlayer, "called");
if (handle == nullptr) {
return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS;
}
return ORBIS_OK;
return handle->SetAvSyncMode(sync_mode);
}
s32 PS4_SYSV_ABI sceAvPlayerSetLogCallback(SceAvPlayerLogCallback log_cb, void* user_data) {
s32 PS4_SYSV_ABI sceAvPlayerSetLogCallback(AvPlayerLogCallback log_cb, void* user_data) {
LOG_ERROR(Lib_AvPlayer, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceAvPlayerSetLooping(SceAvPlayerHandle handle, bool loop_flag) {
s32 PS4_SYSV_ABI sceAvPlayerSetLooping(AvPlayerHandle handle, bool loop_flag) {
LOG_TRACE(Lib_AvPlayer, "called, looping = {}", loop_flag);
if (handle == nullptr) {
return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS;
@@ -234,43 +211,36 @@ s32 PS4_SYSV_ABI sceAvPlayerSetLooping(SceAvPlayerHandle handle, bool loop_flag)
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceAvPlayerSetTrickSpeed(SceAvPlayerHandle handle, s32 trick_speed) {
LOG_ERROR(Lib_AvPlayer, "(STUBBED) called");
s32 PS4_SYSV_ABI sceAvPlayerSetTrickSpeed(AvPlayerHandle handle, s32 trick_speed) {
LOG_ERROR(Lib_AvPlayer, "(STUBBED) called speed = {}", trick_speed);
if (handle == nullptr) {
return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS;
}
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceAvPlayerStart(SceAvPlayerHandle handle) {
s32 PS4_SYSV_ABI sceAvPlayerStart(AvPlayerHandle handle) {
LOG_TRACE(Lib_AvPlayer, "called");
if (handle == nullptr) {
return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS;
}
const auto res = handle->Start();
LOG_TRACE(Lib_AvPlayer, "returning {}", res);
return res;
return handle->Start();
}
s32 PS4_SYSV_ABI sceAvPlayerStop(SceAvPlayerHandle handle) {
s32 PS4_SYSV_ABI sceAvPlayerStop(AvPlayerHandle handle) {
LOG_TRACE(Lib_AvPlayer, "called");
if (handle == nullptr) {
LOG_TRACE(Lib_AvPlayer, "returning ORBIS_AVPLAYER_ERROR_INVALID_PARAMS");
return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS;
}
const auto res = handle->Stop();
LOG_TRACE(Lib_AvPlayer, "returning {}", res);
return res;
return handle->Stop();
}
s32 PS4_SYSV_ABI sceAvPlayerStreamCount(SceAvPlayerHandle handle) {
s32 PS4_SYSV_ABI sceAvPlayerStreamCount(AvPlayerHandle handle) {
LOG_TRACE(Lib_AvPlayer, "called");
if (handle == nullptr) {
return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS;
}
const auto res = handle->GetStreamCount();
LOG_TRACE(Lib_AvPlayer, "returning {}", res);
return res;
return handle->GetStreamCount();
}
s32 PS4_SYSV_ABI sceAvPlayerVprintf(const char* format, va_list args) {

View File

@@ -16,38 +16,38 @@ namespace Libraries::AvPlayer {
class AvPlayer;
using SceAvPlayerHandle = AvPlayer*;
using AvPlayerHandle = AvPlayer*;
enum class SceAvPlayerUriType : u32 {
enum class AvPlayerUriType : u32 {
Source = 0,
};
struct SceAvPlayerUri {
struct AvPlayerUri {
const char* name;
u32 length;
};
enum class SceAvPlayerSourceType {
enum class AvPlayerSourceType {
Unknown = 0,
FileMp4 = 1,
Hls = 8,
};
enum class SceAvPlayerStreamType : u32 {
enum class AvPlayerStreamType : u32 {
Video,
Audio,
TimedText,
Unknown,
};
struct SceAvPlayerSourceDetails {
SceAvPlayerUri uri;
struct AvPlayerSourceDetails {
AvPlayerUri uri;
u8 reserved1[64];
SceAvPlayerSourceType source_type;
AvPlayerSourceType source_type;
u8 reserved2[44];
};
struct SceAvPlayerAudio {
struct AvPlayerAudio {
u16 channel_count;
u8 reserved1[2];
u32 sample_rate;
@@ -55,50 +55,50 @@ struct SceAvPlayerAudio {
u8 language_code[4];
};
struct SceAvPlayerVideo {
struct AvPlayerVideo {
u32 width;
u32 height;
f32 aspect_ratio;
char language_code[4];
};
struct SceAvPlayerTextPosition {
struct AvPlayerTextPosition {
u16 top;
u16 left;
u16 bottom;
u16 right;
};
struct SceAvPlayerTimedText {
struct AvPlayerTimedText {
u8 language_code[4];
u16 text_size;
u16 font_size;
SceAvPlayerTextPosition position;
AvPlayerTextPosition position;
};
union SceAvPlayerStreamDetails {
union AvPlayerStreamDetails {
u8 reserved[16];
SceAvPlayerAudio audio;
SceAvPlayerVideo video;
SceAvPlayerTimedText subs;
AvPlayerAudio audio;
AvPlayerVideo video;
AvPlayerTimedText subs;
};
struct SceAvPlayerFrameInfo {
u8* pData;
struct AvPlayerFrameInfo {
u8* p_data;
u8 reserved[4];
u64 timestamp;
SceAvPlayerStreamDetails details;
AvPlayerStreamDetails details;
};
struct SceAvPlayerStreamInfo {
SceAvPlayerStreamType type;
struct AvPlayerStreamInfo {
AvPlayerStreamType type;
u8 reserved[4];
SceAvPlayerStreamDetails details;
AvPlayerStreamDetails details;
u64 duration;
u64 start_time;
};
struct SceAvPlayerAudioEx {
struct AvPlayerAudioEx {
u16 channel_count;
u8 reserved[2];
u32 sample_rate;
@@ -107,7 +107,7 @@ struct SceAvPlayerAudioEx {
u8 reserved1[64];
};
struct SceAvPlayerVideoEx {
struct AvPlayerVideoEx {
u32 width;
u32 height;
f32 aspect_ratio;
@@ -124,53 +124,53 @@ struct SceAvPlayerVideoEx {
u8 reserved1[37];
};
struct SceAvPlayerTimedTextEx {
struct AvPlayerTimedTextEx {
u8 language_code[4];
u8 reserved[12];
u8 reserved1[64];
};
union SceAvPlayerStreamDetailsEx {
SceAvPlayerAudioEx audio;
SceAvPlayerVideoEx video;
SceAvPlayerTimedTextEx subs;
union AvPlayerStreamDetailsEx {
AvPlayerAudioEx audio;
AvPlayerVideoEx video;
AvPlayerTimedTextEx subs;
u8 reserved1[80];
};
struct SceAvPlayerFrameInfoEx {
void* pData;
struct AvPlayerFrameInfoEx {
void* p_data;
u8 reserved[4];
u64 timestamp;
SceAvPlayerStreamDetailsEx details;
AvPlayerStreamDetailsEx details;
};
using SceAvPlayerAllocate = void* PS4_SYSV_ABI (*)(void* p, u32 align, u32 size);
using SceAvPlayerDeallocate = void PS4_SYSV_ABI (*)(void* p, void* mem);
using SceAvPlayerAllocateTexture = void* PS4_SYSV_ABI (*)(void* p, u32 align, u32 size);
using SceAvPlayerDeallocateTexture = void PS4_SYSV_ABI (*)(void* p, void* mem);
using AvPlayerAllocate = void* PS4_SYSV_ABI (*)(void* p, u32 align, u32 size);
using AvPlayerDeallocate = void PS4_SYSV_ABI (*)(void* p, void* mem);
using AvPlayerAllocateTexture = void* PS4_SYSV_ABI (*)(void* p, u32 align, u32 size);
using AvPlayerDeallocateTexture = void PS4_SYSV_ABI (*)(void* p, void* mem);
struct SceAvPlayerMemAllocator {
struct AvPlayerMemAllocator {
void* object_ptr;
SceAvPlayerAllocate allocate;
SceAvPlayerDeallocate deallocate;
SceAvPlayerAllocateTexture allocate_texture;
SceAvPlayerDeallocateTexture deallocate_texture;
AvPlayerAllocate allocate;
AvPlayerDeallocate deallocate;
AvPlayerAllocateTexture allocate_texture;
AvPlayerDeallocateTexture deallocate_texture;
};
using SceAvPlayerOpenFile = s32 PS4_SYSV_ABI (*)(void* p, const char* name);
using SceAvPlayerCloseFile = s32 PS4_SYSV_ABI (*)(void* p);
using SceAvPlayerReadOffsetFile = s32 PS4_SYSV_ABI (*)(void* p, u8* buf, u64 pos, u32 len);
using SceAvPlayerSizeFile = u64 PS4_SYSV_ABI (*)(void* p);
using AvPlayerOpenFile = s32 PS4_SYSV_ABI (*)(void* p, const char* name);
using AvPlayerCloseFile = s32 PS4_SYSV_ABI (*)(void* p);
using AvPlayerReadOffsetFile = s32 PS4_SYSV_ABI (*)(void* p, u8* buf, u64 pos, u32 len);
using AvPlayerSizeFile = u64 PS4_SYSV_ABI (*)(void* p);
struct SceAvPlayerFileReplacement {
struct AvPlayerFileReplacement {
void* object_ptr;
SceAvPlayerOpenFile open;
SceAvPlayerCloseFile close;
SceAvPlayerReadOffsetFile readOffset;
SceAvPlayerSizeFile size;
AvPlayerOpenFile open;
AvPlayerCloseFile close;
AvPlayerReadOffsetFile read_offset;
AvPlayerSizeFile size;
};
enum class SceAvPlayerEvents {
enum class AvPlayerEvents {
StateStop = 0x01,
StateReady = 0x02,
StatePlay = 0x03,
@@ -182,26 +182,26 @@ enum class SceAvPlayerEvents {
DrmError = 0x40,
};
using SceAvPlayerEventCallback = void PS4_SYSV_ABI (*)(void* p, SceAvPlayerEvents event, s32 src_id,
void* data);
using AvPlayerEventCallback = void PS4_SYSV_ABI (*)(void* p, AvPlayerEvents event, s32 src_id,
void* data);
struct SceAvPlayerEventReplacement {
struct AvPlayerEventReplacement {
void* object_ptr;
SceAvPlayerEventCallback event_callback;
AvPlayerEventCallback event_callback;
};
enum class SceAvPlayerDebuglevels {
enum class AvPlayerDebuglevels {
None,
Info,
Warnings,
All,
};
struct SceAvPlayerInitData {
SceAvPlayerMemAllocator memory_replacement;
SceAvPlayerFileReplacement file_replacement;
SceAvPlayerEventReplacement event_replacement;
SceAvPlayerDebuglevels debug_level;
struct AvPlayerInitData {
AvPlayerMemAllocator memory_replacement;
AvPlayerFileReplacement file_replacement;
AvPlayerEventReplacement event_replacement;
AvPlayerDebuglevels debug_level;
u32 base_priority;
s32 num_output_video_framebuffers;
bool auto_start;
@@ -209,13 +209,13 @@ struct SceAvPlayerInitData {
const char* default_language;
};
struct SceAvPlayerInitDataEx {
struct AvPlayerInitDataEx {
size_t this_size;
SceAvPlayerMemAllocator memory_replacement;
SceAvPlayerFileReplacement file_replacement;
SceAvPlayerEventReplacement event_replacement;
AvPlayerMemAllocator memory_replacement;
AvPlayerFileReplacement file_replacement;
AvPlayerEventReplacement event_replacement;
const char* default_language;
SceAvPlayerDebuglevels debug_level;
AvPlayerDebuglevels debug_level;
u32 audio_decoder_priority;
u32 audio_decoder_affinity;
u32 video_decoder_priority;
@@ -233,25 +233,25 @@ struct SceAvPlayerInitDataEx {
u8 reserved[3];
};
enum class SceAvPlayerVideoDecoderType {
enum class AvPlayerVideoDecoderType {
Default = 0,
Reserved1,
Software,
Software2,
};
enum class SceAvPlayerAudioDecoderType {
enum class AvPlayerAudioDecoderType {
Default = 0,
Reserved1,
Reserved2,
};
struct SceAvPlayerDecoderInit {
struct AvPlayerDecoderInit {
union {
SceAvPlayerVideoDecoderType video_type;
SceAvPlayerAudioDecoderType audio_type;
AvPlayerVideoDecoderType video_type;
AvPlayerAudioDecoderType audio_type;
u8 reserved[4];
} decoderType;
} decoder_type;
union {
struct {
s32 cpu_affinity_mask;
@@ -261,34 +261,34 @@ struct SceAvPlayerDecoderInit {
u8 compute_queue_id;
u8 enable_interlaced;
u8 reserved[16];
} avcSw2;
} avc_sw2;
struct {
u8 audio_channel_order;
u8 reserved[27];
} aac;
u8 reserved[28];
} decoderParams;
} decoder_params;
};
struct SceAvPlayerHTTPCtx {
struct AvPlayerHTTPCtx {
u32 http_context_id;
u32 ssl_context_id;
};
struct SceAvPlayerPostInitData {
struct AvPlayerPostInitData {
u32 demux_video_buffer_size;
SceAvPlayerDecoderInit video_decoder_init;
SceAvPlayerDecoderInit audio_decoder_init;
SceAvPlayerHTTPCtx http_context;
AvPlayerDecoderInit video_decoder_init;
AvPlayerDecoderInit audio_decoder_init;
AvPlayerHTTPCtx http_context;
u8 reserved[56];
};
enum class SceAvPlayerAvSyncMode {
enum class AvPlayerAvSyncMode {
Default = 0,
None,
};
using SceAvPlayerLogCallback = int PS4_SYSV_ABI (*)(void* p, const char* format, va_list args);
using AvPlayerLogCallback = int PS4_SYSV_ABI (*)(void* p, const char* format, va_list args);
void RegisterLib(Core::Loader::SymbolsResolver* sym);

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