Compare commits

...

1349 Commits

Author SHA1 Message Date
nmzik 099de8dea6 graphics: publish each PM4 WRITE_DATA word exactly once 2026-10-18 16:17:51 +02:00
opcod3 f4bdb52922 agc: restore verified fused shader size name 2026-10-18 16:12:28 +02:00
nmzik 22ef16a044 shader: implement PS5 vector data cache invalidation 2026-10-18 15:57:14 +02:00
nmzik 37df7f3278 Show pipeline cache sizes in MB and remove obsolete texture folder cleanup 2026-10-18 03:57:45 +02:00
nmzik 33208a545a shader: remove artificial sampled image and sampler pair limit 2026-10-18 03:20:38 +02:00
Santiago Paquete 4059179e9d graphics: write proven compute buffer fills to guest memory (#1628)
Avoid readbacks for compute metadata fills

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-10-18 05:42:14 +02:00
nmzik fe3857a171 graphics: materialize CMASK clears for multisampled targets (PPSA13794) 2026-10-18 02:37:56 +02:00
nmzik c3e7ec8285 graphics: fix Jusant regression from d8c4a9af3 2026-10-18 01:03:37 +02:00
nmzik 763d3be3a9 graphics: add opt-in ZMask support and launcher rendering options 2026-10-17 17:50:02 +02:00
nmzik d8c4a9af38 graphics: preserve HTILE metadata across native image replacement 2026-10-17 17:31:25 +02:00
Juan Pablo Farias 6aa3846fb2 feat: add an in-game performance panel (#1090)
Add in-game performance panel

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-10-17 14:47:51 +02:00
Felipe 415387f00d Support multiple controllers for local multiplayer (#1583)
* Support multiple controllers for local co-op
2026-10-17 13:15:22 +02:00
Matthew Hurley 890393fbe6 vulkan: start without fragmentShaderBarycentric on GPUs that lack it (#1590)
* vulkan: start without fragmentShaderBarycentric on GPUs that lack it

Pascal (GTX 10xx), RDNA 1 and older drivers have no
VK_KHR_fragment_shader_barycentric, so device selection rejected them
with 'Could not find suitable device' (#1432, #1416, #762). The SPIR-V
backend only emits the capability for pixel shaders with
per-vertex/barycentric inputs, so make the extension and feature
optional: warn at selection and creation, enable only when supported.
Shaders that need custom barycentrics fail at pipeline creation
instead of blocking startup for every game.

* vulkan: fix macOS build and warn about unsupported GPUs

---------

Co-authored-by: Matthew Hurley <171001439+theantipopau@users.noreply.github.com>
Co-authored-by: nmzik <Nmzik@mail.ru>
2026-10-17 12:55:33 +02:00
nmzik 9f88043ebe shader: use compact integer RTZ half conversion 2026-10-17 12:23:12 +02:00
nmzik c2173801d4 shader: skip resources in proven empty unsigned loops 2026-10-17 10:38:14 +02:00
nmzik 56d03f16e9 network: UDPP2P 2026-10-17 10:24:45 +02:00
nmzik 3ecc6b7d1b network: implement POSIX socket shutdown on Linux 2026-10-17 10:10:16 +02:00
nmzik 5bf37f52ad renderer: clear compressed stencil with pending depth metadata 2026-10-17 09:50:11 +02:00
nmzik 57791645e4 renderer: track attachment load clears by image aspect 2026-10-17 09:34:51 +02:00
nmzik d1fe1324c8 shader: keep coherent 64bit atomic 2026-10-17 07:52:20 +02:00
nmzik b485dd24be system service: stub 2026-10-17 07:30:21 +02:00
nmzik ae25558321 shader: size NGG primitive outputs from amplification 2026-10-17 06:54:45 +02:00
nmzik ec08ea197b shader: new fill pattern 2026-10-17 06:24:29 +02:00
nmzik f6f1ac8b40 shader: batch dependent folds to avoid repeated SSA graph walks 2026-10-17 06:20:02 +02:00
Nawid3333 b82512be06 shader: read float inline constants on 64-bit operands as f64 bits (#1576)
A float inline constant (240-248) read by a 64-bit operand is the f64 bit
pattern for integer B64 opcodes too: AMD's compilers emit
v_lshrrev_b64 v[4:5], v0, 1.0 for 0x3ff0000000000000 >> lane. ReadU32Pair
returned {f32 bits, 0}, so only F64-typed reads had the right value.

Based on TheCruZ's 284deab28 (closed #1219).

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 05:21:06 +02:00
Nawid3333 ba8b0c85b8 shader: keep quiet NaNs with payload bits out of the packed f16 min/max sNaN path (#1579)
V_PK_MIN_F16 and V_PK_MAX_F16 return the quieted NaN for a signaling NaN
operand and the other operand for a quiet one (per half, as V_MIN_F16 and
V_MAX_F16 do). The signaling test masked the half with 0x7c00 and checked
for a nonzero payload, so a quiet NaN with payload bits such as 0x7e01 was
taken as signaling and returned. Mask with 0x7e00 so the quiet bit must be
clear.

Two more vectors in PackedMinMaxF16NanAndSignedZeroEdges cover it.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 05:12:37 +02:00
Nawid3333 b6bd9ecae4 shader: read float inline constants on 16-bit operands as half bits (#1582)
The 16-bit encodings of the float inline constants are fixed: the exact
halves of 0.5, 1.0, 2.0 and 4.0 and their negations, and 0x3118 for
1/(2*pi). Read16LaneBits converted the 32-bit value at run time instead,
through PackHalf2x16, which the AMD driver rounds toward zero, so
1/(2*pi) became 0x3117. Use the encodings directly.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 05:05:40 +02:00
Felipe b95ea4bb5f Support mountable-content DLC (addcont with real content) (#1581)
Support mountable-content DLC (addcont) and fix PlayGo chunk count query
2026-10-17 04:44:28 +02:00
Nawid3333 e93b4b0378 shader: support returning 32-bit LDS compare-exchange (DS_CMPST_RTN_B32) (#1578)
* shader: support DS_CMPST_RTN_B32

Assassin's Creed Valhalla (PPSA01490, #281) stops on DS opcode 0x30 in a
compute shader. DS compares DATA and stores DATA2, the opposite of
BUFFER_ATOMIC_CMPSWAP, so the 32-bit atomic path swaps the two for this
opcode, as the 64-bit form does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* shader: reject unsupported GDS compare-store variant

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: nmzik <Nmzik@mail.ru>
2026-10-17 04:37:16 +02:00
nmzik 0fd41ae206 Fix Linux CI xxHash include path (#1580)
Fix xxHash include path capitalization for test builds
2026-10-17 04:37:00 +02:00
nmzik 9202bddad2 recognize verified pattern fills
Co-authored-by: Juan Pablo Farias <juanpablo.profissional.a.f@gmail.com>
2026-10-17 04:09:54 +02:00
nmzik 32587337b5 renderdoc: advance capture flips independently of logging 2026-10-17 04:09:54 +02:00
Çağatay Güçlü 02ead0e2e1 shader: 64-bit buffer atomic add (BUFFER_ATOMIC_ADD_X2) 2026-10-17 04:09:54 +02:00
NeySlim 4f1f3b1bb3 shader: make the f32 clamp modifier turn NaN into 0 2026-10-17 04:09:53 +02:00
Nawid3333 42bb0da520 loader: keep the caller's flags in the TLS stubs (#1571)
A patched TLS load calls TlsRegStub and SafeCall, which moved RSP past the
red zone with sub/add rsp,0x80. ADD and SUB write the arithmetic flags, so
the sub ran before SafeCall's pushfq saved them and the add ran after its
popfq restored them: guest code that compares, loads fs:[0] and then
branches on the flags could branch the wrong way. lea moves RSP without
touching the flags. The entry lea plus a two-byte nop keeps every patched
offset in both stubs; the exit lea is one byte longer and moves only ret.

TlsStubsPreserveFlags calls the stubs with two flag patterns and checks
the status flags, the output register and RAX; it fails with the old
bytes.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 00:05:08 +02:00
nmzik 5dec523143 Stub RazorCpu profiling markers in a dedicated library 2026-10-16 19:16:42 +02:00
nmzik d01633e18e Revert "Fix scalar buffer reads across sparse guest mappings"
This reverts commit d7974dc763.
2026-10-16 19:13:36 +02:00
nmzik e7ac242039 Load packaged system modules through the native module lifecycle 2026-10-16 19:13:36 +02:00
nmzik d7974dc763 Fix scalar buffer reads across sparse guest mappings 2026-10-16 18:20:31 +02:00
shadowbeat070 b899717900 renderer: log unsupported depth feedback once 2026-10-16 17:24:45 +02:00
shadowbeat070 d58aefde49 renderer: reduce synchronization and allocation overhead
Performance changes from #1495:

- Sync changed BDA ranges instead of scanning all mappings.
- Let VMA suballocate BDA buffers.
- Remove the renderer lock from presentation.
- Keep compatible pipeline caches across builds.
- Fold masked shifts that always produce zero.
2026-10-16 17:18:49 +02:00
Pipe530 4c6be6cd1d Localize trophy notifications with embedded JSON catalogs 2026-10-16 16:19:43 +02:00
Felipe 584c2e8ca6 Play snd0.at9 during the startup splash screen (#1545)
launcher: play snd0.at9 on title selection
2026-10-16 15:59:03 +02:00
nmzik 717b50155a launcher: rename executable to kyty_launcher 2026-10-16 12:57:28 +02:00
shadowbeat070 57b161019d shader: honor front-face input format 2026-10-16 12:57:27 +02:00
Felipe 3ff6606fcb Input mapping tabs UI, emulated touchpad, and rumble for non-PS5 controllers (#1541)
* Revamp input mapping dialog with tabs, gamepad remapping and gyro emulation toggle

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* Add emulated touchpad (mouse/gamepad) with particle skins; widen input dialog

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* Disable mouse touchpad mode when the cursor leaves the window

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* Add touchpad hand-cursor toggle; share touchpad options across both tabs

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* Hide touchpad trail and particles when the visual toggle is off

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* Rename input mapping tabs

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* Rumble non-DualSense gamepads from haptic audio

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* Fix input mapping, touchpad transitions, and rumble fallback

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: nmzik <Nmzik@mail.ru>
2026-10-16 04:04:37 +02:00
Ali Almohaya 6a0a666a41 loader: keep the output and log of a game LoadExec relaunches (#1480)
* loader: keep the output of a process LoadExec relaunches

LoadExec on Windows starts a new emulator process and exits the current
one. The new process was created without a console and without the
standard handles, so everything it printed was lost: a redirected log of
a game that relaunches itself ended at the relaunch.

Hand the new process the standard input, output and error handles,
inheriting only those, and let it share the console when there is one.

* loader: flush output before LoadExec starts the new program

On Windows, LoadExec flushed the C streams only after the new process
had been created, so output the old process still held could appear
after the new one's first lines. On Linux they were not flushed at all
before exec, which discards them.

Flush the log and every stream before starting the new program.

* loader: continue the log file across LoadExec

With --printf-direction File, the program LoadExec starts is given the
same --printf-output-file and opened it anew, emptying it. Everything
the first program had logged, its LoadExec line included, was lost.

LoadExec now sets KYTY_RELAUNCHED for the program it starts, which then
appends to the log file instead of replacing it. On Linux the variable
goes into the environment passed to exec rather than this process's
own, which other threads may be reading.

* loader: show LoadExec switches on the console

LoadExec logged the program it switched to only when guest output was
logged, and then only into the log: on a console the new program's
startup output followed the old one's without anything marking where
one program ended and the next began.

Write the switch to the console as well as the log, with the program's
arguments.
2026-10-16 03:01:17 +02:00
AN0DIN 83db2efec3 shader: pack v_cvt_pkrtz_f16_f32 with the native half conversion (GTA V) (#1520)
* shader: pack v_cvt_pkrtz_f16_f32 with the native half conversion

The round-toward-zero pack was emulated with integer operations: about 20 to 30 operations
per half. GTA V uses it in 613 of its 656 pixel shaders, about 16 times in each G-buffer
pixel shader.

The pair is now packed with PackHalf2x16, unpacked again, and each half whose magnitude
exceeds its input's takes one unit off. Half signs and magnitudes are separate, so that is
the next value toward zero, whatever rounding the native conversion uses as long as it
returns one of the two neighbours. Same bits as before for every finite input and infinity;
a NaN stays a NaN. Checked against the old code on 2 million values on the CPU, and on an
Apple M5 GPU through Metal (400 000 values, subnormals included, safe and fast math).

GTA V on an Apple M5 (MoltenVK), 1080p, fixed script camera, three places, A B B A between
launches: -1.7 to -2.8 ms per frame (+4 to +6 %).

Scope: generic
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* shader: remove half-pack commentary and unused shift helper

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: nmzik <Nmzik@mail.ru>
2026-10-16 02:56:35 +02:00
opcod3 13e4c315b6 agc: Cleanup names so they match NIDs (#1508)
* agc: Cleanup names so they match NIDs

Simple commit tidying up libSceAgc function names so they match their
NIDs. This just a tidy-up commit that makes it more obvious what each
function is.

* agc: Preserve unknown fused shader size name
2026-10-16 02:16:19 +02:00
Felipe 4242ec5a64 Add add-on (DLC) support (#1519)
Add add-on content support

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-10-16 02:09:39 +02:00
NeySlim c6b8210d7c test: fix the Linux and Windows CI test builds (#1504) 2026-10-16 01:43:24 +02:00
Mr. Big Britches 6568fe9a84 Implement Missing NGS2 System Functions Lock & Unlock (#1542)
* Implement NGS2 SystemLock

* Implement NGS2 SystemUnlock

* Add guard for system_handle value of 0

* Return correct error code from system_handle guard

* Validate NGS2 system handles before locking

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-10-16 01:39:40 +02:00
Felipe 57c4a6ee11 Make trophy toast duration configurable (5-10s, default 6s) (#1538)
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
2026-10-16 01:37:51 +02:00
Hector Mödinger S. 54abbf48f2 kernel: implement vectored writes for profile index saves 2026-10-16 01:27:57 +02:00
overlordxrz-source 56d3ce98f0 kernel: implement path-based truncate for replay files 2026-10-16 01:27:53 +02:00
nmzik cbe5b62947 file: keep independent Linux file handles coherent 2026-10-16 01:26:56 +02:00
nmzik f7ae86c982 kernel: optimize virtual range edits with an ordered map
Co-authored-by: shadowbeat070 <70843316+shadowbeat070@users.noreply.github.com>
2026-10-16 00:58:57 +02:00
shadowbeat070 30a4673c60 libs: port entitlement requests and fixed-refresh VRR status 2026-10-16 00:16:01 +02:00
nmzik a5ceb48184 agc: encode acquire-memory byte ranges in standard packets 2026-10-15 23:34:42 +02:00
nmzik c8caa27936 shader: preserve folded native constants for descriptor provenance 2026-10-15 23:22:30 +02:00
nmzik e4019af522 shader: remove disabled legacy stage register checks 2026-10-15 22:31:45 +02:00
nmzik f7226ca7dc graphics: emit PS5 register object and primitive IDs to RT7 2026-10-15 22:28:01 +02:00
nmzik d172ab75ca shader: reuse selector domains proven by prior resource accesses 2026-10-15 22:28:01 +02:00
nmzik bcf13e101e shader: validate texture mip ranges and channel selectors 2026-10-15 22:28:01 +02:00
nmzik 2caf2f7e4e shader: retain runtime count bounds for finite descriptor choices 2026-10-15 22:28:01 +02:00
nmzik df92a08990 shader: report descriptor materialization rejection context 2026-10-15 22:28:01 +02:00
nmzik e291589177 shader: resolve GPU-selected parent pointers and bounded child image tables
Co-authored-by: fxpw <fxpw@outlook.com>
2026-10-15 22:28:01 +02:00
nmzik 2285a25182 shader: prove narrowing loop masks through shared implication analysis
Co-authored-by: fxpw <fxpw@outlook.com>
2026-10-15 22:28:01 +02:00
nmzik a50e4de389 shader: recognize reversed unsigned greater-than resource bounds
Co-authored-by: fxpw <fxpw@outlook.com>
2026-10-15 22:28:01 +02:00
nmzik 959bee4799 graphics: checkpoint live Vulkan pipeline cache after new compilations
Co-authored-by: fxpw <fxpw@outlook.com>
2026-10-15 22:28:01 +02:00
nmzik 232e2f2593 shader: bound waterfall buffer descriptors with same-lane guards
Co-authored-by: fxpw <fxpw@outlook.com>
2026-10-15 22:28:01 +02:00
nmzik b4406b0467 graphics: render packed 11-11-10 UNorm targets with exact rounding
Co-authored-by: fxpw <fxpw@outlook.com>
2026-10-15 22:28:01 +02:00
nmzik fb213e8ae5 shader: share packed color component encoding 2026-10-15 22:28:01 +02:00
nmzik 87d938139d graphics: log complete per-target state before format resolution 2026-10-15 22:28:01 +02:00
nmzik 2a4ccaa5d5 shader: share proven selector domains for paired images and samplers 2026-10-15 22:28:01 +02:00
nmzik 9c04abacc5 shader: resolve shared selector keys once per materialization
Co-authored-by: fxpw <fxpw@outlook.com>
2026-10-15 22:28:01 +02:00
nmzik 5916a184cc shader: preserve affine image heap candidate domains
Co-authored-by: fxpw <fxpw@outlook.com>
2026-10-15 22:28:01 +02:00
nmzik fcab4e5d0d shader: trace unsupported sampled image candidate provenance 2026-10-15 22:28:01 +02:00
nmzik fe23334ff0 shader: remove unreachable candidate diagnostic branches 2026-10-15 22:28:01 +02:00
nmzik 81169d77ea shader: materialize compact image and paired sampler tables
Co-authored-by: fxpw <fxpw@outlook.com>
2026-10-15 22:28:01 +02:00
nmzik 7d24972b8f shader: report rejected indirect buffer candidate context 2026-10-15 22:28:01 +02:00
nmzik 1d3fd07fe6 shader: share indirect buffer format geometry lookup 2026-10-15 22:28:01 +02:00
nmzik 28766a915b audio: decode PS5 ATRAC9 discrete multichannel streams
Co-authored-by: fxpw <fxpw@outlook.com>
2026-10-15 22:28:01 +02:00
nmzik 279bc95941 graphics: track HTile clears across PS5 depth array slices
Co-authored-by: fxpw <fxpw@outlook.com>
2026-10-15 22:28:01 +02:00
nmzik 12c522bba5 graphics: log cached GPU completion beside dispatch submission ticks 2026-10-15 22:28:01 +02:00
nmzik 65a6f30f51 shader: compare real nested descriptor pointer instructions 2026-10-15 22:28:01 +02:00
nmzik bb2d6dbeb3 shader: share scalar condition results with direct subgroup votes
Co-authored-by: fxpw <fxpw@outlook.com>
2026-10-15 22:28:01 +02:00
nmzik 50844badbf shader: map debug SPIR-V blocks to native RDNA2 PCs 2026-10-15 22:28:01 +02:00
nmzik c1f6838e40 shader: share repeated raw indirect buffer load bodies 2026-10-15 22:28:01 +02:00
nmzik 6455546f26 shader: admit bounded multi-component formatted buffer loads
Co-authored-by: fxpw <fxpw@outlook.com>
2026-10-15 22:28:00 +02:00
nmzik dcc642551f graphics: classify signed byte textures for native sampling 2026-10-15 22:28:00 +02:00
nmzik dd429ef858 shader: decode high-half formatted buffer stores
Co-authored-by: fxpw <fxpw@outlook.com>
2026-10-15 22:28:00 +02:00
nmzik bc2664cefa shader: decode comparison gathers with explicit LOD
Co-authored-by: fxpw <fxpw@outlook.com>
2026-10-15 22:28:00 +02:00
nmzik 8b81f665a2 shader: separate indirect buffer candidates from tracked root limits
Co-authored-by: fxpw <fxpw@outlook.com>
2026-10-14 21:19:38 +02:00
nmzik 1039c54f5d shader: share indirect buffer array access after an empty root
Co-authored-by: fxpw <fxpw@outlook.com>
2026-10-14 21:17:44 +02:00
nmzik b24ce3440d shader: track buffer liveness and offsets by resource count
Co-authored-by: fxpw <fxpw@outlook.com>
2026-10-14 21:11:14 +02:00
nmzik 2f6ee0e91d shader: support RDNA2 high-half short buffer stores
Co-authored-by: fxpw <fxpw@outlook.com>
2026-10-14 20:55:50 +02:00
nmzik 6b1c4a7a71 test: model bounded scalar selector batches in native CFG coverage 2026-10-14 20:55:39 +02:00
nmzik 166b9a5eea test: dispatch null texture coverage with the intended wave size 2026-10-14 20:47:25 +02:00
nmzik 5313181ecf shader: bound workgroup selector prefixes from runtime starting indices 2026-10-14 20:39:25 +02:00
nmzik ceccd746d8 shader: resolve workgroup-selected descriptor prefixes from dispatch arguments
Co-authored-by: fxpw <fxpw@outlook.com>
2026-10-14 20:29:48 +02:00
nmzik 82470c7181 shader: share workgroup and selector count resolution 2026-10-14 19:45:31 +02:00
nmzik 4843d8d942 shader: support packed D16 XYZW formatted buffer stores
Co-authored-by: fxpw <fxpw@outlook.com>
2026-10-14 19:35:08 +02:00
nmzik c914435f20 shader: plan finite GPU-selected RGBA16 buffer stores 2026-10-14 19:13:16 +02:00
nmzik 7468e4f60a shader: share descriptor dispatch for scalar and wide buffer stores 2026-10-14 19:01:14 +02:00
nmzik b6da068313 shader: preserve typed candidates for unfiltered indirect image access
Co-authored-by: fxpw <fxpw@outlook.com>
2026-10-14 18:57:26 +02:00
nmzik 127cf8d46f shader: route image stores through shared indirect descriptor access
Co-authored-by: fxpw <fxpw@outlook.com>
2026-10-14 18:39:40 +02:00
nmzik e0586cc85a shader: decode unsigned byte loads into preserved low halves
Co-authored-by: fxpw <fxpw@outlook.com>
2026-10-14 18:21:58 +02:00
nmzik 302240da70 shader: lower complete wave minima for sparse fragment subgroups 2026-10-14 18:03:48 +02:00
nmzik 892e70c8a1 graphics: bind unbound textures as native null descriptors 2026-10-14 17:56:47 +02:00
nmzik 7c9da0e56f shader: share finite texture selection through masked first-lane reads
Co-authored-by: fxpw <fxpw@outlook.com>
2026-10-14 17:29:49 +02:00
nmzik 6d6da57a95 shader: share formatted stores for GPU-selected signed byte records 2026-10-14 17:10:02 +02:00
nmzik 04cb4c6553 shader: separate exact descriptor row bounds from pointer offsets 2026-10-14 16:55:47 +02:00
nmzik 487bbf95fd shader: share nested pointer-table image and sampler selection
Co-authored-by: fxpw <fxpw@outlook.com>
2026-10-14 16:40:15 +02:00
nmzik 3a925efddf graphics: preserve sparse spans in rebased mip-tail views 2026-10-14 16:07:49 +02:00
nmzik aeecc9343a test: give native binding fixture valid nonempty buffer descriptors 2026-10-14 16:02:33 +02:00
nmzik 8c7fe539b8 graphics: represent rebased contiguous mip-tail texture views
Co-authored-by: fxpw <fxpw@outlook.com>
2026-10-14 15:56:45 +02:00
nmzik c88f05f7b5 graphics: share signed storage conversion and support R16 image writes
Co-authored-by: fxpw <fxpw@outlook.com>
2026-10-14 15:36:29 +02:00
nmzik f3c017b168 shader: fold reads through empty scalar descriptor tables
Co-authored-by: fxpw <fxpw@outlook.com>
2026-10-14 15:17:03 +02:00
nmzik 4b549b9cb3 shader: prove constant post-tested image selector loops
Co-authored-by: fxpw <fxpw@outlook.com>
2026-10-14 15:11:12 +02:00
nmzik 9cc0bba80b shader: bound GPU-selected record descriptors by scalar table geometry 2026-10-14 14:45:56 +02:00
nmzik 150bcb06a9 shader: share runtime buffer format conversion across loads 2026-10-14 14:29:40 +02:00
nmzik 280b87adec shader: allow reverse left shifts to use shared SDWA partial writes 2026-10-14 05:20:23 +02:00
nmzik 26d326d1b0 shader: share bounded record descriptors for packed loads and byte stores
Co-authored-by: fxpw <fxpw@outlook.com>
2026-10-14 05:07:24 +02:00
nmzik 4cf5a96b79 shader: reuse prepared binding offsets and shared resource switch 2026-10-14 04:46:46 +02:00
nmzik 7bba785963 shader: load bytes and halfwords from GPU-selected buffers
Co-authored-by: fxpw <fxpw@outlook.com>
2026-10-14 04:35:21 +02:00
nmzik 8d18be71db shader: decode upper-half byte stores through shared operand selection
Co-authored-by: fxpw <fxpw@outlook.com>
2026-10-14 04:20:02 +02:00
nmzik 6abfe3bbe4 shader: share formatted loads and support packed D16 XYZW buffers
Co-authored-by: fxpw <fxpw@outlook.com>
2026-10-14 04:09:57 +02:00
nmzik 1905b28b3c shader: decode packed UNorm image loads through shared conversion
Co-authored-by: fxpw <fxpw@outlook.com>
2026-10-14 03:53:32 +02:00
nmzik 8e4c3b5e14 shader: prove finite masked selectors for writable buffer tables
Co-authored-by: fxpw <fxpw@outlook.com>
2026-10-14 03:48:26 +02:00
nmzik be5915c248 graphics: skip GPU-clean empty indirect dispatches before shader preparation
Co-authored-by: fxpw <fxpw@outlook.com>
2026-10-14 03:36:33 +02:00
nmzik 9e41d8320a shader: support returning 64-bit LDS max and compare-exchange 2026-10-13 21:33:50 +00:00
nmzik e998f21e71 shader: reuse EXEC proof contexts across shared predicate graphs 2026-10-13 21:33:50 +00:00
nmzik 3197ef093c test: align scalar image tables and buffer reads with PS5 semantics 2026-10-13 21:33:50 +00:00
nmzik fa0e81bfba shader: zero out-of-range scalar descriptor reads 2026-10-13 21:33:50 +00:00
nmzik 01ce973882 renderer: preserve guest writes to reused metadata buffers 2026-10-13 21:33:50 +00:00
nmzik f57d2c0965 shader: keep unbounded material selectors on bounded GPU heaps 2026-10-13 21:33:50 +00:00
nmzik 735a229236 shader: preserve native types in indirect image tables 2026-10-13 21:33:50 +00:00
nmzik 9ade7e3582 shader: prove inactive resources across masked traversal merges 2026-10-13 21:33:50 +00:00
nmzik 259a40abfc memory: honor sparse AMM unmaps and restore failed GPU ranges 2026-10-13 21:33:50 +00:00
nmzik f1577a5a94 shader: memoize bounded material record bit analysis 2026-10-13 21:33:50 +00:00
nmzik d08a6cef64 shader: specialize guarded packed material selectors 2026-10-13 21:33:50 +00:00
nmzik 907c65f54c shader: track material offsets scaled after lane selection 2026-10-13 21:33:50 +00:00
nmzik fe6499b86e shader: preserve clamped scalar material selector provenance 2026-10-13 21:33:50 +00:00
nmzik 6309ac838d shader: restrict shared-list descriptor bounds to overlapping producers 2026-10-13 21:33:50 +00:00
nmzik 19799b3079 shader: simplify invariant execution masks in descriptor proofs 2026-10-13 21:33:50 +00:00
nmzik 4e16234d32 shader: bound signed image loops from their initial descriptor index 2026-10-13 21:33:50 +00:00
Ali Almohaya 3c9da9c3f4 graphics: decode both channels of RG32 float metadata clears 2026-10-13 21:33:50 +00:00
nmzik ff6dffe298 graphics: decode packed unsigned float CMASK register clears
Co-authored-by: Ali Almohaya <AliAlmohaya@gmail.com>
2026-10-13 21:33:50 +00:00
nmzik 5f6dc0a8d0 shader: stream tile bitmaps within their fixed descriptor domain 2026-10-13 21:33:50 +00:00
nmzik 34893dd8c8 shader: recognize unconditional predicates in implication proofs 2026-10-13 21:33:50 +00:00
nmzik 50595d1c13 shader: recover counted image rows through private LDS spills 2026-10-13 21:33:50 +00:00
nmzik 717c54e085 gpu: match complete NOP marker tags and ignore opaque payloads
Co-authored-by: Ali Almohaya <AliAlmohaya@gmail.com>
2026-10-13 21:33:50 +00:00
nmzik 31b7be9ff2 graphics: materialize fast clears before sampling reused targets
Co-authored-by: Ali Almohaya <AliAlmohaya@gmail.com>
2026-10-13 21:27:07 +00:00
nmzik 40692dfb64 graphics: copy sparse buffer uploads through resident mappings 2026-10-13 21:27:07 +00:00
nmzik 9a3aca963a shader: combine image execution masks with descriptor branch bounds 2026-10-13 21:27:07 +00:00
nmzik 1fa79d5cac shader: specialize bounded pointer and packed image tables 2026-10-13 21:27:07 +00:00
nmzik c9ec82e32e shader: factor live execution guards before resource planning 2026-10-13 21:27:07 +00:00
nmzik 2f88a0a3b2 shader: elide bitcasts between identical physical types 2026-10-13 21:27:07 +00:00
nmzik 7e884f55e0 shader: reuse dominating descriptor loads across image samples 2026-10-13 21:27:07 +00:00
nmzik d70cbd4184 shader: bound descriptor worklists by their finite bit masks 2026-10-13 21:27:07 +00:00
nmzik 9bcf80bf67 graphics: share temporary staging for oversized image uploads 2026-10-13 21:27:07 +00:00
nmzik ed1195d1e7 shader: prove descriptor bounds from simplified image EXEC predicates 2026-10-13 21:27:07 +00:00
nmzik 25e1cc7ec9 shader: preserve descriptor bounds through guarded branch joins 2026-10-13 21:27:07 +00:00
nmzik a287a54f26 shader: prove guarded descriptor counts for interleaved image records 2026-10-13 21:27:07 +00:00
nmzik 56738aa4e1 shader: sample packed normalized images with one bilinear gather 2026-10-13 21:27:07 +00:00
nmzik c11254a996 shader: share format conversion for packed normalized image stores 2026-10-13 21:27:07 +00:00
nmzik aec8c88755 graphics: support signed 32-bit image atomic descriptors 2026-10-13 21:27:07 +00:00
nmzik 68d7bc94e2 shader: correlate masked first-lane material rows 2026-10-13 21:27:07 +00:00
nmzik 8ee31abd9d shader: bound indirect image selectors by counted scalar rows 2026-10-13 21:27:07 +00:00
nmzik 9a7c54da58 shader: share formatted buffer payload reads across format conversions 2026-10-13 21:27:07 +00:00
nmzik 5dc6914688 shader: lower bounded UInt formatted buffer copies to shared stores 2026-10-13 21:27:07 +00:00
nmzik a7a734b5d3 video: implement PS5 Vdecsw using a shared queued AVC decoder
Co-authored-by: Ali Almohaya <AliAlmohaya@gmail.com>
2026-10-13 21:27:07 +00:00
nmzik e2c8b61de6 shader: remove unreachable mixed image specialization paths 2026-10-13 21:27:07 +00:00
nmzik 145578ac03 shader: materialize image keys from proven GPU bitmap subsets 2026-10-13 21:27:07 +00:00
nmzik f01a3750d4 shader: validate indirect image operands at each typed access 2026-10-13 21:27:07 +00:00
nmzik 0e9c77b0a2 shader: bound material selectors by proven one-wave LDS append lists 2026-10-13 21:27:07 +00:00
nmzik d692d8ee08 shader: preserve full region addresses for LDS and GDS reads and writes 2026-10-13 21:27:07 +00:00
Ali Almohaya 460a196fca shader: emit dynamic sample offsets with the enabled maintenance8 feature 2026-10-13 21:27:07 +00:00
nmzik 652154aead shader: merge typed image candidates as raw vectors with shared sampler variants 2026-10-13 21:27:07 +00:00
nmzik 49ebbfd627 shader: prove descending image ranges and prune impossible register selectors
Co-authored-by: Ali Almohaya <AliAlmohaya@gmail.com>
2026-10-13 21:27:07 +00:00
nmzik 7688093ca3 shader: resolve GPU scalar image selectors within buffer bounds
Co-authored-by: Ali Almohaya <AliAlmohaya@gmail.com>
2026-10-13 21:27:07 +00:00
nmzik df08b83287 shader: propagate late constants through affected IR users 2026-10-13 21:27:07 +00:00
nmzik fa68e104ea shader: fold full wave64 masks before register predication 2026-10-13 21:27:07 +00:00
nmzik fd66f580b4 shader: resolve packed buffer selectors with shared indexed stores
Co-authored-by: Ali Almohaya <AliAlmohaya@gmail.com>
2026-10-13 21:27:07 +00:00
nmzik 8f7d745383 graphics: simplify image usage and dirty state 2026-10-13 21:27:07 +00:00
nmzik f4692a450e graphics: avoid full-cache scans when deleting stencil associations
Co-authored-by: overlordxrz-source <overlordxrz-source@users.noreply.github.com>
Co-authored-by: TheCruZ <thecruzwtf@gmail.com>
2026-10-13 21:27:07 +00:00
nmzik df5b9b92be minor cleanup 2026-10-12 15:06:38 +02:00
Devran Cosmo Uenal 5b0ef07742 audio: keep NGS2 sampler voices within max_waveform_blocks (#1450)
audio: preserve NGS2 streaming buffer ownership
2026-10-12 14:22:06 +02:00
Ettore Sartori 5ce9a52936 Fix the splash screen (#1378)
Fix swapchain acquire semaphore reuse

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-10-12 13:40:59 +02:00
nmzik dad900c61d Fix BC alias writes and GC 2026-10-12 04:51:02 +02:00
nmzik 5b730d4df0 simplify guest gpu 2026-10-12 02:52:49 +02:00
nmzik e699a35f20 netctl: add opt-in host IPv4 connectivity and launcher toggle 2026-10-12 01:20:43 +02:00
nmzik 41beda4367 ampr: fix APR completion loss in 768-byte read batches
Co-authored-by: Chai T <ct@talnikar.in>
2026-10-12 01:20:43 +02:00
Chai T 048fe9f413 kernel: export sceKernelFtruncate through existing native handler 2026-10-12 01:20:43 +02:00
nmzik e51de54ee4 add hdr display support 2026-10-11 20:29:32 +02:00
nmzik 984cfcebd1 shader: emit native texel offsets using sample execution context
Co-authored-by: netwarex <mail@pety.me>
2026-10-11 18:53:01 +02:00
nmzik df0412afb5 shader: preserve shared predicates during resource plan extraction
Co-authored-by: netwarex <mail@pety.me>
2026-10-11 18:53:01 +02:00
nmzik f28c0fccb2 texture: preserve guest DCC metadata for comparison depth aliases
Co-authored-by: netwarex <mail@pety.me>
2026-10-11 18:53:01 +02:00
netwarex 4c87dbebb2 shader: select indirect texture descriptors for image gathers 2026-10-11 18:53:01 +02:00
nmzik 16a7fe689a fix windows compilation (2) (#1411)
* fix windows compialtion (2)

* loader: guard LoadExec close_range path with __linux__ for macOS

---------

Co-authored-by: ReverendOzmund <catmilker@proton.me>
2026-10-11 11:11:02 +02:00
thenotsoquietninja44-collab 6f0cddd440 implement LoadExec (windows) 2026-10-11 08:24:33 +02:00
nmzik 4084a008ea fix windows compilation 2026-10-11 07:53:59 +02:00
HamsterCL c0ebf22476 tests: rename a local that collides with the Windows small macro (#1400)
windows.h pulls in rpcndr.h, which defines `small` as `char`. The R64 BC1
array case added in b7b335ac declared `const auto small`, so the Windows
build of shader_recompiler_compute_tests failed to compile:

  ShaderRecompilerComputeTests.cpp(17928,24): error: expected unqualified-id

Rename the local to `small_array`.
2026-10-11 09:35:18 +02:00
nmzik cb375ec35a add load exec
Co-authored-by: thenotsoquietninja44-collab <thenotsoquietninja44@gmail.com>
2026-10-11 09:31:31 +02:00
nmzik 6f3bebcb50 playgo: read plgx chunks 2026-10-11 09:31:31 +02:00
nmzik 1029511bbc add depth to color copy
Co-authored-by: shadowbeat070 <70843316+shadowbeat070@users.noreply.github.com>
2026-10-11 09:31:31 +02:00
nmzik 65144ce4ac gpu: centralize depth copy state validation in target resolution 2026-10-11 09:31:31 +02:00
nmzik f848d2761b add srt walker 2026-10-11 09:31:31 +02:00
ReverendOzmund 730e1a3cf3 docs: add Fedora and Fedora Atomic (Bazzite) build instructions (#1372)
* docs: add Fedora and Fedora Atomic (Bazzite) build instructions

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SscrMzrvwrj17PJsfzqog9

* docs: note --nvidia for Distrobox on NVIDIA hosts

* docs: streamline Fedora build instructions

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: nmzik <Nmzik@mail.ru>
2026-10-11 03:24:15 +02:00
nmzik d4bb7fd786 agc: remove command buffer debug dump 2026-10-11 03:03:26 +02:00
popcoder565 fbea51c684 agc: implement sceAgcSetNop (#1343)
* agc: implement sceAgcSetNop

Star Wars Outlaws calls sceAgcSetNop (K2mciNVxUCE) and crashes right after
the unresolved stub returns, without the packet being disabled.

The call turns a packet into a NOP of the same length. Clear the emulator's
custom NOP code as well, so packets that the HLE encodes as NOPs, such as
end-of-pipe actions, stop executing too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* agc: keep packets disabled by sceAgcSetNop from reading as markers

A disabled packet whose first payload word carries the 0x6875 marker
signature still reached the marker handler, which can flip or stop on an
unknown marker ID. Clear the signature so the packet is skipped like any
other NOP.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* agc: tidy SetNop logging and comments

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: nmzik <Nmzik@mail.ru>
2026-10-11 03:00:09 +02:00
Devran Cosmo Uenal a6f4e8e7f4 AvPlayer: recycle output buffers so the decoder can run ahead 2026-10-11 02:08:27 +02:00
nmzik 448a4c8a6a launcher: reorganize panels 2026-10-11 01:44:04 +02:00
nmzik ece4e28740 gpu: store private format byte sizes in uint8_t 2026-10-11 01:25:47 +02:00
nmzik 58ba1e4cb4 docs: update README wording and grammar 2026-10-11 01:13:14 +02:00
nmzik cf77fb4353 shader: initialize NGG vertex count from active native invocations 2026-10-11 01:05:56 +02:00
nmzik 7e4e142aae gpu: enable native R8 SNORM texture sampling 2026-10-11 01:05:56 +02:00
nmzik b7b335ac63 gpu: admit block-compressed textures in PS5 R64 tiling 2026-10-11 01:05:56 +02:00
nmzik 9a5dd9faff agc: reserve driver backing before guest direct-memory allocation 2026-10-11 01:05:56 +02:00
nmzik 947627d10d docs: clarify pull request scope 2026-10-10 22:47:36 +02:00
Kelvin Oliveira 1cfb9522a3 controller: use Back as the touchpad click on pads without a touchpad (#1355)
* controller: use Back as the touchpad click on pads without a touchpad

Gamepads without a touchpad (Switch, Xbox, 8BitDo, ...) cannot click it, so
games that require the touchpad can't be played with them. The keyboard
already emulates it (Backspace/Tab); gamepads had nothing.

For SDL_GAMEPAD_BUTTON_BACK on a pad that reports no touchpads, report
PAD_BUTTON_TOUCH_PAD plus a finger at the centre of the touchpad. Pads with a
real touchpad are unchanged.

Fixes #1298

* controller: establish touch before fallback click

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-10-10 19:20:34 +02:00
nmzik f63d3befdc Add startup splash screen 2026-10-10 19:07:06 +02:00
nmzik 307fdcf7ad add self updater (#1352)
* add self updater

* remove updater tests after validation
2026-10-10 05:42:32 +02:00
Mac 679be25c37 shader: recognize remaining disabled debug branches 2026-10-10 04:31:55 +02:00
fxpw fa56c5eae9 shader: add scalar zero-bit count and search operations 2026-10-10 04:31:55 +02:00
foufouadi 3b9e176b70 shader: support VOP1/VOP2 DPP8 fetch-inactive 2026-10-10 04:31:55 +02:00
Bartlomiej Wolynczyk 053f5fd3cc shader: emit DPP row_share instead of an identity move 2026-10-10 04:31:55 +02:00
HamsterCL f3836bb831 tests: fix the Linux build of ResourceMaterializationTests (#1333)
tests: avoid empty optional::emplace() on IndirectDescriptor (fixes Linux build)

clang with libstdc++ 14 does not treat std::optional<DescriptorSource::IndirectDescriptor>
as default-constructible (nested struct with default member initializers), so the
argument-less emplace() fails to resolve. Pass an explicit value-initialized
IndirectDescriptor, matching the form already used elsewhere in this file.
2026-10-10 03:47:38 +02:00
popcoder565 2f4d0f383e shader: add SDWA support for V_MIN_I32 (#1342)
WWE 2K26 stops building a shader CFG with "unsupported family=VOP2
opcode=0x11 raw=[0x220404f9 0x00060605] reason=VOP2 SDWA modifier is not
supported for opcode".

V_MIN_I32 takes the same integer path as V_MAX_I32, so give it the same
full-destination SDWA profile. The test runs the game's encoding, which
takes the signed minimum with the zero-extended low byte of a register.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 03:43:08 +02:00
TheCruZ d247d3d60c shader: complete signed 64-bit integer comparisons 2026-10-10 03:36:25 +02:00
nmzik 93452b24e3 renderer: cache dynamic graphics state 2026-10-10 03:28:02 +02:00
nmzik 5559cfcbb2 renderer: optimize tiling and reuse centralized image layouts 2026-10-10 03:27:13 +02:00
nmzik 1c301c9aab Revert "shader: keep scalar payload and terminal conditions on the GPU" 2026-10-09 21:10:15 +02:00
nmzik 59183dbfa8 shader: add missing F64 VOPC compares
Co-authored-by: Hector Mödinger S. <hectormodinger@gmail.com>
2026-10-09 21:01:51 +02:00
nmzik c1926f915d update screenshot 2026-10-09 19:07:22 +02:00
nmzik 7da3c4ed21 launcher: add resizable game grid/improve controller setup 2026-10-09 19:03:35 +02:00
nmzik 3e9f88bf79 shader: isolate SWAPPC work from ordinary shader paths 2026-10-09 17:27:07 +02:00
nmzik 8c81386568 shader: share finite descriptor planning with GPU-selected inline samplers 2026-10-09 15:06:39 +00:00
nmzik bb5edbd490 shader: expose graphics compute queue fields to GETREG 2026-10-09 15:06:39 +00:00
nmzik 1818aae562 shader: link scalar leaf calls only for SWAPPC programs
Co-authored-by: Behzad <behzadkhan1736@gmail.com>
2026-10-09 15:06:39 +00:00
nmzik 165cd884ca agc: initialize function table in tracked driver memory 2026-10-09 15:06:39 +00:00
nmzik 973809cde0 shader: retain bounded scalar material image selectors 2026-10-09 15:06:39 +00:00
nmzik 71c7261740 shader: share indirect texture dispatch with image loads 2026-10-09 15:06:39 +00:00
nmzik 5b68a26cce shader: keep scalar payload and terminal conditions on the GPU 2026-10-09 15:06:39 +00:00
nmzik 3b1a94707a shader: capture only memory-dependent resource predicates 2026-10-09 15:06:39 +00:00
nmzik 488c0acae9 shader: resolve writable descriptors selected by immutable branches 2026-10-09 15:06:39 +00:00
nmzik 4c8fc53a85 agc: support one-word NOP reservations and share packet sizing 2026-10-09 14:02:06 +02:00
nmzik 3ae5a9b70a agc: implement branch target patching and packet size queries 2026-10-09 13:01:19 +02:00
nmzik a31e2cd361 shader: BUFFER_LOAD_SHORT_D16_HI 2026-10-09 12:57:04 +02:00
nmzik 1bd282ec0a shader: BUFFER_LOAD_SHORT_D16 2026-10-09 12:57:04 +02:00
nmzik 1fc520cd62 shader: FLAT_STORE_DWORD 2026-10-09 12:57:04 +02:00
nmzik 7b9997baea shader: fold exact float class masks into native NaN predicates 2026-10-09 02:54:21 +02:00
nmzik 393257eaae shader: classify float NaNs with one magnitude comparison 2026-10-09 02:54:21 +02:00
nmzik 13e3ca314c shader: unpack buffer offsets from one load per packed word 2026-10-09 02:54:21 +02:00
nmzik b4853a0e08 shader: preserve export vectors instead of rebuilding scalar components 2026-10-09 02:54:21 +02:00
nmzik ee4dd90649 shader: emit native integer operations and remove signedness casts 2026-10-09 02:54:21 +02:00
nmzik 3df456675d shader: own control flow on IR blocks with direct targets 2026-10-09 01:59:41 +02:00
nmzik 8abf99c56e shader: emit bounded SPIR-V operands without temporary vectors 2026-10-09 01:58:39 +02:00
nmzik 7c6121cba5 shader: build CFG labels and targets from ordered storage 2026-10-09 01:55:50 +02:00
nmzik 46997dfc7a shader: retain resource type IDs in SPIR-V emission state 2026-10-09 01:55:50 +02:00
nmzik 97fda7b10f renderer: bind prepared buffer descriptors without copying 2026-10-09 01:49:18 +02:00
nmzik dbe5353f3a shader: eliminate retained SRT lookup aliases 2026-10-09 01:44:34 +02:00
nmzik e1ac893a0c shader: collect usage once and emit descriptor slots directly 2026-10-09 02:17:38 +04:00
nmzik b35cdc39b7 shader: append deferred Phi operands directly to SPIR-V storage 2026-10-09 01:40:52 +04:00
nmzik 52dbc724f8 shader: store SPIR-V definitions directly in IR nodes 2026-10-09 01:40:41 +04:00
Mac 2f4b8a335d shader: allow SDWA byte destinations for bitwise VOP2 ops 2026-10-08 22:12:05 +04:00
nmzik b38b7454a6 Preserve vertex export locations for mixed pixel interpolation 2026-10-08 22:05:53 +04:00
nmzik b65dc12208 Track pad port ownership and reject duplicate opens 2026-10-08 21:58:53 +04:00
Devran Cosmo Uenal 58978d154a font: rasterize glyphs larger than 128 pixels (#1214)
Glyph images were rendered into a fixed 128x128 buffer and their width and
height were clamped to 128. Since glyphs are rasterized at the requested
scale (f96a14a0), large text such as title cards lost every row and column
past 128 pixels, so letters were drawn cut into bands.

The glyph buffers now grow to the glyph's bitmap box and width_byte is the
glyph's width. The VGA fallback font keeps its 128-pixel limit; scalable
glyphs are limited to 4096 pixels only to reject absurd scales.
2026-10-08 20:03:13 +04:00
popcoder565 1f3adf5109 cmake: accept glslang's current tool name and document Python 3 (#1161)
* cmake: accept glslang's current tool name and document Python 3

Official glslang release archives for Windows ship the compiler only as
glslang.exe, so configuring with one of them on PATH could not find
glslangValidator. Fall back to glslang; glslangValidator is still
preferred where both exist.

The bundled SPIRV-Tools needs Python 3 at configure time, which the
Windows build requirements did not mention.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs: list Python 3 in the Linux and macOS prerequisites

The bundled SPIRV-Tools calls find_host_package(Python3 REQUIRED) on every platform, so the apt and Homebrew package lists need it too, not only the Windows requirements.

* cmake: remove glslang naming comment

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: nmzik <Nmzik@mail.ru>
2026-10-08 19:46:09 +04:00
NeySlim 107d5f750a libNet: finish NpCommerce dialogs at open (#1166)
* libNet: finish NpCommerce dialogs at open

* libNet: complete NpCommerce dialog cancellation

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-10-08 19:31:47 +04:00
Dimitar Vagalinski f40755173f ampr: keep resolved host paths in native form (#1175)
* ampr: keep resolved host paths in native form

ResolveOnePath stored each resolved file as a UTF-8 std::string
(Common::PathToString) and the read, stat and size paths turned that
string back into a std::filesystem::path. On POSIX this round trip is a
no-op, but on Windows path(std::string) decodes the bytes with the ANSI
code page, not UTF-8 (/utf-8 only sets the source and execution
charsets). Any non-ASCII character in the game folder therefore produced
a different path: the resolve step found the file through the native
path, then every APR read of it failed with ENOENT.

Tokyo Xtreme Racer (#1156) installed under "D:/Инсталляторы/[ps5]/..."
hits this on its first pak read:

  APR read missing host file: .../tokyoxtremeracer/content/paks/global.utoc
  Apr read failure 80020002 at CB offset 0   (LowLevelFatalError, abort)

even though KernelStat and the directory listing see the same file.

Store std::filesystem::path in ResolvedPathInfo and the file-id table
and pass it straight to Common::File. Convert to UTF-8 only for the log
lines.

* tests: cover APR stat and size under a non-ASCII host folder

Resolve a file inside a Cyrillic directory through APR and check that
the stat and size exports find it by ID, matching the Tokyo Xtreme
Racer install layout from #1156. On POSIX the old string round trip
also passed, so this guards the Windows path.

* tests: read the non-ASCII APR fixture through an APR command

Review on #1175 noted that the Unicode fixture only checked the stat
and size exports. A submitted APR read opens the stored host path in
ExecuteCommand/ReadHostFileToGuest, which the fixture did not reach.

Add AprReadMatches, which submits one APR read command for a file ID
and compares the bytes, and use it on the file under the Cyrillic
folder. As with the stat and size checks, POSIX hosts run this path but
only Windows would show an ANSI code page round trip.

* Remove APR path tests from this change

* Remove unrelated formatting changes

* Remove native path explanatory comments

---------

Co-authored-by: overlordxrz-source <overlordxrz-source@users.noreply.github.com>
Co-authored-by: nmzik <Nmzik@mail.ru>
2026-10-08 19:27:10 +04:00
Romain Hedouin 4e14eed770 kernel: start the semaphore wait timer after the early returns (#1173)
Wait() read the clock and looked up the thread id before checking for an available token. Both are only needed once the thread has to block.
2026-10-08 19:21:36 +04:00
nmzik aa3b2cd57f Implement AGC async rewind imports 2026-10-08 17:43:02 +04:00
Dimitar Vagalinski 4865dd92ca libNet: answer sceNpGetAccountLanguage2 as a signed-out user (#1186)
* libNet: answer sceNpGetAccountLanguage2 as a signed-out user

sceNpGetAccountLanguage2 was not registered, so games that call it hit
the unresolved-import stub. The stub returns 0, which tells the game the
request succeeded and that the language code buffer now holds the
account's language, but nothing was written to it.

Saros (#1053) calls it from its analytics thread right after
sceNpGetAccountAge, each on its own request. sceNpGetAccountAge already
reports SCE_NP_ERROR_SIGNED_OUT there, so the game is told the user is
signed out for one query and signed in for the next. Demon's Souls
(#890), Ghost of Yotei (#1095) and NHL 27 (#1101) import it as well.

Register it next to the other NpManager account queries and answer the
way they do: SCE_NP_ERROR_INVALID_ARGUMENT for a request id <= 0 or a
null output pointer, SCE_NP_ERROR_SIGNED_OUT otherwise. The output is
left untouched because nothing was looked up.

* libNet: reject missing account language requests

---------

Co-authored-by: overlordxrz-source <overlordxrz-source@users.noreply.github.com>
Co-authored-by: nmzik <Nmzik@mail.ru>
2026-10-08 16:48:01 +04:00
Jetsku 3c62359e05 Fix/trigger effect state (#1132)
* Pad: report the adaptive trigger state instead of always 0

scePadGetTriggerEffectState returned 0 for both triggers. Games that wait for
the state of the trigger effect they set before acting on L2/R2 never saw it
change; in Astro Bot, L2/R2 actions such as punches did nothing in some levels.

The state now follows from the game's last effect per trigger (already kept
for the DualSense output) and the trigger's travel, 0..255 over the effect's
ten positions: feedback no force / pushing, weapon not / almost / fully
pressed, vibration not firing / firing, with the values 1..7 that duaLib
(WujekFoliarz/duaLib) reads from a DualSense input report. SDL does not expose
that report, so this is an approximation; it also works with other pads and
the keyboard, where a digital L2/R2 is full travel. The trigger intensity
setting changes only the output, not the reported state.

Tested in Astro Bot (PPSA21567 1.018) by a player in the levels where the
triggers did nothing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* tests: controller_settings covers scePadGetTriggerEffectState

Feedback, weapon and vibration states across the trigger travel, a trigger without an effect, a masked update keeping the other trigger's effect, and the intensity setting leaving the reported state unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Pad: a feedback trigger reports pushing only while it is pressed

A feedback effect from position 0 reported FEEDBACK_IS_PUSHING on an untouched trigger, so a game waiting for the change from no force to pushing never saw it. In Astro's Playroom the gacha capsules did not break on R2. Feedback states (modes 1, 4, 5) now need some travel (>= 8 of 255). Tested in Astro's Playroom (PPSA01325): the capsules break on R2 again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Pad: a vibration trigger reports firing only while it is pressed

A vibration effect from position 0 reported VIBRATION_IS_FIRING on an untouched trigger; in Astro's Playroom the gun fired by itself. Vibration states (modes 3 and 6) now need some travel, as the feedback states do. Tested in Astro's Playroom.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Pad: reject invalid handles in scePadGetTriggerEffectState; test the remaining effect modes

scePadGetTriggerEffectState ignored its handle and returned pad 1's state for any handle. It now returns
SCE_PAD_ERROR_INVALID_HANDLE (0x80920003) for handles other than 1, like the other pad queries in libPad.cpp
and duaLib.

controller_settings now also covers multiple-position feedback (mode 4: pushes only at positions with a
strength), slope feedback (mode 5: pushes from its start position, not on an untouched trigger) and
multiple-position vibration (mode 6: fires only at positions with an amplitude and a frequency).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Pad: scePadGetTriggerEffectState returns libScePad's invalid-argument code

A null state returned 0x80960005, which is SCE_USER_SERVICE_ERROR_INVALID_ARGUMENT,
not a pad error; libScePad's code is SCE_PAD_ERROR_INVALID_ARG (0x80920001), as
scePadSetTriggerEffect returns. The call now lives with the other pad calls in
controller.cpp so controller_settings tests its handle and argument checks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Pad: correct trigger effect state reporting

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: nmzik <Nmzik@mail.ru>
2026-10-08 16:00:17 +04:00
nmzik 62643c3424 system service: deliver initial AppContent entitlement updates through shared queue 2026-10-08 15:53:14 +04:00
nmzik 210d4dcd99 sysmodule: track shared module load references and unloaded status 2026-10-08 15:52:18 +04:00
nmzik 5a8808086a ampr: honor shared counter waits and completion writes 2026-10-08 03:36:59 +04:00
nmzik 861dd76d7f net: accept sufficient Ethernet address output buffers 2026-10-08 03:36:59 +04:00
nmzik db41d0482f kernel: retain POSIX file descriptor close-on-exec flags 2026-10-08 03:36:11 +04:00
Henrique Reis Neves de62664908 kernel: report /dev/random and /dev/urandom as character devices (#1140)
kernel: report entropy sources as character devices

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-10-08 03:35:58 +04:00
Nawid3333 34f6fd1f5f tests: cover the untested 16-bit integer ALU opcodes (#1151)
* tests: cover the 16-bit integer VOPC compares

V_CMP_{EQ,LE,GT,NE}_I16 and V_CMP_{EQ,LE,GT,NE,GE}_U16 decode and translate but
no test exercised them. VectorCompareI16U16Ops compares low halves that
differ in sign interpretation (0x8000 vs 0x7fff) with both the signed and the
unsigned opcodes, and uses operands whose high halves differ to check that only
the low 16 bits are compared. It runs in the default list and with
--int16-compare-only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* tests: cover the 16-bit integer VOP3 ALU ops

V_SUB_NC_U16, V_ADD_NC_I16, V_ASHRREV_I16, V_MAX_U16 and V_MIN_U16 decode and
translate but no test exercised them. Vop3Int16Ops checks wraparound without
clamp, the shift amount taken from the low four bits of src0, unsigned
ordering for max/min on 0x8000 vs 0x7fff, that the high halves of the sources
are ignored and that the high half of the destination is preserved. It runs in
the default list and with --int16-alu-only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* tests: cover the packed 16-bit integer VOP3P ops

V_PK_MAD_I16, V_PK_MAD_U16, V_PK_MUL_LO_U16, V_PK_ADD_I16, V_PK_SUB_U16,
V_PK_LSHLREV_B16, V_PK_LSHRREV_B16, V_PK_ASHRREV_I16, V_PK_MIN_I16, V_PK_MAX_U16
and V_PK_MIN_U16 decode and translate but no test exercised them. Vop3pInt16Ops
runs each on both halves with the default half selection: wraparound without
clamp, shift amounts from the low four bits of each src0 half, and min/max on
0x8000 vs 0x0001 so signed and unsigned ordering give different results. It
runs in the default list and with --int16-alu-only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 03:31:46 +04:00
Romain Hedouin 79a91ecfaf graphics: cache the macOS thread id in TrackingSpinLock (#1169)
Every lock and unlock called pthread_mach_thread_np. Cache it per thread like the Linux branch does.
2026-10-08 03:18:49 +04:00
nmzik 420bb51d6c fix regression 9f83fd5f0c 2026-10-08 02:42:14 +04:00
nmzik c86c8b4d93 audio: mix AudioOut2 objects and apply port gains
Co-authored-by: chenxiao07 <chenxiao07@gmail.com>
2026-10-08 01:47:34 +04:00
chenxiao07 e43aadf75f ampr: assign unique IDs to resolved file paths 2026-10-08 01:18:40 +04:00
shadowbeat070 9f25e3c23e shader: support partial SDWA multiply and byte-source moves 2026-10-08 01:10:49 +04:00
shadowbeat070 7881c69a54 shader: decode v_cmp_class_f16 2026-10-08 01:10:49 +04:00
shadowbeat070 9e666e4dd2 shader: support scalar byte sign extension 2026-10-08 01:10:49 +04:00
Nawid3333 c3a12397b0 tests: use function pointers in the concurrent backing read pairs (#1163)
TestConcurrentBackingReads (7e011fa5) builds its reader pairs with
std::pair {TryReadBacking, TryReadSparseBacking}. Class template argument
deduction then also considers pair's const T1& / const T2& constructors, which
deduce function types, and libstdc++ and libc++ reject a pair member of
function type ("data member instantiated with function type"), so
virtual_memory_allocation_tests no longer compiles on Linux and macOS. MSVC's
library accepts it, which is why Windows still builds.

Take the functions' addresses so the pairs hold function pointers.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 00:56:44 +04:00
nmzik 45b6d2c597 memory: copy sparse backing in one traversal 2026-10-07 23:17:53 +04:00
nmzik 7e011fa565 memory: allow concurrent backing reads 2026-10-07 23:10:14 +04:00
nmzik 4d10ea17a0 graphics: streamline staging-buffer writes 2026-10-07 22:48:42 +04:00
nmzik 006875ed4f graphics: pause memory-tracking spin loops 2026-10-07 22:47:50 +04:00
nmzik a87889f032 graphics: process upload regions in one traversal 2026-10-07 22:47:50 +04:00
nmzik 9c79d9d298 memory: flatten direct and batch mapping paths 2026-10-07 22:47:50 +04:00
nmzik c30ac7c904 memory: avoid redundant Windows view protection 2026-10-07 22:47:50 +04:00
nmzik 038d2257de tests: enable image aliasing coverage on Linux 2026-10-07 21:35:28 +04:00
nmzik 190f838ea4 shader: preserve workgroup bounds for scalar image descriptor tables 2026-10-07 21:25:53 +04:00
nmzik 470669c677 graphics: make raw image synchronization an opt-in setting 2026-10-07 21:17:35 +04:00
Claxten dd754065d8 graphics: preserve full tiled array backing in image-to-buffer copies 2026-10-07 21:17:35 +04:00
Claxten 743fdc6990 graphics: synchronize raw storage reads with GPU image aliases 2026-10-07 21:17:35 +04:00
Claxten 9f83fd5f0c graphics: apply indirect draw offsets to guest user SGPRs 2026-10-07 21:17:35 +04:00
Claxten 5297abb7ac shader: run non-amplifying NGG programs in mesh workgroups 2026-10-07 21:17:35 +04:00
Claxten a8beac190f shader: evaluate scalar branch decisions across the complete guest wave 2026-10-07 21:17:35 +04:00
Claxten b96871e2bf shader: unpack compressed SNORM16 color exports as normalized signed values 2026-10-07 21:17:35 +04:00
Claxten 21a1346e27 graphics: route compact color exports through CB_SHADER_MASK 2026-10-07 21:17:35 +04:00
Claxten 3ba6ebae81 shader: initialize perspective sample barycentrics at SampleId 2026-10-07 20:44:46 +04:00
nmzik fbf6ae400c graphics: preserve depth array layout during storage reinterpretation 2026-10-07 20:44:46 +04:00
Pipe530 d2413fc2eb trophies: add viewer inspector and wrap toast titles 2026-10-07 17:22:44 +04:00
nmzik 96eb681b90 shader: add V_MIN3_U16 opcode 2026-10-07 16:22:30 +04:00
nmzik 26cce9909a shader: add BUFFER_LOAD_FORMAT_D16_X opcode 2026-10-07 16:22:30 +04:00
nmzik 5af370c257 shader: add BUFFER_STORE_FORMAT_D16_X opcode 2026-10-07 16:22:30 +04:00
nmzik 67d7db685a agc: new abi 2026-10-07 16:22:30 +04:00
nmzik bb98f26433 shader: add missing I64/U64 compare variants 2026-10-07 05:03:09 +04:00
dcave14 cc44a43ebc systemservice: add an option to report the notice screen as skipped (#1127)
* systemservice: add an option to report the notice screen as skipped

sceSystemServiceGetNoticeScreenSkipFlag always returned false. Return the
new skip_notice_screen option instead. Games that check this flag skip
their boot logo movies when it is set; Marvel's Wolverine, for example,
then does not queue movies/BootSequence/BootSequence.movie.

The option defaults to off, so behaviour is unchanged unless it is
enabled with --skip-notice-screen true or the launcher's "Skip boot
logos" checkbox. The launcher stores it with the other per-game settings,
so it is included in per-game config import and export.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Shorten skip notice screen wording

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: nmzik <Nmzik@mail.ru>
2026-10-07 04:21:27 +04:00
nmzik 2a18e66a4c gpu: validate depth copy state when drawing instead of decoding 2026-10-07 04:14:49 +04:00
Henrique Reis Neves e7cfe5a2f7 libkernel: implement sceKernelAioWaitRequests (#1109)
kernel: implement batch AIO completion waits

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-10-07 04:13:06 +04:00
nmzik 7415febd93 SDL title fix
Co-authored-by: netwarex <mail@pety.me>
2026-10-07 03:15:16 +04:00
NeySlim 7492cb9577 shader: emulate DS_ORDERED_COUNT as a GDS atomic (#1117)
* feat(shader): emulate DS_ORDERED_COUNT as a GDS atomic

* fix(shader): issue one ordered-count atomic per wave

* shader: correct ordered-count addressing and wave results

Use the M0 base and pixel packer offset for the GDS counter. Broadcast the
previous value to every lane and preserve the counter when EXEC is empty.

Add GPU regressions for add/exchange with full, partial, and empty EXEC in
wave32 and wave64. The targeted DS and buffer atomic suite passes 63 cases.

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-10-07 01:45:37 +04:00
NeySlim 60e53a39cc decoder: accept clamp on V_MIN3/MAX3/MED3_F16 (#1116)
fix(decoder): accept clamp on V_MIN3/MAX3/MED3_F16
2026-10-07 01:24:18 +04:00
Nawid3333 1b21161aac kernel: fix the macOS build of host thread naming (#1122)
* kernel: apply clang-format to pthread.cpp

Output of the repository's pre-commit clang-format hook (v22.1.3) on
this file; no code change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* kernel: fix the macOS build of host thread naming

199d0a9d (#1106) names guest threads on the host with the two-argument
glibc pthread_setname_np(thread, name). KYTY_PLATFORM is
KYTY_PLATFORM_LINUX on macOS too, so the macOS job now fails with "no
matching function for call to 'pthread_setname_np'": Apple's version
takes only the name and renames the calling thread. This code already
runs on the new thread itself (it passes pthread_self()), so use the
one-argument form on Apple with Apple's 63-character limit and keep the
Linux call unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Remove formatting

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: nmzik <Nmzik@mail.ru>
2026-10-07 01:18:48 +04:00
NeySlim 1195af2510 decoder: add V_CMPX_U_F32 (#1120)
feat(decoder): add V_CMPX_U_F32
2026-10-07 01:16:23 +04:00
nmzik 9a5658c038 launcher: add per-game config import and export 2026-10-07 01:02:33 +04:00
Oberd 199d0a9d92 kernel: name guest threads on the host (#1106)
PthreadCreate carries a guest thread name, but RunThread never handed it to
the host, so every guest thread showed up as the same generic host thread
name in core dumps, perf samples and htop.

Call pthread_setname_np() on Linux so host-side diagnostics can attribute
work to the guest thread that caused it.
2026-10-06 23:43:36 +04:00
nmzik e679486ed3 net: translate native UDP socket options and microsecond timeouts 2026-10-06 23:41:06 +04:00
Henrique Reis Neves 6ef406542c tests: make kyty_tests build and run every test without LTO (#1110)
avplayer_file_tests compiles libs/avPlayer.cpp into the test, and its
PRINT_NAME() calls Loader::Timer::GetTimeMs(). Add loader/timer.cpp to the
target, like the other tests that compile HLE library sources. CI links the
test with LTO, which drops the unused reference, so the failure only shows
in non-LTO builds such as the README's no-Qt instructions.

Clang with libstdc++ rejects optional<IndirectDescriptor>::emplace() with
no arguments in ShaderRecompilerComputeTests.cpp. Assign the descriptor the
same way the neighbouring test does.

trophy_system is registered with ctest but kyty_tests did not build its
executable, so ctest reported it as Not Run.

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-06 21:56:48 +04:00
Bartłomiej Wołyńczyk 35c6e8fff6 loader: enable the AMD CPU instruction patcher on macOS (#1014)
* loader: enable AMD CPU instruction patching on macOS

The guest instruction patcher was compiled out on macOS and runtimeLinker forced emulate_amd off,
so under Rosetta every SSE4a EXTRQ/INSERTQ took the SIGILL path (about 18 us each). Build the
patcher on all hosts and let --amd-cpu enable it on macOS like on Windows and Linux. The host
feature probe already reports no SSE4a under Rosetta, so EXTRQ becomes a native trampoline and the
remaining fallbacks keep using the x64 instruction emulator through the host exception handler.

* tests: macos_sse4a covers the guest instruction patcher on macOS

Patch EXTRQ/INSERTQ blobs in an RWX area with a trampoline page behind it, with the host features of
Rosetta (no SSE4a/RDPID/CLWB), and compare against the SIGILL emulator: EXTRQ must become a native
trampoline without SIGILL, INSERTQ stays a trap handled by the emulator, and nothing is touched
without emulate_amd.

* loader: emulate the patcher's VRSQRTPS trap and MWAITX on macOS

The AMD CPU patcher marks VRSQRTPS it cannot relocate by clearing a reserved
VEX.vvvv bit, which raises #UD on every host including Rosetta. The macOS build
left TryEmulateReciprocalSquareRoot and TryEmulateMonitorxMwaitx out, so the
guest died with an unhandled SIGILL at the first such site.

Both are plain SSE2/libc, so enable them on macOS. The Darwin context also
gains ClearUpperYmm so the VEX.128 result zeroes YMM[255:128] when the thread
has the AVX context. macos_sse4a covers the trapped VRSQRTPS and MWAITX.

* tests: macos_sse4a runs a plain VEX.128 VRSQRTPS through the patcher

The existing case started from an instruction that was already marked as a trap. The
new cases feed the ordinary encoding to PatchGuestInstructions and compare the result
with the emulated reference, both through a native trampoline and, when the instruction
cannot be relocated, through the trap mark and the signal emulator.

* loader: compact macOS instruction patcher coverage

Share the emulator dispatch chain while keeping SHA emulation limited to non-Apple hosts and preserving handler order. Remove a duplicate VRSQRTPS signal test already covered by both native and trapped patcher cases, plus blank lines left by removed platform guards.

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-10-06 21:55:11 +04:00
thenotsoquietninja44-collab 4852721005 net: export connect, getsockopt, sendto, and recvfrom 2026-10-06 21:32:46 +04:00
Felipe fb7ff7ec03 Map UDS events to trophies from dumped metadata; trophy viewer/overview improvements (#1088)
* Map UDS events to trophies via dumped metadata and redesign trophy UI

Correlate each UDS event to its stat ID (uds00.ucp) and trophy target (trophy00.ucp) instead of a hard-coded event, store trophy JSON with unlock date/time outside _SaveData, and add a PS5-style toast, viewer and overview.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* Fix trophy rule evaluation and share progress accounting

* Match trophy and reload toolbar styling

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: nmzik <Nmzik@mail.ru>
2026-10-06 17:45:26 +04:00
nmzik 7d2422abbe add remote cheats launcher 2026-10-06 15:44:26 +04:00
nmzik b929bbe3e0 shader: limit broad image tables to compatible views 2026-10-06 14:59:05 +04:00
nmzik ae1e92621d shader: sample mixed bindless images through contiguous native arrays 2026-10-06 14:53:17 +04:00
nmzik 5a491abbda shader: remove redundant descriptor sorting and stale null check 2026-10-06 14:53:17 +04:00
Claxten afbb322b32 kernel: deliver persistent user events once per wait 2026-10-06 14:53:17 +04:00
Claxten 5601861d67 shader: implement RDNA2 scalar 16-bit sign extension 2026-10-06 14:53:17 +04:00
Claxten cd06601022 shader: replace CPU selector chains with direct image-table lookup 2026-10-06 14:53:17 +04:00
nmzik c23de62184 shader: resolve nested descriptor selector tables with exact scalar offsets 2026-10-06 14:53:17 +04:00
Claxten 9caec9f2c8 shader: preserve RDNA2 DLC coherence for flat address loads 2026-10-06 14:53:17 +04:00
nmzik cdb64bfd4f graphics: share indirect draw handling and honor indexed sources 2026-10-06 00:35:02 +04:00
nmzik e5dcfdb87b graphics: bound unbounded buffer reads and writes (#1066)
Co-authored-by: João Lobo <joaodlobo@gmail.com>
2026-10-06 00:35:02 +04:00
nmzik 984010227f graphics: make depth bounds dynamic to reuse pipelines
Co-authored-by: TheCruZ <thecruzwtf@gmail.com>
2026-10-06 00:35:02 +04:00
TheCruZ 57c97ebd86 Decode 16-bit color clears (TheCruZ/KytyPS5-GTA@b8dcd826) 2026-10-06 00:35:02 +04:00
Rohit Mahto dc3cd2d2c9 libNet: honour the option mask in sceHttpUriBuild (#1069)
* libNet: honour the option mask in sceHttpUriBuild

sceHttpUriBuild's `option` argument (SCE_HTTP_URI_BUILD_WITH_*) selects which
components of the SceHttpUriElement end up in the output. HttpUriBuild logged
the value and ignored it, always returning the full URL.

Black Myth: Wukong calls it with SCHEME alone and requires "https://" (or
"http://") back before it starts an HTTP request. The full URL fails that
check, so the request starter returns false. The caller's "run on game thread
and wait" helper then returns early while its task stays queued, still holding
by-reference captures of a stack frame that is already gone. About 70 seconds
into boot the game thread runs that task against the dead stack and faults
(null read at eboot+0x59662f). With the mask honoured the game gets past that
point and reaches its title cinematic and menu.

Bits: SCHEME 0x01, HOSTNAME 0x02, PORT 0x04, PATH 0x08, USERNAME 0x10,
PASSWORD 0x20, QUERY 0x40, FRAGMENT 0x80. A mask with none of the eight bits
set keeps the previous "everything" behaviour for callers that never pass one.
A scheme-only build returns "https://", the authority marker belonging to the
scheme chunk.

Adds TestBuildHonoursOption to http_uri_parse covering scheme-only, hostname,
port, path, and the 0xff / 0 cases.

* libNet: simplify URI build code and tests

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-10-05 21:31:45 +04:00
nmzik e6fce45d3a gpu: skip drains for CPU-only memory unmaps 2026-10-05 21:00:12 +04:00
nmzik 5b826c6e4a shader: emit native 64-bit operations where compatible 2026-10-05 20:41:03 +04:00
nmzik 77d7722173 shader: disable explicit MAD denormal checks for performance testing
Comment out the five explicit flush checks and record the substantial 3DMiniGolf menu FPS drop on NVIDIA RTX 5080 Laptop GPU. Preserve separate multiply/add rounding and both NoContraction decorations.

The matched runs used silent logging, no debugger, no Vulkan validation, and the cd9fc6ff revert on both revisions. Native denormal behavior remains GPU-dependent.
2026-10-05 18:39:31 +04:00
nmzik 266c12cec6 Revert "shader: keep scalar data native and preserve raw addresses"
This reverts commit cd9fc6ff2d.
2026-10-05 18:39:31 +04:00
nmzik 7a0e1dafd7 shader: classify native half values with shared operand decoding 2026-10-05 18:39:31 +04:00
nmzik 1d41ddb378 shader: allow RDNA2 SDWA partial destinations for i24 multiply 2026-10-05 18:39:31 +04:00
nmzik 5c83060481 shader: resolve masked image keys in strided descriptor records 2026-10-05 14:43:21 +04:00
nmzik 72e4989b1e Add trophy notification support
Co-authored-by: Felipe <54341095+Pipe530@users.noreply.github.com>
2026-10-05 10:24:12 +04:00
fxpw 1d55272467 shader: support V_CMPX_NE_U16 2026-10-05 09:25:19 +04:00
nmzik 2b1b7ed0e4 shader: FLAT opcode=0x24 2026-10-05 08:48:20 +04:00
nmzik af3011cd69 shader: add missing 64-bit integer image atomics
Co-authored-by: shadowbeat070 <70843316+shadowbeat070@users.noreply.github.com>
2026-10-05 04:12:06 +04:00
nmzik de9c15fa79 shader: encode SNORM and scaled formatted buffer stores
Co-authored-by: shadowbeat070 <70843316+shadowbeat070@users.noreply.github.com>
2026-10-05 04:11:48 +04:00
nmzik e85279ea7b shader: correct DS float min/max operands and special values
Co-authored-by: shadowbeat070 <70843316+shadowbeat070@users.noreply.github.com>
2026-10-05 04:11:48 +04:00
nmzik d8be245c22 shader: separate legacy FP32 MAD rounding from fused FMA
Co-authored-by: shadowbeat070 <70843316+shadowbeat070@users.noreply.github.com>
2026-10-05 04:11:48 +04:00
Çağatay Güçlü bbb98bd490 hle: add BluetoothHid, DeviceService and Usbd stubs (#1031) 2026-10-05 03:04:41 +04:00
nmzik f96a14a0ab font: fix glyph metrics and raster sizes
Co-authored-by: Çağatay Güçlü <33038942+defektu@users.noreply.github.com>
2026-10-05 02:24:51 +04:00
nmzik c753efdde7 font: add scaled kerning
Co-authored-by: Çağatay Güçlü <33038942+defektu@users.noreply.github.com>
2026-10-05 02:24:51 +04:00
nmzik 8e46a3ccfa gpu: add packed unsigned-scaled vertex formats
Co-authored-by: Çağatay Güçlü <33038942+defektu@users.noreply.github.com>
2026-10-05 02:24:51 +04:00
Çağatay Güçlü b27b89f513 shader: fix VOP2 DPP8 decoding 2026-10-05 02:24:51 +04:00
nmzik e56899902b tests: use a valid image descriptor for mixed samplers 2026-10-05 02:24:51 +04:00
nmzik 0885f43a6a gpu: keep 2D and 3D texture aliases separate
Co-authored-by: Çağatay Güçlü <33038942+defektu@users.noreply.github.com>
2026-10-05 02:24:51 +04:00
Çağatay Güçlü a98a39c575 gpu: accept partially resident depth flags 2026-10-05 02:24:51 +04:00
nmzik 94e7d239dd gpu: fix zero-source alpha blending on swizzled targets
Co-authored-by: Çağatay Güçlü <33038942+defektu@users.noreply.github.com>
2026-10-05 02:24:51 +04:00
nmzik 8274e517b2 shader: add FP64 min, max and rounding
Co-authored-by: Çağatay Güçlü <33038942+defektu@users.noreply.github.com>
2026-10-05 02:24:51 +04:00
nmzik 96011cc5c9 gpu: share pipelines when color and alpha blend equations match 2026-10-05 02:24:51 +04:00
nmzik f7bd0b436a tests: update shared-memory binding expectations 2026-10-05 02:24:51 +04:00
nmzik b7d3c572c1 shader: clear unused sampler bits after constant folding
Co-authored-by: Çağatay Güçlü <33038942+defektu@users.noreply.github.com>
2026-10-05 02:24:51 +04:00
nmzik b0bbaef1eb gpu: store large compute shared memory in device buffers 2026-10-05 02:24:51 +04:00
nmzik 0ee8800905 shader: read image descriptors indexed by workgroup
Co-authored-by: Çağatay Güçlü <33038942+defektu@users.noreply.github.com>
2026-10-05 02:24:51 +04:00
nmzik 0bef3fc0d3 gpu: fix separate alpha blending on swizzled render targets
Co-authored-by: Çağatay Güçlü <33038942+defektu@users.noreply.github.com>
2026-10-05 02:24:51 +04:00
Çağatay Güçlü 45fab265d5 gpu: draw polygons as triangle fans 2026-10-05 02:24:51 +04:00
Çağatay Güçlü a2f851788f gpu: create texture views before rebinding overlapping images 2026-10-05 02:24:51 +04:00
nmzik 5940e623d5 gpu: fix 10-11-11 render-target storage
Co-authored-by: Çağatay Güçlü <33038942+defektu@users.noreply.github.com>
2026-10-05 02:24:51 +04:00
nmzik 07c84876a1 shader: fix constant types in converted image gathers 2026-10-05 02:24:51 +04:00
nmzik 96c067d0fb shader: fix filtering for scaled 8-bit textures
Co-authored-by: Çağatay Güçlü <33038942+defektu@users.noreply.github.com>
2026-10-05 02:24:51 +04:00
Çağatay Güçlü deb45a8bb2 kernel: use the AMPR filter for APR completion events 2026-10-05 02:24:51 +04:00
nmzik fdac55a5ef loader: load libc automatically at startup 2026-10-05 02:24:51 +04:00
Pyxellator 719e02574a launcher: Raise DualSense speaker volume range for SpeakerFX (#1043)
controller: restore speaker midpoint and raise volume ceiling
2026-10-04 19:48:25 +04:00
Arthur Alves c885da0a3f haptics: recognize 'Wireless Controller' audio endpoint on Linux (#1046)
On Linux (PipeWire / ALSA), the 4-channel USB audio playback device for
the DualSense controller is named 'Wireless Controller' based on Sony's
USB product descriptor string. Previously, FindDevice() only matched
names containing 'DualSense', causing quad-channel endpoint discovery to
fail on Linux systems.

Add 'Wireless Controller' to the allowed endpoint names when 4 channels
are present, and add a test case verifying discovery under this name.
2026-10-04 19:44:55 +04:00
nmzik 2984c41235 docs: show UFC 6 in README screenshots 2026-10-04 18:39:34 +04:00
nmzik 9313a0886f launcher: fix zar selection 2026-10-04 18:39:34 +04:00
nmzik 39248a1f87 shader: emit per-vertex mesh clip and cull distances
Co-authored-by: Senaxx <michelbeld@gmail.com>
Co-authored-by: shadowbeat070 <70843316+shadowbeat070@users.noreply.github.com>
2026-10-04 18:39:34 +04:00
nmzik 98557a83b6 shader: implement RDNA2 DS masked OR through shared atomic updates
Co-authored-by: shadowbeat070 <70843316+shadowbeat070@users.noreply.github.com>
2026-10-04 18:39:34 +04:00
nmzik c3f4962715 shader: use native narrow storage for byte-aligned PS5 buffers
Co-authored-by: MehmetCambaz <mcambaz18@gmail.com>
2026-10-04 18:39:34 +04:00
nmzik 0ce84e59b6 gpu: limit buffer readback to requested dirty pages 2026-10-04 18:39:34 +04:00
nmzik efbaa17f71 shader: preserve raw EXEC and VCC bits in 64-bit scalar selects 2026-10-04 18:39:34 +04:00
nmzik 783d9f8d6b shader: read descriptor dependencies from the native raw buffer source 2026-10-04 18:39:34 +04:00
nmzik 57cf086886 shader: synchronize GPU-written descriptor dependencies through buffer cache 2026-10-04 18:39:34 +04:00
nmzik dbf66b7f4f shader: support RDNA2 BVH64 ray intersections with shared traversal 2026-10-04 18:39:34 +04:00
nmzik 33e74cab2c test: verify native vector descriptor loads in structured loops 2026-10-04 18:39:34 +04:00
nmzik 3ba0e971e9 shader: materialize exact buffer capacity through shared clean reads
Co-authored-by: shadowbeat070 <70843316+shadowbeat070@users.noreply.github.com>
2026-10-04 18:39:34 +04:00
nmzik 92ac54a493 shader: eliminate impossible relative writes with closed loop bounds
Co-authored-by: Ali Almohaya <AliAlmohaya@gmail.com>
2026-10-04 18:39:34 +04:00
nmzik 8b05b6730e shader: bind dispatch spans while keeping GPU record counts native
Co-authored-by: TheCruZ <thecruzwtf@gmail.com>
2026-10-04 18:39:34 +04:00
nmzik cd9fc6ff2d shader: keep scalar data native and preserve raw addresses 2026-10-04 18:39:34 +04:00
nmzik c17fa5b936 shader: implement RDNA2 DS forward lane permute
Co-authored-by: shadowbeat070 <70843316+shadowbeat070@users.noreply.github.com>
2026-10-04 18:39:34 +04:00
nmzik 46900d8042 memory: replace live direct mappings without exposing an inaccessible gap 2026-10-04 18:39:34 +04:00
nmzik 1f6be3d570 shader: preserve descriptor key SSA across native-resolved image uses
Co-authored-by: TheCruZ <thecruzwtf@gmail.com>
2026-10-04 18:39:34 +04:00
nmzik b183cb1011 shader: share bounded material-key scans across scalar and vector loads 2026-10-04 18:39:34 +04:00
nmzik 919c058fee tests: preserve descriptor phi rejection coverage for writable buffers 2026-10-04 18:39:34 +04:00
nmzik 5f01308b20 shader: reuse aligned indirect buffer loads for scalar DWORD reads
Co-authored-by: TheCruZ <thecruzwtf@gmail.com>
Co-authored-by: tototomate123 <rushwars201966@gmail.com>
2026-10-04 18:39:34 +04:00
nmzik e0c90acee0 shader: preserve EXEC witnesses across reconverged descriptor loops 2026-10-04 18:39:34 +04:00
nmzik 843b577880 shader: resolve bounded GPU material keys through sampled image arrays
Co-authored-by: TheCruZ <thecruzwtf@gmail.com>
2026-10-04 18:39:34 +04:00
nmzik 139b564c01 shader: fold constant bit reversal before flat stack classification
Co-authored-by: TheCruZ <thecruzwtf@gmail.com>
Co-authored-by: Ali Almohaya <AliAlmohaya@gmail.com>
2026-10-04 18:39:34 +04:00
nmzik a55a28380d shader: decode GPU-selected formatted buffer loads with native bounds
Co-authored-by: TheCruZ <thecruzwtf@gmail.com>
2026-10-04 18:39:34 +04:00
nmzik 181123ea08 tests: exercise full graphics binding preparation before scratch checks 2026-10-04 18:39:34 +04:00
nmzik 0258bd61ea shader: preserve complete clear recognition with dispatch EXEC bounds
Co-authored-by: TheCruZ <thecruzwtf@gmail.com>
Co-authored-by: Mac <me@itsmemac.com>
2026-10-04 18:39:34 +04:00
nmzik b8946fef94 shader: translate RDNA2 signed 64-bit not-equal comparisons 2026-10-04 18:39:34 +04:00
nmzik a5eeab98de tests: recognize existing PS user-data address register handlers
Co-authored-by: Matthew Hurley <171001439+theantipopau@users.noreply.github.com>
2026-10-04 18:39:34 +04:00
nmzik 7992aecb7c shader: keep native rounding consistent in mixed-precision programs
Co-authored-by: Çağatay Güçlü <33038942+defektu@users.noreply.github.com>
2026-10-04 18:39:34 +04:00
nmzik b4d32394b6 shader: keep GPU-derived scalar resource reads on the GPU
Co-authored-by: Ali Almohaya <AliAlmohaya@gmail.com>
Co-authored-by: TheCruZ <thecruzwtf@gmail.com>
2026-10-04 18:39:34 +04:00
nmzik f18679e0cd shader: mask ALIGNBYTE offsets to the two-bit selector
Co-authored-by: shadowbeat070 <70843316+shadowbeat070@users.noreply.github.com>
Co-authored-by: TheCruZ <thecruzwtf@gmail.com>
2026-10-04 18:39:34 +04:00
nmzik 284d58d1d5 shader: implement RDNA2 double-precision fractional part 2026-10-04 18:39:34 +04:00
nmzik 068d7621db graphics: preserve stencil view layers through uploads and clears 2026-10-04 18:39:34 +04:00
nmzik d890bb190c shader: decode RDNA2 bit-reverse SDWA source selectors
Co-authored-by: TheCruZ <thecruzwtf@gmail.com>
2026-10-04 18:39:34 +04:00
nmzik ec3e48cdde shader: synchronize GPU-produced direct writable descriptors
Co-authored-by: TheCruZ <thecruzwtf@gmail.com>
2026-10-04 18:39:34 +04:00
nmzik e4aca7a60b shader: initialize EXEC from requested dispatch thread extents
Co-authored-by: TheCruZ <thecruzwtf@gmail.com>
Co-authored-by: Mac <me@itsmemac.com>
2026-10-04 18:39:34 +04:00
nmzik f58014ff0e shader: preserve wave-wide vector-store completion before publication 2026-10-04 18:39:34 +04:00
nmzik 42a315f0e4 graphics: trace direct dispatches at their recording tick 2026-10-04 18:39:34 +04:00
nmzik 429d0af62b shader: bind bounded GPU-selected buffer store destinations
Co-authored-by: Ali Almohaya <AliAlmohaya@gmail.com>
2026-10-04 18:39:34 +04:00
Yossi Yadgar db17585277 docs: show per-platform build status in the README badges (#1021)
All three build badges pointed at the status of the whole build.yml
workflow, so a failure in one platform's job turned every badge red.
Point each badge at its own job through the check-runs badge with a
name filter, so each one reports only its platform.
2026-10-04 01:44:24 +04:00
nmzik 0e8ded37b9 window: ignore nonpositive resize dimensions 2026-10-03 17:54:06 +02:00
nmzik ab98fb1ff9 loader: preserve red-zone liveness across stack adjustments 2026-10-03 17:27:00 +02:00
nmzik e7f6327068 net: emulate Windows PEEK and WAITALL receives
Co-authored-by: Firas Ben Mbarek <firasbenmbarek@outlook.com>
Co-authored-by: rudy-07 <kanhaiffco2007@gmail.com>
Co-authored-by: Matthew Hurley <171001439+theantipopau@users.noreply.github.com>
Co-authored-by: usopp-sama <go4av05.pvtx@gmail.com>
Co-authored-by: wruwami <wruwami@users.noreply.github.com>
2026-10-03 17:14:41 +02:00
nmzik 19a9464b7d loader: add INSERTQ RDPID and CLWB fallbacks
Co-authored-by: nomolao2-cell <nomolao2@gmail.com>
2026-10-03 20:14:50 +04:00
Ewen trividic a4d26cf81a loader: replace SSE4a EXTRQ with native trampolines on hosts without SSE4a (#839)
loader: add native EXTRQ patches with trap fallback

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-10-03 19:40:51 +04:00
Ewen trividic b11aea803c loader: native trampoline for VRSQRTPS under --amd-cpu (#893)
loader: add AMD CPU compatibility patches

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-10-03 19:13:12 +04:00
Aryan Sharma feeced81d2 window: auto-hide the cursor over the game window (#958)
* window: auto-hide the cursor over the game window

Hide the cursor when the game window is created and whenever the mouse
has been idle for two seconds; any mouse motion, button or wheel event
shows it again. Games that draw their own cursor (e.g. Blue Prince) no
longer show the host pointer on top of it.

Only real mouse input counts as activity: synthetic touch/pen mouse
events and zero-delta motion (sent by some platforms on focus or cursor
visibility changes) are ignored. The event loop only waits with a
timeout while the cursor is visible, so it still blocks indefinitely
once the cursor is hidden. The cursor is restored on shutdown.

Uses SDL_HideCursor/SDL_ShowCursor, which SDL implements for X11,
Wayland, Cocoa and Win32 and which only affect the cursor over the
emulator window.

Closes #282

* window: make cursor auto-hide optional in CLI and launcher

Co-authored-by: Anatolii Kucheruk <anatolii.kucheruk01@gmail.com>

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
Co-authored-by: Anatolii Kucheruk <anatolii.kucheruk01@gmail.com>
2026-10-03 18:15:15 +04:00
Pyxellator 820856b301 launcher: dualsense vibration/volume setting (#973)
* pad: send DualSense speaker and haptic audio over Bluetooth

* ci: fix Opus clang-cl build and macOS memory tracker test

* docs: remove Bluetooth notes from project README

* pad: keep Bluetooth audio work off emulation timing path

* pad: smooth DualSense speaker audio on USB and Bluetooth

* tests: find available macOS guest range for page manager

* pad: keep haptic waveform when Bluetooth queue overflows

* audio: reject zero output sample frequency

* Simplify DualSense audio routing and fix Bluetooth batching

* controller: add global DualSense volume and vibration controls

* Simplify global controller settings

---------

Co-authored-by: Codex <codex@openai.com>
Co-authored-by: nmzik <Nmzik@mail.ru>
2026-10-03 18:02:59 +04:00
nmzik 45f55413e0 Keep sign-in dialogs active until user dismissal through shared system presentation 2026-10-03 17:31:16 +04:00
nmzik c3330caba2 Report NP Web API memory pool statistics for active library contexts 2026-10-03 17:31:16 +04:00
nmzik 92c22d60ef Support periodic kernel timers through shared event queue deadlines 2026-10-03 17:31:15 +04:00
nmzik a0858abe35 Implement batch AIO completion polling and deletion with per-request results 2026-10-03 17:31:15 +04:00
nmzik 5766b241c3 Implement POSIX thread stack attribute import through kernel setter 2026-10-03 17:31:15 +04:00
nmzik 7f158c656e Share sampler descriptor snapshots across native variants 2026-10-03 17:31:15 +04:00
nmzik 8b0cc79acf Preserve native slices when PS5 volume texture depth grows 2026-10-03 17:31:15 +04:00
Nawid3333 8cbee7f4b7 cmake: raise the bundled-dependency policy floor to 3.10 (#975)
CMake 4 warns "Compatibility with CMake < 3.10 will be removed" for every
fetched project that declares an older minimum. zydis and its bundled
zycore both declare cmake_minimum_required(VERSION 3.9), so each configure
prints two deprecation warnings. The existing floor of 3.5 does not lift
them past the threshold; 3.10 does.

Existing build directories keep the cached 3.5 until reconfigured with
-U CMAKE_POLICY_VERSION_MINIMUM or a fresh cache.

Tested on Windows 11, clang-cl 19.1.5, CMake 4.4.3: configure prints 0
deprecation warnings (2 with the old floor); virtual_memory_allocation_tests
builds and links zydis/xbyak; ctest guest_red_zone_patcher passes.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 17:24:03 +04:00
rocketrobot99 52c8ff18d0 Update gpu_format.cpp (#1003)
* Update gpu_format.cpp

Fix SRGB render-target formats (k8Srgb, k8_8Srgb)

Corrects render_target_bytes_per_element for SRGB formats:
- k8Srgb: 1 byte (was 0)
- k8_8Srgb: 2 bytes (was 0)

These formats appear in ChannelLayout::k8 and k8_8 render-target paths.
Incorrect RT byte sizes caused TextureCache render-target validation failures
in Lucky's Tale

* Fix narrow sRGB render-target format tests

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-10-03 16:57:59 +04:00
nmzik f53e5d2283 fix windows ci (#998)
* fix windows ci

* Fix Windows SPIR-V gather opcode narrowing conversion
2026-10-03 15:05:20 +04:00
frans bd611bfe15 Honor explicit gather LOD with shared image mip selection
Co-authored-by: YuhiAida <21134775+YuhiAida@users.noreply.github.com>
Co-authored-by: BlackCAT <52720489+psnwd@users.noreply.github.com>
Co-authored-by: shadowbeat070 <70843316+shadowbeat070@users.noreply.github.com>
Co-authored-by: Senaxx <michelbeld@gmail.com>
Co-authored-by: Mac <me@itsmemac.com>
Co-authored-by: Ali Almohaya <AliAlmohaya@gmail.com>
2026-10-03 14:19:33 +04:00
chenxiao 0bb2bdad17 Skip clean memory tracker ranges during buffer synchronization 2026-10-03 14:19:33 +04:00
nmzik 0ec3655f1c Clear single-mip color targets reused from cached mip chains 2026-10-03 14:19:33 +04:00
nmzik 190608ae20 Publish consumed color metadata without invalidating pooled images 2026-10-03 14:19:32 +04:00
nmzik ebe401d052 Preserve image contents across unrelated buffer alias writes 2026-10-03 14:19:32 +04:00
BlackCAT 0d4f993358 Keep reused BC5 textures in their own guest layout 2026-10-03 14:19:32 +04:00
BlackCAT ef4c5baf3a Implement RDNA2 64-bit image atomic maximum
Co-authored-by: shadowbeat070 <70843316+shadowbeat070@users.noreply.github.com>
2026-10-03 14:19:32 +04:00
Hamza Shakir e6cb880adb Clamp compute LDS to the device limit and ignore unopenable gamepads 2026-10-03 04:27:38 +04:00
nmzik 8fa116eeb1 Remove redundant per-dispatch checks and buffer resets 2026-10-03 04:22:39 +04:00
nmzik e317465d8a fix linux CI (#972)
* fix linux CI

* Fix indirect image initialization in materialization tests
2026-10-02 17:20:12 +04:00
nmzik 684330c9e4 Specialize shader resources in place and fuse buffer refresh work 2026-10-02 16:16:31 +04:00
nmzik f3dc5ee4a9 Collect shader interface metadata in place without copying resources 2026-10-02 16:07:16 +04:00
nmzik 2545723065 Stub NetResolverAbort import AzqoBha7js4 with success 2026-10-02 15:49:55 +04:00
nmzik 95c89229ad Remove dead shader instruction cycles with linear liveness traversal 2026-10-02 15:49:43 +04:00
nmzik 7804eef9b6 Lower finite GPU-selected image descriptors through shared indirect bindings 2026-10-02 15:37:17 +04:00
Devran Cosmo Uenal 82a2f4ad42 controller: cycle DualSense speaker volume, vibration and trigger intensity in game (#946)
* controller: cycle DualSense speaker volume, vibration and trigger intensity in game

Three new input mapping controls cycle the PS5's controller settings in
game (default keys 1, 2 and 3): speaker volume (100% -> off -> 2% -> 12%
-> 42%), vibration intensity and trigger effect intensity (strong -> off
-> weak -> medium). Each starts at full and is not saved.

Changing vibration or trigger intensity re-sends the game's last rumble
and trigger effect, so the change is felt immediately.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Clean up controller settings test captures and formatting

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: nmzik <Nmzik@mail.ru>
2026-10-02 15:11:34 +04:00
Pyxellator e1be2ead54 DualSense haptics and controller speaker sound bluethooth (#969)
* pad: send DualSense speaker and haptic audio over Bluetooth

* ci: fix Opus clang-cl build and macOS memory tracker test

* docs: remove Bluetooth notes from project README

* pad: keep Bluetooth audio work off emulation timing path

* pad: smooth DualSense speaker audio on USB and Bluetooth

* tests: find available macOS guest range for page manager

* pad: keep haptic waveform when Bluetooth queue overflows

* audio: reject zero output sample frequency

* Simplify DualSense audio routing and fix Bluetooth batching

---------

Co-authored-by: Codex <codex@openai.com>
Co-authored-by: nmzik <Nmzik@mail.ru>
2026-10-02 14:55:00 +04:00
nomolao2-cell 89792a3bca Improve Hades II compatibility (#964)
Fix Hades II startup and color clears

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-10-02 14:37:49 +04:00
nmzik 39e23ac92e Publish synchronous buffer downloads inline after ordered completion 2026-10-02 13:24:03 +04:00
nmzik a67a033ff8 Remove redundant tracking lock checks from the hot path 2026-10-02 13:24:03 +04:00
nmzik d1c99bbfb0 Consolidate instruction operand bounds checks 2026-10-02 13:24:03 +04:00
nmzik a9620f98f4 Query dirty region bits without constructing temporary snapshots 2026-10-02 13:24:03 +04:00
nmzik 28f29b8e6f Inline common IR operands and share storage with Phi pairs 2026-10-02 13:24:03 +04:00
nmzik 3353c1ff3b shader: pack the runtime evaluation index beside the IR opcode 2026-10-02 13:24:03 +04:00
Mr.Hakkuh 70a475ec8c audio: fix popping and time-stretching in output (#966)
fix audio accumulated timing drift

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-10-02 13:22:38 +04:00
Louis b3e419ff11 shader: implement 32-bit RDNA2 IMAGE_ATOMIC_CMPSWAP (#952)
* shader: implement 32-bit RDNA2 image atomic compare-and-swap

* shader: share atomic emission and correct image barriers

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-10-02 01:15:53 +04:00
nmzik 4428640b44 add one time log for BDA 2026-10-02 00:53:51 +04:00
nmzik 2b2915e271 Reuse SSA read traversal storage within each pass 2026-10-02 00:53:51 +04:00
nmzik 7101741637 Cache SPIR-V arithmetic types lazily in existing emitters 2026-10-02 00:53:51 +04:00
nmzik b86cf0a820 Reuse pipelines when inactive blend settings change 2026-10-02 00:52:49 +04:00
nmzik f29bd0fe35 Reuse whole-wave ballot and first-lane SPIR-V results 2026-10-02 00:51:15 +04:00
nmzik 64eea6b32d Reuse vertex shaders across equivalent vertex buffer layouts 2026-10-02 00:51:15 +04:00
nmzik 706eec3ca9 add tests 2026-10-02 00:51:15 +04:00
nmzik 35759e48cf shader: expose wave32 feature guards through ballot mask simplification 2026-10-02 00:51:15 +04:00
nmzik 6409be2874 shader: respect branch reachability when refreshing scalar resources 2026-10-02 00:51:15 +04:00
Senaxx 0d0b215fab shader: port 64-bit ALU and atomic opcodes 2026-10-02 00:51:15 +04:00
nmzik 11001c97f7 shader: add distinct mesh shader type 2026-10-02 00:51:15 +04:00
nmzik 337f432016 shader: execute PS5 BVH intersections and local FLAT stacks
Co-authored-by: Ali Almohaya <AliAlmohaya@gmail.com>
Co-authored-by: Mac <me@itsmemac.com>
Co-authored-by: Senaxx <michelbeld@gmail.com>
Co-authored-by: Jean-Philippe <github@meunier.jp>
2026-10-02 00:51:15 +04:00
nmzik 581dad7dd3 shader: implement RDNA2 FP64 equality comparisons
Co-authored-by: Senaxx <michelbeld@gmail.com>
Co-authored-by: Ali Almohaya <AliAlmohaya@gmail.com>
2026-10-02 00:51:15 +04:00
nmzik 64dcbe0ea1 shader: decode the combined conditional-debug branch
Co-authored-by: Mac <me@itsmemac.com>
Co-authored-by: Senaxx <michelbeld@gmail.com>
Co-authored-by: BlackCAT <52720489+psnwd@users.noreply.github.com>
2026-10-02 00:51:15 +04:00
nmzik 0ecd32299c shader: cache registered code identities instead of parsing legacy footers
Co-authored-by: Mac <me@itsmemac.com>
Co-authored-by: Senaxx <michelbeld@gmail.com>
2026-10-02 00:51:15 +04:00
nmzik c2f8e64f6d graphics: reuse texture conversion scratch buffers across uploads 2026-10-02 00:51:15 +04:00
nmzik 44ba657573 renderer: validate depth swizzles by available channels
Co-authored-by: Mac <me@itsmemac.com>
Co-authored-by: Senaxx <michelbeld@gmail.com>
Co-authored-by: Ali Almohaya <AliAlmohaya@gmail.com>
2026-10-02 00:51:15 +04:00
Aryan Sharma 44798085bd network: handle SO_NBIO on non-Windows hosts (#954)
* network: handle SO_NBIO on non-Windows hosts

Setsockopt only translated the guest SOL_SOCKET/SO_NBIO (0x1200) option
under _WIN32; other hosts rejected it with ENOPROTOOPT. FMOD Studio's Live
Update listener sets SO_NBIO, so on Linux its socket setup failed and the
Studio async manager latched FMOD_ERR_NET_CONNECT. Every blocking Studio
call then failed: loadBankFile returned FMOD_ERR_NOTREADY for all banks,
leaving the game silent and stuck on the splash screen waiting for
RuntimeManager.HaveAllBanksLoaded (PPSA28997).

Toggle O_NONBLOCK with fcntl on non-Windows hosts.

* network: map connection errors from POSIX socket calls

ConvertHostSocketError only covered a handful of errno values on
non-Windows hosts, so anything else reached the guest as EIO. With
SO_NBIO now honoured there, a nonblocking connect() that is still in
progress returned EIO instead of EINPROGRESS (and EALREADY on retry).

Map the same connection and network errors the Windows branch already
translates.

* network: share nonblocking socket error handling

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-10-01 17:54:21 +04:00
Ewen trividic b7a1fac898 input: correct gyro orientation drift with the accelerometer (#899)
* input: correct gyro orientation drift with the accelerometer

* input: simplify gyro drift correction and reset gravity on reconnect

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-09-30 22:40:53 +04:00
nmzik bc193f5272 shader: V_CMPX_LT_I16 + fix SDWA with SEXT 2026-09-30 20:49:20 +04:00
nmzik 17100ec968 shareplay: return initialized connection information 2026-09-30 19:56:25 +04:00
Senaxx 8ba2caf58a videoout: WQHD detection and VRR peg/unpeg 2026-09-30 17:45:51 +04:00
Senaxx 48b52d31b5 libs: libScePngEnc on stb_image_write 2026-09-30 17:06:41 +04:00
nmzik 840b9f5753 Fix unnecessary queue drains in predication and suspend points 2026-09-30 16:51:40 +04:00
Pyxellator 05057c9441 launcher: configure and preview DualSense lightbar color (#912)
launcher: configure and preview controller lightbar color

Add an optional lightbar color to launcher settings and pass it to the emulator with --controller-color. Preview changes on RGB gamepads, handle controller hotplug events, and restore the saved color when settings dialogs close. Release launcher preview handles when starting a game.

Co-authored-by: m66401970-eng <m66401970@gmail.com>
2026-09-30 00:46:44 +04:00
Aryan Sharma af4edc2865 window: explain why each GPU was rejected in device selection (#910)
* window: explain why each GPU was rejected in device selection

"Could not find suitable device" gave no hint of what was missing; the
reasons only went to the log file, which users often cannot find (#489).

Device selection now records each rejection reason and the fatal error
lists every GPU with its reasons, for example:

  Could not find suitable device:
    AMD BC-250 (RADV GFX1013): fragmentShaderBarycentric is not supported

The missing-extension check also names each missing extension instead of
stopping at the first one without saying which. Device requirements and
selection are unchanged; the log keeps the same messages.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* window: simplify GPU rejection reporting and capability checks

* window: identify storage-image format failures accurately

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: nmzik <Nmzik@mail.ru>
2026-09-30 00:08:19 +04:00
Kody Schram 9d4da48320 Linux: Strip debug symbols from launcher (#913)
* Add stripping for linux launcher build

* Fix launcher strip

* Removed garbage

* Fix launcher link option formatting

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-09-29 23:50:20 +04:00
nmzik 2650478d92 profiling: preserve emulator fault handlers when Tracy connects 2026-09-29 21:56:38 +04:00
nmzik 18a5f04d05 graphics: retain oversized readbacks through GPU completion
Co-authored-by: Mac <me@itsmemac.com>
2026-09-29 21:56:38 +04:00
nmzik da9b38af2b ampr: reuse file-read staging storage on the APR worker
Co-authored-by: Mac <me@itsmemac.com>
2026-09-29 21:56:38 +04:00
nmzik c045f08904 ampr: schedule address waits without blocking other priorities
Co-authored-by: Mac <me@itsmemac.com>
2026-09-29 21:56:38 +04:00
nmzik 5bf9218b32 ampr: keep commands in one append-ordered sequence 2026-09-29 21:56:38 +04:00
nmzik f9fd400dbb memory: validate sparse uploads against the guest address-space owner 2026-09-29 21:56:38 +04:00
nmzik 650dc1e0af graphics: upload streamed texture mips from sparse reservations 2026-09-29 21:56:15 +04:00
EmK530 59a1760427 sampler: clamp mipLodBias to not be greater than maxSamplerLodBias 2026-09-29 20:06:22 +04:00
nmzik 73615c31ff graphics: preserve logical alpha when blending reordered targets (PPSA02721)
Co-authored-by: EmK530 <admin@emk530.net>
2026-09-29 19:52:40 +04:00
nmzik 6799ecbc5b shader: add native 64-bit LDS OR with shared typed storage views 2026-09-29 19:13:33 +04:00
nmzik 35c4dca2ce shader: add V_CMPX_NLE_F16 opcode 2026-09-29 19:13:33 +04:00
nmzik 6f24b031f5 kernel: block short sleep requests instead of busy waiting 2026-09-29 16:49:09 +04:00
nmzik 0c844e4bc2 profiler: use native Tracy scopes and remove unused manual lifetime tracking 2026-09-29 13:57:32 +04:00
nmzik e57c37fa9c graphics: consume vertex semantics directly from shader metadata 2026-09-29 13:57:32 +04:00
nmzik 6d6666819a graphics: serialize pipeline cache through its renderer owner 2026-09-29 13:57:32 +04:00
nmzik 0fbeac6d3f graphics: compact shader keys and hash packed pipeline state 2026-09-29 13:57:32 +04:00
nmzik 5e4f6afc30 graphics: build color target descriptors in place 2026-09-29 13:57:32 +04:00
nmzik 37501b5a78 graphics: stream clean guest buffers without backing-store lookups 2026-09-29 13:57:32 +04:00
nmzik b43bf9f7fb graphics: store vertex attribute bindings without duplicated arrays 2026-09-29 13:57:32 +04:00
nmzik 8e42e99788 graphics: batch release labels without redundant submissions 2026-09-29 13:57:32 +04:00
João Lobo 539c0f7bf8 graphics: restore block image storage usage where the device supports it (#894) 2026-09-29 01:57:25 +04:00
GodsWill Dev 62a0222e24 tests: cover 1D-array color render targets (#377)
* tests: cover 1D-array color render targets

* tests: build shader regressions on Windows CI

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-09-29 01:48:56 +04:00
Saif Malik 6f241bef49 Fix macOS aggregate test build (#536)
* tests: add Darwin memory test support

* tests: fix x86_64 aggregate test build

* tests: verify macOS memory and shader tests

* tests: validate macOS death-test setup before fork

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-09-29 01:43:28 +04:00
Matthew Hurley 21d7e8e1f0 tests: run the saveexec mask cases in a populated subgroup (#876)
tests: run saveexec masks in a populated subgroup

Co-authored-by: Matthew Hurley <171001439+theantipopau@users.noreply.github.com>
2026-09-29 01:42:11 +04:00
Matthew Hurley 49db3ea54c tests: skip rasterization cases instead of aborting the suite on limited GPUs (#875)
tests: skip rasterization cases on limited GPUs

Co-authored-by: Matthew Hurley <171001439+theantipopau@users.noreply.github.com>
2026-09-29 01:41:37 +04:00
Aspen 4b0de1b672 Zarchive Loading (#724)
* Simplify archive loading and harden filesystem integration

* Restore directory entry name length assertion

* Keep graphics-dependent filesystem tests out of CI

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-09-29 00:06:44 +04:00
nmzik 8e61798bfd graphics: honor CPU ownership in image dirty-region queries 2026-09-28 22:17:43 +04:00
nmzik 6ee1bf9db0 graphics: trust image-local readback validity 2026-09-28 22:17:43 +04:00
nmzik 0471c9991c audio: implement AudioOut2 user capability queries 2026-09-28 22:17:43 +04:00
nmzik b10bd53dd3 audio: prevent ATRAC9 vibration configuration heap corruption 2026-09-28 22:17:43 +04:00
nmzik 4cf456fb77 graphics: retain buffer names across draw bindings 2026-09-28 22:17:43 +04:00
Devran Cosmo Uenal 22ff4693c5 audio: play pad speaker ports on the DualSense speaker (#868)
* audio: play pad speaker ports on the DualSense speaker

Route the right channel to the speaker with the audio-control values the Linux hid-playstation
driver uses without headphones, and fall back to the main output while no DualSense audio device
is active. Also stop the previous DualSense's rumble when another DualSense becomes active.

* audio: harden DualSense speaker routing and fallback

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-09-28 20:00:58 +04:00
nmzik a107d1e333 filesystem: keep unmapped guest paths out of the host namespace 2026-09-28 19:17:03 +04:00
Emil 05f92b6422 libCes CP932 fix for Windows/macOS, fix SaveDataDialog lockups (#878)
* libs: fix CP932 iconv conversion on Windows and macOS

SDL3's SDL_SYSTEM_ICONV build option defaults off on Windows and macOS,
so SDL falls back to its own bundled iconv there, which only implements
ASCII/Latin-1/UTF/UCS. SDL_iconv_open("UTF-8", "CP932") always failed as
a result, crashing games that convert Shift-JIS strings via
sceCesMbcsStrToUtf8Str (e.g. save-data dialogs).

Add a small CesIconv shim selected at compile time: Windows converts one
character at a time via the Win32 codepage-932 APIs, replicating
SDL_iconv's chunked semantics and error codes; macOS calls real POSIX
iconv directly, since libiconv is always present there and does support
CP932, unlike SDL's fallback. Linux is untouched, since SDL already
links real system iconv by default there.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* libs: fix SaveDataDialog infinite loop on save

SaveDataDialogOpen() jumped straight from SAVE_STATUS_INITIALIZED (1) to
SAVE_STATUS_FINISHED (3), skipping SAVE_STATUS_RUNNING (2) entirely. At
least one title's save-write dialog stage only accepts a FINISHED status
after observing a RUNNING poll first; without it, the title assumed the
Open() request never took effect and re-issued it forever, hanging the
save flow (this only became visible once the CP932 crash above stopped
masking it).

Open() now starts the dialog as RUNNING. UpdateStatus() advances the
state machine, reporting RUNNING once before flipping to FINISHED for
subsequent polls; GetStatus() is untouched, staying a pure peek with no
side effects, matching the real SDK's pump-vs-peek split between the two
calls.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* Add iconv linking to macOS

* Fix missing macOS iconv link for tests

* Fix CP932 edge cases and save dialog status consistency

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Co-authored-by: nmzik <Nmzik@mail.ru>
2026-09-28 18:42:22 +04:00
nmzik a892097ff0 tests: fix macOS extended-memory alias regression check (#889)
tests: use a macOS-owned address for extended memory alias checks
2026-09-28 18:33:46 +04:00
nmzik c8baa7b909 shader: derive immutable resource policy once per plan 2026-09-28 18:01:49 +04:00
nmzik 34a3eb6b58 memory: recycle automatic backing through physical ownership 2026-09-28 18:01:49 +04:00
nmzik a20b64d3e5 audio: rewind compressed sampler blocks at loop boundaries 2026-09-28 18:01:49 +04:00
nmzik 2016f8e2fe gpu: address extended guest memory without widening dense cache tables 2026-09-28 18:01:49 +04:00
nmzik c91fe80d64 memory: separate extended allocations from ordinary guest mappings 2026-09-28 18:01:49 +04:00
nmzik ab2c1c4c03 Update README screenshot to UFC 5 2026-09-28 18:01:49 +04:00
gohansharma79-svg 0a5774be7b shader: support FP64 conversions used by FighterZ (#884)
shader: support float and unsigned widening to FP64

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-09-28 17:39:31 +04:00
nmzik 0791f921f6 UFC 5 in-game (#883)
* shader: release descriptor dependencies

* shader: simplify shared-exit control flow

* shader: fix scalar memory loads

* shader: fix LDS counter bounds

* renderer: skip inactive pixel shaders

* shader: respect FP32 mode in comparisons

* renderer: fix sampler border colors

* shader: resolve descriptors from control flow

* shader: resolve descriptors before resource planning

* shader: handle scalar guards for image bounds

* shader: handle reduced guards for image loops

* shader: fix wave guards and material indices

* shader: preserve scalar buffer offset alignment and carry

* shader: prove masked loop bounds across iteration transitions

* shader: preserve source and IR before resource tracking failures

* shader: track material keys selected from active lanes

* shader: remove obsolete post-dominator analysis

* shader: follow bounds guards through control-flow joins
2026-09-28 16:03:05 +04:00
nmzik 421684e75f docs: add weekly updates and Discord links to README (#866)
* docs: link weekly updates from README

* docs: add Discord development channel

* docs: use Discord server invite link

* docs: refine weekly updates wording
2026-09-27 18:06:26 +04:00
Elija 025b39c018 Fix empty query handling in HttpUriParse (#764)
* Fix empty query handling in HttpUriParse

* Handle empty URI query consistently

* Cover empty URI query handling

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-09-27 16:07:03 +04:00
João Lobo 7c8583d204 audio: implement the AJM Opus decoder (#858)
* audio: implement the AJM Opus decoder

* Audio: simplify Opus decoding and preserve packet boundaries

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-09-27 15:53:20 +04:00
nmzik 9229c04ebf samplerCache: handle reserved sampler anisotropy ratios
Co-authored-by: EmK530 <admin@emk530.net>
Co-authored-by: Hamza Shakir <60213466+hamzashakir99@users.noreply.github.com>
2026-09-27 15:46:25 +04:00
Matthew Hurley 1b6af301b5 tests: wire dormant VOP3 lane-read check and guard new dormant tests (#840)
Tests: enable lane-read coverage and clarify layout failures

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-09-27 15:37:32 +04:00
nmzik e51f252b75 AvPlayer: preserve clip timestamps across playback loops 2026-09-27 15:23:36 +04:00
nmzik 0f1ff37f23 Graphics: materialize CMASK clears before publishing expanded metadata 2026-09-27 15:05:46 +04:00
nmzik da33a1c4a3 Graphics: respect physical tile layout when resolving depth aliases 2026-09-27 15:05:46 +04:00
nmzik f53f0ca483 Graphics: preserve rendered contents across 1D and 2D texture aliases 2026-09-27 15:05:46 +04:00
nmzik 7b6bfdec64 Graphics: share canonical padded layouts for single-sample color targets 2026-09-27 15:05:46 +04:00
nmzik a88181b897 Graphics: share texture layout for linear render-target mip chains 2026-09-27 11:10:02 +04:00
nmzik 041874f663 Graphics: resolve equivalent terminal mip views without expanding backing 2026-09-27 11:04:19 +04:00
nmzik 496432bbb4 Shader: skip identity image remapping on materialization hits 2026-09-27 10:47:18 +04:00
Pcniado bec67b7863 Fix HITMAN 3 boot, layered presentation, and socket imports (#851)
* videoout: synchronize layered flips with premultiplied composition

* shader: support unsigned FFBH subword sources

* shader: apply cube-face result scaling

* shader: prune buffer reads proven out of bounds

* net: implement send and receive exports with shared socket handling

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-09-27 02:13:30 +04:00
Devran Cosmo Uenal a22a9d9348 audio: play DualSense haptics from vibration audio ports (#843)
* audio: play DualSense haptics from vibration audio ports

Games drive the DualSense's actuators through a vibration audio port, one channel per actuator.
These ports had no device, so their samples were dropped. Over USB the DualSense is a 4-channel
audio device whose back channels feed the actuators; play the port's samples there through SDL.

The device is looked up while the port plays, so the controller can be connected at any time. The
queue keeps about the latency of the regular audio path, with the playback rate nudged by up to 3%
when the port is fed off real time.

While haptic audio plays, hold a DualSense's rumble at zero: SDL disables audio haptics whenever
rumble is non-zero.

Add pad_haptics tests for the sample conversion, device-name matching and rate correction.

* Simplify DualSense audio haptics and restore idle rumble

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-09-27 00:37:27 +04:00
nmzik 81f312638f graphics: encode packed UNorm buffer stores before writing skinning normals 2026-09-26 23:42:19 +04:00
nmzik f1f930e06c fix(launcher): use native macOS game folder picker 2026-09-26 22:14:09 +04:00
Devran Cosmo Uenal e0b682e4b2 AvPlayer: fix Crash Bandicoot 4 intro playback and green video padding (#848)
* AvPlayer: advance the shared audio-master clock after final audio frame

* AvPlayer: initialize padded NV12 planes with neutral black

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-09-26 20:39:46 +04:00
nmzik 16b83a034c Shader: execute RDNA2 FP64 shadow arithmetic and log denorm limits
Shader: disable FP64 denorm preservation controls for now
2026-09-26 15:15:35 +04:00
nmzik cf268af839 Shader: implement RDNA2 image atomic float maximum
Shader: implement RDNA2 image atomic float minimum

Co-authored-by: foufouadi <attar.foued@gmail.com>
Co-authored-by: frans <francois.att@gmail.com>
Co-authored-by: fxpw <fxpw@outlook.com>
Co-authored-by: Matthew Hurley <171001439+theantipopau@users.noreply.github.com>
2026-09-26 15:15:35 +04:00
Mehmet Cambaz fd2e15ee73 ci: run the recompiler unit tests (#447)
Build and run the CPU-only resource_tracking, scalar_provenance, resource_materialization, and shader_vertex_metadata tests on Windows, macOS, and Linux. Each test executable is excluded from the default build, so add it to the explicit CMake targets and the matching CTest selection. Leave the Vulkan-dependent shader_recompiler_compute suite for a separate CI setup.
2026-09-26 03:00:01 +04:00
Saadi 4e8d8c849d tests: add LeastRecentlyUsedCache regression tests (#671)
* launcher: keep primary update feed answer when the fallback request fails

When the primary feed is reachable but its tag differs from the build tag,
the result was discarded and the GitHub API fallback was consulted. If the
fallback request failed (api.github.com rate-limits unauthenticated
requests), the launcher reported an error even though the primary feed had
already returned a usable update answer with a working release URL. Keep
the primary feed answer and show it if the fallback fails.

* emulator: validate numeric CLI arguments

--screen-width, --screen-height, --gpu, and --vblank-frequency were parsed
with Common::ToInt32/ToInt64, which ignores std::from_chars errors and
returns 0, so values like "--screen-width abc" or "--gpu xyz" were
silently accepted: zero screen size, or GPU 0 selected instead of auto
(-1). Reject invalid values with an error message like the other options,
using from_chars-based helpers (ParseUint32/ParseInt32); reject zero
screen dimensions.

* tests: add LeastRecentlyUsedCache regression tests

Cover the LRU cache walk order, tick filtering in ForEachItemBelow,
early-exit boolean callbacks, Touch reordering and same-tick skips,
Free, and freed-id reuse by later inserts. Modeled on BitArrayTests.

* tests: use a tick cutoff that detects a stale newest-item tick

Collect(cache, 35) also visits c when Touch(c, 35) failed to update
its tick (30 <= 35). Use a cutoff of 30 and expect only b.

* Run LRU cache tests in CI

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-09-26 02:42:31 +04:00
Matthew Hurley 1e438136fa Build save_data_memory_tests from the kyty_tests aggregate (#798)
Build save_data_memory_tests with kyty_tests

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-09-26 02:39:20 +04:00
Emil 313b60e922 Capture PCM at set time when multiple AudioOut2 ports share a buffer (#826)
* capture PCM at set time when ports share a buffer

* Snapshot size limit and open device check

* Fall back to PCM pointer on stale snapshot

* audio: own AudioOut2 PCM at attribute set time

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-09-26 02:19:49 +04:00
Hamza Shakir cda236dbb3 Shader recompiler: accept V_NOT_B32 SDWA partial dst with any source; allow 64 buffers
SDWA source extraction and destination insertion are independent. Cover the reported word1-to-word0 preserve form and byte-source partial destinations in compute tests. Verify 64 distinct compute buffers survive resource tracking and binding layout, and remove the obsolete CFG rejection.

(cherry picked from commit 9e74df7dc0)
2026-09-26 01:58:55 +04:00
Henrique Reis Neves 1216fa36cf docs: fix stale README notes, document building without Qt (#812)
* docs: fix stale README notes, document building without Qt

- Use the current issue template name, Game Emulation Status Report
  (renamed in 027433f).
- Raise the documented Windows CMake minimum from 3.12 to 3.22.1, which
  the bundled SPIRV-Tools requires.
- Note that -DKYTY_BUILD_LAUNCHER=OFF builds kyty_emulator and the
  regression tests without Qt (#193).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* docs: add Qt-free Linux build commands

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: nmzik <Nmzik@mail.ru>
2026-09-26 01:50:06 +04:00
nmzik 497166009c loader: unlink exact module imports before releasing their mapping 2026-09-25 21:15:41 +04:00
nmzik 0fb3ac5605 kernel: retain modules until their final explicit unload 2026-09-25 21:15:41 +04:00
nmzik e056d55dd5 loader: consolidate eager symbol resolution and remove dead PLT machinery 2026-09-25 21:15:41 +04:00
nmzik 1371219f5c loader: preserve resolved relocations across dynamic loads 2026-09-25 21:15:41 +04:00
nmzik cf423df624 shader: remove per-draw vertex diagnostic atomics 2026-09-25 21:15:41 +04:00
nmzik 5ce4f08364 audio: improve NGS2 stream and ATRAC9 playback 2026-09-25 18:26:08 +04:00
nmzik 7e1c2d1532 avplayer: auto-start playback without an event callback 2026-09-25 16:39:54 +04:00
nmzik 0ec43a8d3d graphics: name Vulkan images and views only on creation 2026-09-25 16:15:05 +04:00
nmzik bfdbba3aa4 graphics: share EOP clock and immediate write handling
Co-authored-by: Mac <me@itsmemac.com>
2026-09-25 16:14:40 +04:00
Devran Cosmo Uenal f7ae6e0a83 audio: support NGS2 PCM16 samplers and rear low-pass filters (#825)
* audio: support standard NGS2 PCM16 sampler playback

Extend the existing fixed-point PCM path to standard samplers, loops, and progress reporting. Apply voice events immediately and honor callback interruption during source advancement.

Reuse upstream rate and pitch handling. Add regression coverage for streaming, routing, callbacks, loops, and custom sampler controls; ngs2_sampler passes.

* audio: apply NGS2 rear low-pass filters

Handle rear low-pass FCQ controls at the output sample rate with per-channel history and channel masks. Preserve filter tails through streaming gaps and use the standard pi constant for coefficients.

Add regression coverage for frequency response, control layout, channel isolation, and starvation/refill continuity. Emulator build and both audio test suites pass.

* Preserve resampling phase for accepting voices

Only reset voice.sample_phase when there are no blocks and the voice does not accept blocks (change in src/libs/ngs2.cpp). Add TestResamplingPhaseAfterStarvation to tests to ensure sampler and custom sampler retain resampling phase and pending source advancement after starvation, and that SetupSampler still resets the phase. This prevents resampling phase loss during starvation/refill across sample rates.

* audio: correct sampler controls, lifecycle, and filter tails

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-09-25 15:44:58 +04:00
nmzik 3585cd8f03 shader: simplify translator dispatch to void handlers 2026-09-25 14:27:09 +04:00
nmzik ff54608569 shader: add V_CMPX_O_F32 opcode 2026-09-25 14:27:09 +04:00
nmzik 6bb68a3fd9 shader: stop repeated CFG merge gateway splitting 2026-09-25 14:27:09 +04:00
nmzik 93185953f1 shader: fuse image specialization setup with materialization 2026-09-25 14:27:09 +04:00
6d4m 7855c980cb audio: keep blocking AudioOut writes on an even cadence (#822)
* audio: keep blocking AudioOut writes on an even cadence

The blocking queue check only enforced a minimum cushion, so the guest
could queue a burst of buffers and then be blocked for the whole cushion.
Measured on PPSA03647, intervals between guest writes alternated between
0 ms and ~44 ms instead of one 5.33 ms buffer period, while the average
rate stayed correct at 48000 frames/s. Mixers that run on a timer cannot
track that cadence and the music turns slow and warbling.

Keep the cushion as-is, but also hold writes to the buffer period, and
skip that wait when the stream is running low so it cannot underrun.

Intervals become ~5.4 ms with microsecond-level deviation and the menu
music plays correctly.

* audio: reuse output clock after SDL queue priming

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-09-25 12:33:01 +04:00
Matthew Hurley 5a705dd15f shader: support V_CMPX_EQ_U16 (#816)
* shader: support V_CMPX_EQ_U16

Decode gfx11 VOPC 0xba and lower it as an unsigned 16-bit equality
compare with CMPX EXEC-mask semantics.

🤖 Generated with Codebuff 🤖
Co-Authored-By: Codebuff <noreply@codebuff.com>

* shader: correct CMPX EQ U16 runtime expectations

Remove the added CFG tests and correct two EXEC expectations in the compute regression case.

---------

Co-authored-by: Matthew Hurley <171001439+theantipopau@users.noreply.github.com>
Co-authored-by: Codebuff <noreply@codebuff.com>
Co-authored-by: nmzik <Nmzik@mail.ru>
2026-09-25 02:27:44 +04:00
nmzik e73324c2e0 Fix Linux fiber stack overflow with Clang 18 (#813)
Keep function-name formatting off small fiber stacks
2026-09-25 02:08:35 +04:00
Mac a20fb7f9f8 agc: trace per-frame packet parameters only with graphics debug dump
The per-frame ACB submit, indirect dispatch, reset-queue and patch-address
parameter dumps, and the flip-pending poll, are logged only with the graphics
debug dump, the way the DCB submit path already is. Otherwise they were about
7.5 MB of log a minute in the Spider-Man world.
2026-09-25 00:03:08 +04:00
nmzik 1cc0ac7ed8 ajm: share control handling to fully reset gapless decoders
Co-authored-by: Mac <me@itsmemac.com>
2026-09-25 00:01:51 +04:00
nmzik 83628a436e audio: fix NGS2 playback 2026-09-24 22:34:55 +04:00
nmzik 2165c710c3 audio: share block completion 2026-09-24 22:34:55 +04:00
Saadi b9a0bd2791 loader: wrap elapsed time in Timer::GetTime (#679)
loader: format elapsed log timestamps beyond 24 hours

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-09-24 22:02:19 +04:00
6d4m 96874909ab cmake: pass -Map as discrete link option on non-clang-cl builds (#806)
LINK_FLAGS is a space-delimited string, so when the build path contains
spaces the linker map option is split into bogus arguments and the final
link fails:

  clang++: error: no such file or directory:
  'pro/KytyPS5/_Build/linux/kyty_emulator_clang_lld.map'

Move -Wl,-Map=<path> out of LINK_FLAGS into target_link_options, which
CMake passes to the linker as a single argument. This completes #26 for
the WIN32 OR LINUX branch (clang/gcc builds); the clang-cl branch was
already converted there.
2026-09-24 21:23:13 +04:00
Romain Hedouin d646fd92d1 graphics: hoist loop-invariant checks out of draw/attrib hot paths (#807)
* graphics: hoist loop-invariant checks out of draw/attrib hot paths

DrawIndirectMulti recomputed the index_type_and_size switch on every
sub-draw of a multi-draw-indirect call, and ShaderApplyAttribSemantics
re-checked the debug-dump config flag on every vertex attribute. Both
values are invariant across their respective loops, so compute them
once before iterating instead.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* graphics: cache vertex buffer descriptor size in AcquireVertexBuffers

VertexBufferDescriptorSize was computed twice per vertex-buffer slot
on every draw call: once while collecting guest ranges, and again
while rebuilding slot bindings. Both calls use identical inputs, so
cache the first pass's result and reuse it in the second.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-24 21:02:23 +04:00
nmzik d72a79af2d graphics: skip compute dispatches with BVH instructions
Co-authored-by: Mac <me@itsmemac.com>
2026-09-24 20:46:04 +04:00
nmzik dc9280d75d shader: add GLC/DLC buffer cache policy support
Co-authored-by: Mac <me@itsmemac.com>
2026-09-24 20:46:04 +04:00
nmzik 6a9ae4ae43 shader: add SDWA support for V_MAX_I32 2026-09-24 20:46:04 +04:00
nmzik 392f39e2f6 shader: support indirect BUFFER_LOAD_DWORDX3 2026-09-24 20:46:04 +04:00
nmzik cce0cd950c videoout: add RGB10A2 PQ buffer support
Co-authored-by: Mac <me@itsmemac.com>
2026-09-24 20:46:04 +04:00
nmzik e43c242683 shader: add S_MEMREALTIME opcode
Co-authored-by: Maxime Allanic <maxime@allanic.me>
Co-authored-by: Mac <me@itsmemac.com>
2026-09-24 20:46:04 +04:00
nmzik 732057b072 videoout: fix VRR status import signature
Co-authored-by: Mac <me@itsmemac.com>
2026-09-24 20:46:04 +04:00
nmzik 2aaf0c9ba3 graphics: clamp raster depth after polygon offset
Enable native Vulkan depth clamping independently of guest depth clipping
2026-09-24 14:09:02 +04:00
nmzik db7745ef41 update README 2026-09-24 12:30:27 +04:00
nmzik 02578f3c6b docs: update screenshots 2026-09-24 12:18:55 +04:00
Douglas Soares Silva fcf0f3b67e shader: fold the lane test after a pixel shader's entry s_wqm (#801)
Preserve live lane predicates through RDNA2 whole-quad expansion

Keep the source-live predicate when WQM expands a scalar mask, so entry masks remain known live without an instruction pre-scan. Preserve scalar mask values, SCC, half writes, and raw-source behavior.

Cover entry pixel masks, cross-half copies, and scalar/high-word sources with existing shader regression suites.

Co-authored-by: nmzik <Nmzik@mail.ru>
Co-authored-by: Douglas <douglasproducoes21@gmail.com>
2026-09-24 12:02:19 +04:00
nmzik 84d015120c Remove duplicate image scratch setup from push constant test 2026-09-24 11:13:33 +04:00
nmzik a6248c7c7c Convert formatted half-float buffer stores from F32
Co-authored-by: TarkusR <90155059+TarkusR@users.noreply.github.com>
2026-09-24 11:13:33 +04:00
nmzik 3bd5de646d Reuse prepared shader bindings across draws and dispatches 2026-09-24 11:13:33 +04:00
nmzik 0382d0ca58 Publish reserved guest mappings atomically after backing commit 2026-09-24 11:13:33 +04:00
nmzik a670dc84b3 Test RDNA2 wave32 ReadLane material key selection 2026-09-24 11:13:33 +04:00
nmzik 963a0817dc Bound uniformized image keys by guarded material mask
Co-authored-by: TarkusR <90155059+TarkusR@users.noreply.github.com>
2026-09-24 11:13:33 +04:00
nmzik 1617ee77e5 Share CFG reachability for descriptor bounds analysis 2026-09-24 11:13:33 +04:00
nmzik 66cc2fe26d Track depth and stencil attachment feedback across graphics stages
Co-authored-by: TarkusR <90155059+TarkusR@users.noreply.github.com>
2026-09-24 11:13:33 +04:00
nmzik 51c34d1a24 Test zero scalar shift folding on RDNA2 compute shader 2026-09-24 11:13:33 +04:00
nmzik 3b89e36d1e Track bounded indirect image tables from signed shader loops
Co-authored-by: TarkusR <90155059+TarkusR@users.noreply.github.com>
2026-09-24 11:13:33 +04:00
João Lobo 3dc3fd0197 shader: implement DS_INC_U32 and DS_DEC_U32 (#790) 2026-09-24 00:45:12 +04:00
Deniz ŞAHİN fc86509aac shader: support DS_WRITE_B8_D16_HI (#794)
Decode GFX10 DS opcode 0xa0 as DS_WRITE_B8_D16_HI (next to
DS_WRITE_B16_D16_HI at 0xa1) and lower it through the existing 8-bit
shared-memory write. The stored byte is bits 23:16 of the data VGPR,
selected with SDWA BYTE_2 on src1.

Add captured-instruction decode coverage (from GTA V, PPSA04264) and a
runtime regression that writes one byte of a distinctive source value
into a pre-filled LDS dword.
2026-09-24 00:44:39 +04:00
nmzik 569ec04d1a Fix save metadata and timestamps
Co-authored-by: Ali Almohaya <AliAlmohaya@gmail.com>
Co-authored-by: CheesyPoofs346 <jjs777406@gmail.com>
2026-09-23 22:50:51 +04:00
nmzik 7d7267cc56 Translate NGG mesh prolog with guest wave32 width 2026-09-23 22:50:51 +04:00
nmzik 2aa0a64f63 materialize compressed video-out DCC clears before flip
PPSA27624
2026-09-23 22:50:51 +04:00
nmzik fc04db7596 NGS2: preserve ATRAC9 config word byte order 2026-09-23 22:50:51 +04:00
nmzik 1275d65bb3 Audio: split ACM, Audio3D, and NGS2 implementations 2026-09-23 22:50:51 +04:00
nmzik 3742ad9980 NGS2: warn and skip unsupported custom audio modules 2026-09-23 22:50:51 +04:00
nmzik c437de9721 Presenter: avoid lock 2026-09-23 22:50:51 +04:00
Daniil Shushakov ba579088d7 loader: refresh imports after dynamic module loads (#511)
#307: loader: refresh imports after dynamic module loads
2026-09-23 21:04:10 +04:00
Fayaz Shaikh 019929587c Allow resizing by default and recreate swapchain on resize (#763)
* Add `stretch to window` support

* Address comment

* Allow window resizing by default and recreate swapchain on resize

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-09-23 17:49:38 +04:00
nmzik f68c77d785 SDL3 update (#787)
* Update to SDL3

* Add XTest development dependency for SDL3

* Preserve native entry points with SDL3

* Document SDL3 XTest dependency
2026-09-23 17:22:15 +04:00
Louis b5ba482fc2 Implement missing kernel and startup library imports (#772)
* Implement missing kernel and startup library imports

* Remove chmod and test changes; guard vectored I/O size

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-09-23 15:57:42 +04:00
nmzik 9860c2bbf8 Associate stencil when depth is acquired
Co-authored-by: Daniil Shushakov <4shushakov@gmail.com>
2026-09-23 15:41:02 +04:00
nmzik ee3749d9b6 Cover 64 MiB download ring staging 2026-09-23 15:41:02 +04:00
nmzik 3fad77fd8b Increase GPU readback staging to 64 MiB 2026-09-23 15:41:02 +04:00
nmzik d6b2abe26f Remove redundant command buffer checks 2026-09-23 15:41:02 +04:00
nmzik 79530b4c5e Read indirect dispatch counts from GPU buffers
Co-authored-by: Mac <me@itsmemac.com>
2026-09-23 15:41:02 +04:00
nmzik d8a4412498 Refresh stencil backing through the depth image
Co-authored-by: Daniil Shushakov <4shushakov@gmail.com>
2026-09-23 15:41:02 +04:00
nmzik 5ed5fdd36e Preserve resource level bits in texture descriptors 2026-09-23 15:41:02 +04:00
nmzik ef83ba65ad Validate texture descriptor fields 2026-09-23 15:41:02 +04:00
nmzik d30dca78be Read image descriptors in one bounded span 2026-09-23 15:41:02 +04:00
nmzik 66f1a82365 Resolve scalar image tables during resource planning 2026-09-23 15:41:02 +04:00
nmzik eb8a5504a3 Emit coordinates for each indirect image candidate
Co-authored-by: Techx3 <56268269+Techx3@users.noreply.github.com>
2026-09-23 15:41:02 +04:00
nmzik 8a5e5c5476 Fold buffer address identities and remove empty predicates 2026-09-23 15:41:02 +04:00
nmzik 03c55e5712 Keep shader user data inline for cached programs 2026-09-23 15:41:02 +04:00
nmzik 5d1ad31c49 Resolve guarded descriptor Phis at their use edge
Co-authored-by: Techx3 <56268269+Techx3@users.noreply.github.com>
Co-authored-by: GodsWill <GodsWill@users.noreply.github.com>
2026-09-23 15:41:02 +04:00
nmzik 13fcb3a133 Refresh cached resources in one SRT walk 2026-09-23 15:41:02 +04:00
nmzik d6dac92da1 Reuse scalar evaluation storage
Co-authored-by: MehmetCambaz <mcambaz18@gmail.com>
Co-authored-by: Leclowndu93150 <xdr.a123454321@gmail.com>
2026-09-23 15:41:02 +04:00
nmzik 90471836f7 Resolve storage mip views before layout lookup 2026-09-23 15:34:44 +04:00
nmzik 8252caee04 Quiet draw and audio logs 2026-09-23 15:32:30 +04:00
crevant 8b095caefe perf(files): move directory-entry names instead of copying them (#758) 2026-09-22 12:26:06 +04:00
nmzik 8dc9b9d532 Persist save allocations for search and mount capacity queries 2026-09-22 11:38:50 +04:00
nmzik e40438f95e Decode ATRAC9 streams after complete RIFF headers
Co-authored-by: Techx3 <56268269+Techx3@users.noreply.github.com>
Co-authored-by: Ali Almohaya <17254073+Almo7aya@users.noreply.github.com>
2026-09-22 11:38:50 +04:00
nmzik a6a56c8a44 Remove obsolete partial indirect draw warnings 2026-09-22 11:38:50 +04:00
nmzik 4b074cf9e9 Avoid heap allocation when compacting materialized shader images 2026-09-22 11:38:50 +04:00
nmzik 7c9e18e73b Ignore inactive metadata address bits in sampled depth descriptors
Co-authored-by: Ali Almohaya <17254073+Almo7aya@users.noreply.github.com>
2026-09-22 11:38:50 +04:00
nmzik d2df2cad74 Resolve draw-uniform image descriptors through scalar buffer chains 2026-09-22 11:38:50 +04:00
nmzik b2a80a3a96 Resolve GPU-selected raw buffer descriptors through shared RDNA2 addressing
Co-authored-by: Bipin <87369440+bipinkrish@users.noreply.github.com>
2026-09-22 11:38:50 +04:00
nmzik cfb8f7b246 Decode unsigned byte sources for SDWA half-float conversion 2026-09-22 11:11:36 +04:00
nmzik d792dfa885 Reject AvPlayer pause and seek before playback 2026-09-22 11:11:36 +04:00
nmzik 12ff571609 Preserve AvPlayer sync mode before source creation 2026-09-22 11:11:36 +04:00
nmzik d3c182f385 Centralize attachment sample validation before acquisition 2026-09-22 11:11:36 +04:00
nmzik bf4dcdce52 Accept resolved FMASK metadata with native MSAA 2026-09-22 11:11:36 +04:00
nmzik 476204cd4b Initialize native NGG vertex launch state and wave size 2026-09-22 11:11:36 +04:00
nmzik f9e56ef8a0 Scope native barriers to shaders with shared execution 2026-09-22 11:11:36 +04:00
nmzik 61761b65f2 Honor PS5 title output-resolution detection permission 2026-09-22 11:11:36 +04:00
nmzik ba55ba5dc5 Allow storage access to PS5 cubemap faces 2026-09-21 00:49:54 +04:00
nmzik c997cdb837 Skip zero-valued indirect CX 0x24a 2026-09-21 00:49:54 +04:00
Kody Schram fe4f9423e3 Significantly Reduce Linux Release Size (#738)
Added symbol stripping for linux build, drops fs from 120 mb to 20mb
2026-09-20 21:26:24 +04:00
nmzik 81af130147 Avoid game list rescans on settings changes/Remove Space pause shortcut 2026-09-20 21:07:36 +04:00
Saadi ada0514084 launcher: add a game list refresh action (#683)
* launcher: add a game list refresh action

Dropping new games into an already-configured game folder was only
picked up after restarting the launcher or re-saving the global
settings dialog. Add a refresh toolbar button, an F5 shortcut, and a
"Refresh game list" context-menu entry, all triggering a rescan of the
game folders.

* launcher: do not rescan the game list while a game is running

Clearing cfgs_list destroys the running ConfigurationItem: the running
state is lost and the replacement items allow editing or deleting a
game whose process is still active. Skip the rescan while any item is
running (CodeRabbit review finding for the refresh action).

* launcher: preserve game state when refreshing the list

Share one refresh action across the toolbar, keyboard shortcut, and context menu. Retain running items during rescans, update their settings for the next launch, and preserve selection, filtering, and sort order.

Commit active inline editors before rebuilding rows to avoid losing comments or accessing destroyed configuration data. Tie editor callbacks to item lifetime and guard the context-menu item reference.

Validation: launcher build and startup check passed; 32 Qt interaction checks passed.

* launcher: remove refresh from the game context menu

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-09-20 20:44:40 +04:00
Ilyas d7da244475 Add automatic sccache/ccache detection to CMake and remove deprecated Ninja setup action (#734)
* remove outdated ninja setup action

* Remove deprecated ninja setup action

The seanmiddleditch/gha-setup-ninja action has been archived by its
maintainer, who explicitly states that Ninja is now pre-installed on
all GitHub-hosted runners. This removes the action from all three
build jobs (Windows, macOS, Linux) and removes ninja from the package
install lists on macOS and Linux.

* Add automatic ccache/sccache detection to CMakeLists.txt

Detects sccache (preferred on Windows/MSVC) or ccache at configure time
and sets CMAKE_C_COMPILER_LAUNCHER / CMAKE_CXX_COMPILER_LAUNCHER
automatically. Works for local builds without manual flags.

Priority: sccache > ccache (sccache handles MSVC PDBs better).

* Delete github-actions-version-research.md

* Respect user-specified CMAKE_C_COMPILER_LAUNCHER / CMAKE_CXX_COMPILER_LAUNCHER

Only auto-detect sccache/ccache if no launcher was explicitly provided
via -DCMAKE_C_COMPILER_LAUNCHER=... or -DCMAKE_CXX_COMPILER_LAUNCHER=...

* Preserve explicit compiler launcher settings per language

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-09-20 19:49:59 +04:00
Elija 549495575c shader: add S_BITCMP0_B64 and S_BITCMP1_B64 (#688)
* shader: add S_BITCMP0_B64 and S_BITCMP1_B64

* test: move S_BITCMP_B64 coverage to compute suite

* test: use the existing compute CTest entry for bit comparisons

* test: remove the dedicated S_BITCMP_B64 command-line selector

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-09-20 19:36:12 +04:00
Maayan080 c3cc8454b9 common: remove unused recursive file enumeration (#681)
common: don't follow reparse points in the Windows recursive file walk

SysFileFindFiles recurses into every entry carrying
FILE_ATTRIBUTE_DIRECTORY, which on Windows includes directory symlinks
and junctions. A junction pointing at one of its own ancestors makes the
walk recurse until the stack runs out.

The Linux implementation already guards against this: it uses lstat
rather than stat specifically so a symlink is never followed into a
cycle. Skip reparse-point entries on Windows for the same reason.

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-09-20 18:50:57 +04:00
Saadi b8ad1d8c4b common: return real Win32 cache flags from GetCacheAccessType (#673)
GetCacheAccessType returned the sys_file_cache_type_t enum values as
CreateFileW flags: SYS_FILE_CACHE_SEQUENTIAL_SCAN (2) became
FILE_ATTRIBUTE_HIDDEN and SYS_FILE_CACHE_AUTO (0) lost the normal
attributes, and no FILE_FLAG_SEQUENTIAL_SCAN hint was ever applied.
Return FILE_FLAG_SEQUENTIAL_SCAN / FILE_ATTRIBUTE_NORMAL instead,
mirroring the POSIX fadvise handling on Linux.
2026-09-20 18:47:25 +04:00
Elija cfb110e0aa shader: allow partial SDWA destinations for V_NOT_B32 (#684) 2026-09-20 18:21:40 +04:00
nmzik e930657bf6 tesselation support in GUI 2026-09-20 17:16:19 +04:00
nmzik 0ad9149c90 Fix three-vertex rectangle rendering 2026-09-20 17:16:19 +04:00
nmzik 25f2699523 Fix video aspect ratio 2026-09-20 17:16:19 +04:00
nmzik a849f25376 Make tessellation optional 2026-09-20 17:16:19 +04:00
nmzik fa51da4d76 Fix AvPlayer end-of-file handling 2026-09-20 17:16:19 +04:00
nmzik 6b79b7a003 Fix AvPlayer startup state 2026-09-20 17:16:19 +04:00
nmzik 102a10f0fe Fix signed sampler comparisons 2026-09-20 17:16:19 +04:00
nmzik 8d66c4ef6d user service: return logged-out error for unavailable user names 2026-09-20 14:03:08 +04:00
nmzik 8cecaf4e30 Merge PR #716: Fix Unicode paths on Windows
Preserve native Windows paths for filesystem operations, command-line options,
and game icons. Complete Unicode handling in recursive file listings and file
logging, restore unmounting by host directory, and extend regression coverage.

Original implementation by Augusto Domingos (@AghastyGD); retain all five of
his PR commits and include the reviewed follow-up fixes.

Closes #714

Co-authored-by: Augusto Domingos <augustodomingosvasco@gmail.com>
2026-09-20 02:14:22 +04:00
nmzik 82b2711cdf audio: play ATRAC9 sampler blocks 2026-09-20 01:47:43 +04:00
nmzik 35a275e97d avplayer: signal when playback ends 2026-09-20 01:47:43 +04:00
nmzik 303a0203b6 audio: play NGS2 PCM buffers 2026-09-20 01:47:43 +04:00
Çağatay Güçlü cfbaee07f0 Persist SaveDataMemory2 save data to disk (fixes Astro Bot progress not saving) (#659)
* Persist save-data memory across restarts

* Fix SetSaveDataMemory2 data loss, split saves per user, add atomic writes everywhere

- SaveDataSetSaveDataMemory2 treated data_num=0 as "no entries" even when
  a valid data pointer was supplied. Astro Bot calls this with data_num=0
  meaning "one entry, at data[0]" (an implicit-count convention), so every
  real save write from it was silently dropped as a no-op. Default
  data_num to 1 when data is non-null, matching that convention.
- SaveDataSetupSaveDataMemory2/Get/SetSaveDataMemory2 rejected any call
  that included a non-null icon pointer. Icon persistence isn't
  implemented, but titles are allowed to pass one anyway; rejecting the
  whole call over it made every title that does so fail outright. Ignore
  icon instead of rejecting.
- SaveDataMount3/SaveDataTransferringMount/SaveDataDelete built their
  save-data path from title+dir_name only, dropping the user_id PS5
  local users are keyed by (unlike the newer SetSaveDataMemory2 layout,
  which already nests by user_id). Nest these under user_id too so saves
  from different local users can no longer collide. No migration for the
  old flat layout - the project is still pre-release/experimental.
- Classic SaveDataMount3-mounted titles (Blasphemous, Dead Cells, ...)
  write their save files directly through the guest's normal file I/O
  once mounted, bypassing SaveData's own write path entirely, so they
  had none of the crash-safety SetSaveDataMemory2 already had. Added the
  same protection at the file-system layer: a guest file opened under a
  /savedataN mount that recreates the file from scratch (O_CREAT and/or
  O_TRUNC) is now written to a .tmp shadow file and atomically replaces
  the real one on close, instead of being truncated in place.
- Both write paths now back up the file they're about to replace into a
  sibling "backups" folder (same filename, no added suffix) before the
  atomic replace, so a manual recovery copy of the previous save always
  survives a write - even one that "succeeds" but wasn't wanted.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* Fix save-memory compatibility and preserve existing saves

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-20 00:51:22 +04:00
Augusto Domingos fe45265fcd preserve native paths when creating directories 2026-09-19 17:53:15 +02:00
Augusto Domingos 8b294eb5b8 Add unicode path regression coverage 2026-09-19 15:48:30 +02:00
Augusto Domingos 07c9978ac6 keep game icon paths native in windows 2026-09-19 14:45:24 +02:00
Augusto Domingos b61b3f2a40 handle UTF-8 command-line paths 2026-09-19 14:12:35 +02:00
Augusto Domingos 001dfea501 Preserve native windows paths in filesystem operations 2026-09-19 13:11:55 +02:00
nmzik f100f785da libs: fill controller and broadcast status outputs 2026-09-19 05:16:16 +04:00
nmzik ba1854bbdc net: start pool IDs at 1 2026-09-19 04:59:28 +04:00
nmzik ea6aae8577 shader: V_MAD_I16 2026-09-19 04:43:48 +04:00
nmzik 5b7d3343cf shader: V_CMP_NLT_F16 2026-09-18 12:25:13 +04:00
nmzik 394e638905 shader: V_MUL_LO_U16 2026-09-18 11:21:57 +04:00
nmzik c2b7b0b58c Revert "BC7-RGBA32_UINT views (Vulkan validation)"
This reverts commit 165234b159.
2026-09-18 11:12:36 +04:00
nmzik 1d2f59dfa4 ajm: reject invalid batch storage 2026-09-18 09:11:55 +04:00
nmzik 007d7ea2eb audio: infer stereo RAW AAC layout from channel-pair packets
Co-authored-by: BlackCAT <52720489+psnwd@users.noreply.github.com>
2026-09-18 09:11:55 +04:00
nmzik 95d3d9d3ad shader: fix packed integer negation
Co-authored-by: shadowbeat070 <70843316+shadowbeat070@users.noreply.github.com>
2026-09-18 09:11:55 +04:00
nmzik bfc8cd0e0b shader: DPP8 moves
Co-authored-by: foufouadi <attar.foued@gmail.com>
Co-authored-by: fxpw <fxpw@outlook.com>
2026-09-18 09:11:55 +04:00
nmzik 165234b159 BC7-RGBA32_UINT views (Vulkan validation)
Co-authored-by: Techx3 <56268269+Techx3@users.noreply.github.com>
Co-authored-by: shadowbeat070 <70843316+shadowbeat070@users.noreply.github.com>
Co-authored-by: SueryRD <the.ai.tester2@gmail.com>
Co-authored-by: BlackCAT <52720489+psnwd@users.noreply.github.com>
2026-09-18 09:11:55 +04:00
nmzik 6493674726 shader: dual-source blending (Vulkan) 2026-09-18 09:11:55 +04:00
nmzik cbedf5707f UDP P2P sockets 2026-09-18 09:11:55 +04:00
nmzik 57c5b206ca fix network errno 2026-09-18 09:11:55 +04:00
nmzik 87b4417aca fix initial NP sign-in callback 2026-09-18 09:11:55 +04:00
nmzik 104530eafc fix Windows build (#680)
fix Windows Vulkan barrier macro
2026-09-17 21:32:54 +04:00
nmzik 6cfde37e98 avoid extra allocations 2026-09-17 20:35:36 +04:00
nmzik c5cebc1d19 remove unused helpers and the -64 suffix 2026-09-17 20:35:36 +04:00
nmzik 697b18b366 replace ByteBuffer with std::vector 2026-09-17 20:35:36 +04:00
nmzik 5b2935e36c remove the extra virtual memory layer 2026-09-17 20:35:36 +04:00
nmzik 5dc644edb4 clean up graphics helpers 2026-09-17 20:35:36 +04:00
nmzik 1211958b4e clean up runtime helpers 2026-09-17 20:35:36 +04:00
nmzik 218e7200bb clean up launcher helpers 2026-09-17 20:35:36 +04:00
nmzik 2bf78a94e0 remove string wrappers 2026-09-17 20:35:36 +04:00
nmzik cc8e02380f remove magic_enum wrappers
Co-authored-by: Saadi <cosxmos@gmail.com>
2026-09-17 20:35:36 +04:00
nmzik c66d977c1d shader: encode SNORM16 formatted stores for skinning buffers 2026-09-17 17:40:05 +04:00
nmzik 4b77686566 shader: V_CMP_NGT_F16 2026-09-17 16:56:32 +04:00
c0sxm0s a6144f794b launcher: report cheat file save failures (#669)
PatchesDialog::Save silently ignored QSaveFile failures, leaving the
status label showing the old "Loaded N cheat(s)" text so the user could
not tell that their selection was not saved. Report the failure in the
status label and the log instead.
2026-09-17 16:13:35 +04:00
Mininaut bab1c3614c libc: treat negative dynamic printf precision as omitted (#625) 2026-09-17 15:18:04 +04:00
c0sxm0s de1545e19a launcher: wire cancel->reject in C++; document glslang for Windows (#663)
uic from Qt 6.12.0 crashes (0xC0000005) on any non-empty <connections>
block in .ui files. Move the cancel_button -> reject connection from
configuration_edit_dialog.ui into configurationEditDialog.cpp, matching
how the other buttons are already connected there.

Also document the glslang (glslangValidator) requirement for Windows
builds; CMake requires it via find_program(... REQUIRED).
2026-09-17 15:13:20 +04:00
Komary ce629e0391 input: add gyroscope and motion sensor support (#634)
input: add controller motion sensor support

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-09-17 12:28:12 +04:00
BlackCAT 6c03b4aaa5 vscode: point IntelliSense at clang instead of MSVC (#564)
* vscode: point IntelliSense at clang instead of MSVC

KYTY_SYSV_ABI expands to __attribute__((sysv_abi)) with no MSVC fallback,
which is correct for a project that rejects cl.exe at configure time. Nothing
told the C/C++ extension that, so it fell back to windows-msvc-x64 and
flagged every guest-facing function in the tree with "__attribute__ is not a
type name".

Set the IntelliSense mode, compiler path and C++ standard to match the
compiler the build actually uses, and export a compile database for it to
read.

* vscode: resolve the clang toolchain through the VS developer environment

The IntelliSense settings named a specific Visual Studio install, so the
compiler and Ninja only resolved on machines with VS 18 Community under
Program Files. Let CMake Tools source the developer environment instead,
which locates the toolchain through vswhere, and drop the explicit
compilerPath so cpptools takes the compiler from compile_commands.json.

Also point C_Cpp.default.compileCommands at the build directory this
workspace actually configures, and drop CMAKE_EXPORT_COMPILE_COMMANDS
because CMake Tools already exports the database by default.
2026-09-17 11:38:40 +04:00
nmzik 0627e23e92 coderabbit: make it quieter 2026-09-17 11:26:44 +04:00
Jean-Philippe 4e6f4f99d3 loader: emulate immediate SSE4a instructions on macOS (#635)
* loader: emulate immediate SSE4a instructions on macOS

* tests: simplify macOS SSE4a test integration

Keep the Darwin target, CTest registration, and aggregate dependency in
one conditional block without a separate target list. Preserve the
standalone target when BUILD_TESTING is disabled.

Lowercase the test filename and diagnostic prefix, and drop unrelated
formatting changes from the instruction emulator.

Credit Brandon Strong's related SSE4a work in
https://github.com/KytyPS5/KytyPS5/pull/467.

Co-authored-by: Brandon Strong <brandostrong@gmail.com>

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
Co-authored-by: Brandon Strong <brandostrong@gmail.com>
2026-09-17 11:23:50 +04:00
Elija f30afc184e shader: support S_ASHR_I64 (#658)
* shader: implement S_ASHR_I64 with compute coverage

* tests: use existing compute suite for S_ASHR_I64

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-09-17 10:48:05 +04:00
Beru 228cf3fbf4 Build the launcher on Qt below 6.6 and cap the reference-clock log (#653)
* Fix launcher build on Qt versions below 6.6

QVulkanInstance::NoPortabilityDrivers is only available since Qt 6.6, so
guard its use the same way as the Apple-specific case.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Stop logging every reference-clock copy

CopyData of the clock counter runs on every GPU wait, so the handler wrote
one line per wait: a single SpongeBob boot that never reaches a frame logs
1312 of them, and the count grows with run time. Keep the first 64 lines
for diagnostics; the copy itself is unchanged.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Remove reference-clock logging comment

---------

Co-authored-by: YuhiAida <21134775+YuhiAida@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: nmzik <Nmzik@mail.ru>
2026-09-17 10:30:47 +04:00
nmzik 47957faa16 Match stencil associations by guest range and extent
PPSA30279
2026-09-17 09:01:36 +04:00
nmzik 235e24d44f Recognize null-destination SWAPPC shader handoffs
Credits:
BlackCAT (@psnwd):
https://github.com/KytyPS5/KytyPS5/pull/613
YuhiAida (@YuhiAida):
https://github.com/KytyPS5/KytyPS5/pull/655
2026-09-17 08:45:21 +04:00
nmzik e0ecffed70 Approximate explicit-LOD texture gathers at mip zero
Credits:
YuhiAida (@YuhiAida):
https://github.com/KytyPS5/KytyPS5/pull/588
https://github.com/KytyPS5/KytyPS5/pull/589
https://github.com/KytyPS5/KytyPS5/pull/655
frans (@francoisatt):
https://github.com/KytyPS5/KytyPS5/pull/590
BlackCAT (@psnwd):
https://github.com/KytyPS5/KytyPS5/pull/613
shadowbeat070 (@shadowbeat070):
https://github.com/KytyPS5/KytyPS5/pull/654
Pouare514 (@Pouare514):
https://github.com/KytyPS5/KytyPS5/pull/29
https://github.com/KytyPS5/KytyPS5/pull/32
2026-09-17 08:39:57 +04:00
nmzik fa913ec1a7 Accept EXPCLEAR acceleration on expanded depth attachments 2026-09-17 08:25:55 +04:00
nmzik 49b2eedd1c Fix command buffer capacity calculation
Credits:
YuhiAida (@YuhiAida):
https://github.com/KytyPS5/KytyPS5/pull/588
https://github.com/KytyPS5/KytyPS5/pull/589
https://github.com/KytyPS5/KytyPS5/pull/652
Crimson (@Crimson3076):
https://github.com/KytyPS5/KytyPS5/pull/598
2026-09-17 08:16:59 +04:00
nmzik 63fb822f8a Warn and continue mesh draws with primitive restart enabled 2026-09-16 22:33:19 +04:00
nmzik f38d738ee2 Honor PS5 texture minimum LOD for streamed mip chains
Fix broken ground textures in ASTRO BOT.

Related work: https://github.com/KytyPS5/KytyPS5/pull/558

Co-authored-by: Çağatay Güçlü <33038942+defektu@users.noreply.github.com>
2026-09-16 22:33:19 +04:00
nmzik eda6ba37ec Json2: new ABIs
Related work: https://github.com/KytyPS5/KytyPS5/pull/558

Co-authored-by: Çağatay Güçlü <33038942+defektu@users.noreply.github.com>
2026-09-16 22:33:19 +04:00
nmzik b594f8c834 Bind only exported color targets and preserve MRT slots
Related work: https://github.com/KytyPS5/KytyPS5/pull/558

Co-authored-by: Çağatay Güçlü <33038942+defektu@users.noreply.github.com>
2026-09-16 22:33:19 +04:00
nmzik bc45aaf604 Track uniform sampler choices across both conditional arms
Related work: https://github.com/KytyPS5/KytyPS5/pull/558

Co-authored-by: Çağatay Güçlü <33038942+defektu@users.noreply.github.com>
2026-09-16 22:33:19 +04:00
nmzik fb94a819c7 Structure early returns with shared loop continuations 2026-09-16 22:33:19 +04:00
nmzik 8589731a27 Preserve PS5 mip-tail views and GPU data during image expansion
Related work: https://github.com/KytyPS5/KytyPS5/pull/558

Co-authored-by: Çağatay Güçlü <33038942+defektu@users.noreply.github.com>
2026-09-16 22:33:19 +04:00
nmzik c1dccd7db1 Skip zero-sized compute dispatches before shader preparation 2026-09-16 22:33:19 +04:00
nmzik af3a3f4bf6 Preserve uniform conditional sampler choices in resource plans
Related work: https://github.com/KytyPS5/KytyPS5/pull/558

Co-authored-by: Çağatay Güçlü <33038942+defektu@users.noreply.github.com>
2026-09-16 22:33:19 +04:00
nmzik 349fae00d9 Emulate register-form SSE4a EXTRQ 2026-09-16 22:33:19 +04:00
Fag Fag Fag Sahur 10cae50b34 Add Nix flake and development shell (#645) 2026-09-16 22:19:41 +04:00
nmzik 5b541375a3 shader: implement S_CBRANCH_CDBGSYS opcode 2026-09-16 17:04:48 +04:00
nmzik ded6964953 Use native TLS for fiber context across thread migration 2026-09-16 11:22:05 +02:00
nmzik 9b2111dc01 Bundle FFmpeg 2026-09-16 10:13:03 +02:00
nmzik 71f52f9d90 Simplify fiber ownership and preserve small guest stacks 2026-09-16 08:53:56 +02:00
nmzik 86e5e01403 Protect Windows guest red zones when emulating VRSQRTPS 2026-09-16 06:52:36 +02:00
nmzik 77680ce9d2 Make AMD CPU patch optional 2026-09-16 09:48:50 +04:00
nmzik 32e6a433e8 Fix Json2 integer reads 2026-09-16 09:21:44 +04:00
nmzik 7c9148dd47 Support triangle fans in PS5 geometry shaders
Keep the fan center across subgroups and reuse the existing index fetch.
2026-09-16 08:42:47 +04:00
nmzik 957452d6f9 Emulate VRSQRTPS instruction 2026-09-16 08:28:36 +04:00
nmzik e6156bef05 Cache CI builds with sccache
Co-authored-by: Adrian Endlicher <godlike93@gmail.com>
2026-09-15 22:16:54 +04:00
nmzik 441367b1a1 Fix pixel shader input aliases 2026-09-15 20:46:51 +04:00
nmzik 629ae1ac05 Handle Z-pass predication and query waits 2026-09-15 20:15:39 +04:00
nmzik 0d9e95d96a Fix centroid interpolation weights
PPSA03792
2026-09-15 19:51:30 +04:00
nmzik 9cf7963f44 Use system FFmpeg for VP9 playback on Linux 2026-09-15 19:30:28 +04:00
nmzik acd7435d31 Support byte destinations in V_MOV_B32 2026-09-15 18:25:20 +04:00
nmzik 7af28c267d Map Z/C to L2/R2 2026-09-15 15:20:53 +04:00
nmzik 79120d53ec Handle chained PM4 buffers without recursion 2026-09-15 14:43:15 +04:00
nmzik 6a2987a7b2 Log the game title id 2026-09-15 14:09:24 +04:00
nmzik d1372abf46 Add launcher microphone selection and SDL AudioIn capture 2026-09-15 11:24:05 +04:00
nmzik 98b5d88d67 Implement AudioIn HQ open and close with paced silent input 2026-09-15 11:24:05 +04:00
nmzik 86414760e6 Cull zero homogeneous vertex positions before rasterization
Fix Playroom top right artifact on Nvidia by clipping zero-position vertices.
2026-09-15 11:24:05 +04:00
nmzik a1fbc41146 Preserve shared scalar loads during embedded vertex fetch replacement 2026-09-15 11:24:05 +04:00
nmzik 5702cfc935 Fix transfer-save mounts to honor the source title and missing data 2026-09-15 11:24:05 +04:00
nmzik 7b5a33f878 Fix PS5 front-face VGPR encoding to restore scene lighting 2026-09-15 07:01:10 +04:00
nmzik ea092a9472 Fix DCC clears through aliased image formats
Clear DCC images using the requested view format.
UNORM alpha 0xffff reads as NaN in a FLOAT view.
2026-09-15 07:01:10 +04:00
nmzik 18a1e0fadc Remove global condition waiter registry that deadlocks exception delivery
Co-authored-by: Bipin <bipinkrish4@gmail.com>
2026-09-14 21:34:01 +04:00
nmzik 437e69ef1b Remove extra DCC tracking 2026-09-14 20:29:20 +04:00
nmzik dd408ffd00 Resolve image aliases before buffer uploads 2026-09-14 20:29:20 +04:00
nmzik bce8924dd6 Use dynamic stencil state 2026-09-14 20:29:20 +04:00
nmzik fe26c1de17 Share SPIR-V module creation 2026-09-14 20:29:20 +04:00
nmzik 01df42a5f3 Fix DCC clears after metadata writes 2026-09-14 20:29:20 +04:00
nmzik 968cf3c03f Use the correct pixel shader wave size 2026-09-14 20:29:20 +04:00
nmzik 586cbd4a0d Fix separate stencil test and write values 2026-09-14 20:29:20 +04:00
nmzik 940e42f130 Share stencil setup for both faces 2026-09-14 20:29:20 +04:00
nmzik 3f80151a6f Respect vertex buffer sizes 2026-09-14 20:29:20 +04:00
nmzik 7e89b97daf Handle front shader allocation state 2026-09-14 20:29:20 +04:00
nmzik d63fb62367 Fix async compute completion interrupts 2026-09-14 20:29:20 +04:00
nmzik 29e9ea6344 Fix masked stencil replacements 2026-09-14 20:29:20 +04:00
nmzik 9a74ef15c3 Move stencil checks into op conversion 2026-09-14 20:29:20 +04:00
nmzik a9ae04c152 graphics: decode observed FSR setup registers
Inspired by https://github.com/KytyPS5/KytyPS5/pull/607

Co-authored-by: BlackCAT <52720489+psnwd@users.noreply.github.com>
2026-09-14 10:30:28 +04:00
nmzik 8e35e1233b hmd2: initialize reprojection and virtual headset field of view
Inspired by https://github.com/KytyPS5/KytyPS5/pull/607

Co-authored-by: BlackCAT <52720489+psnwd@users.noreply.github.com>
2026-09-14 10:30:28 +04:00
nmzik 5610976720 videoout: map buses to dense port slots before opening
Inspired by https://github.com/KytyPS5/KytyPS5/pull/607

Co-authored-by: BlackCAT <52720489+psnwd@users.noreply.github.com>
2026-09-14 10:30:28 +04:00
nmzik 1133272668 hmd2: initialize a virtual headset with --vr
Inspired by https://github.com/KytyPS5/KytyPS5/pull/607

Co-authored-by: BlackCAT <52720489+psnwd@users.noreply.github.com>
2026-09-14 10:30:28 +04:00
nmzik bbebb6419b graphics: preserve PS5 array mip contents during cache promotion
PPSA05975
2026-09-14 06:58:32 +04:00
nmzik b67cb81359 avplayer: report loop boundaries when decoded output is delivered 2026-09-14 06:58:32 +04:00
nmzik f3c82a317a kernel: support timed umtx waits through shared address deadlines
Co-authored-by: BlackCAT <52720489+psnwd@users.noreply.github.com>
2026-09-14 06:58:32 +04:00
nmzik f426d60ff1 net: use the shared host resolver for Linux name lookups 2026-09-14 06:58:32 +04:00
nmzik b2fdad9e47 memory: preserve live POSIX mappings during partial unmap
Co-authored-by: Ali Almohaya <AliAlmohaya@gmail.com>
2026-09-14 06:58:32 +04:00
nmzik 87971a28f5 gpu: isolate tessellation analysis and SPIR-V emission 2026-09-14 06:58:32 +04:00
nmzik 96d62b3367 gpu: reflect tessellation strides from memory address dataflow 2026-09-14 06:58:32 +04:00
nmzik 7516068662 gpu: compile RDNA2 tessellation through native LS HS and TES stages 2026-09-14 06:58:32 +04:00
nmzik 6d1ba5870a renderer: share graphics resource preparation across shader stages 2026-09-14 06:58:32 +04:00
nmzik 00a16f3120 gpu: retain fused hull shader user-data addresses 2026-09-14 06:58:32 +04:00
nmzik d3d7bd33f8 launcher: Add game size column 2026-09-12 17:56:44 +04:00
Mehmet Cambaz 069f928edc net: return copied bytes for truncated datagram receives (#510)
Normalize Winsock WSAEMSGSIZE on receive to the copied byte count before converting the peer address. Preserve other receive errors and oversized send failures.
2026-09-12 17:51:43 +04:00
Mininaut 0f3674f531 kernel: release descriptors when rejecting read-only truncation (#504)
Co-authored-by: nmzik <Nmzik@mail.ru>
2026-09-12 17:44:45 +04:00
ADBHXNLOL a21ffde34e shader: decode and translate V_FRACT_F16 (VOP1 0x5f) and V_CMPX_LT_U16 (VOPC 0xb9) (#582)
shader: support V_FRACT_F16 and V_CMPX_LT_U16

Decode compact, SDWA, and VOP3 forms using the existing arithmetic and comparison paths. Preserve EXEC masking and VCC for the integer compare, and reject unsupported DPP encoding.

Add captured-instruction, operand-selection, floating-point edge, and execution-mask regression coverage.

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-09-12 17:21:32 +04:00
nmzik 1208d22547 Fix Windows Clang SPIR-V serialization with typed operands 2026-09-12 13:08:23 +02:00
nmzik 3a27f8a76a build: fix SPIR-V enum word conversions 2026-09-12 15:43:47 +04:00
ADBHXNLOL dff2b19c56 json2: export Value::clear (#584)
Export the existing clear implementation while preserving tree ownership and root handler metadata.
2026-09-12 15:15:26 +04:00
V a58db4f023 docs: fix pre-commit setup instructions (#556)
Co-authored-by: vmexe <vmexe@users.noreply.github.com>
2026-09-12 14:58:34 +04:00
Frans 7bcd43dbee shader: support S_MUL_HI_I32 (SOP2 0x36) (#576) 2026-09-12 14:56:14 +04:00
nmzik 7c5473400e config: simplify logging and profiler options. Change to Mailbox 2026-09-12 14:41:34 +04:00
nmzik 23c8a43e37 Simplify and batch buffer cache downloads 2026-09-12 14:17:00 +04:00
nmzik 2d37634ee9 shader: construct SPIR-V module variables in one place 2026-09-12 13:42:15 +04:00
nmzik e026bfc9a2 shader: let structurization own rollback on failure 2026-09-12 13:42:15 +04:00
nmzik 5a31de7955 shader: keep derived frontend metadata with its owner 2026-09-12 13:42:15 +04:00
nmzik 20e57994cf shader: reuse native emitters and simplify memory dispatch 2026-09-12 13:42:15 +04:00
nmzik 59ef88c959 shader: generate SPIR-V dispatch and marshal handler arguments 2026-09-12 13:42:15 +04:00
nmzik 1d1f00bdef shader: use Khronos definitions and simplify compiler ownership 2026-09-12 13:42:15 +04:00
nmzik 47b26e497f pthread: fix per-thread wakeups 2026-09-12 13:40:10 +04:00
nmzik 733842cad4 kernel: index pthread key values per thread 2026-09-12 13:40:10 +04:00
nmzik 73363f1272 memory: remove per-page host protection bookkeeping 2026-09-12 13:40:10 +04:00
nmzik 0cd7682012 Rename texture transfer types and download APIs 2026-09-12 13:40:10 +04:00
nmzik 25a44371e3 refactor(graphics) 2026-09-12 13:40:10 +04:00
nmzik f2455c875e update tracy to 0.14.1 2026-09-10 19:34:37 +04:00
nmzik 2e315a3c62 ajm: parse gapless control data before codec initialization 2026-09-10 18:38:24 +04:00
nmzik d2fa86579b kernel: share directory streams across seeks and reads 2026-09-10 14:36:15 +04:00
nmzik 23e7df21b1 graphics: simplify texture upload and component mapping paths 2026-09-10 14:36:15 +04:00
nmzik a305a6c1c6 graphics: share packed texture and render-target channel layouts
Resolve PS5 5551 textures with alpha in bit 15 and compose host channel order with guest selectors. Share the existing render-target mapping with sampled textures so packed layouts cannot diverge.

Add native GPU readback coverage for 5551 and 4444, arbitrary selectors, constants, and existing 1555 render-target mapping. Verified PPSA24515 through launch.json with Vulkan validation, advancing scenes and over 12,700 guest flips. Independent correctness and cleanliness audits passed.
2026-09-10 14:36:15 +04:00
nmzik 635fb8882b systemservice: use configured language for PS5 parameter 400 2026-09-10 14:11:46 +04:00
nmzik fe6f49632c font: accept supported OpenType CFF faces 2026-09-10 14:11:46 +04:00
nmzik c3546577b6 shader: implement S_WQM_B32
Co-authored-by: Brandon Strong <brandostrong@gmail.com>
2026-09-10 14:11:46 +04:00
nmzik c913951f7b shader: implement RDNA2 subvector loop mask and branch semantics 2026-09-10 14:11:46 +04:00
nmzik 3902b42096 shader: share direct and conditional branch classification 2026-09-10 14:11:46 +04:00
nmzik ae573f941a graphics: share vertex format mapping and support packed float colors 2026-09-10 14:11:46 +04:00
nmzik 20ea54cf0c Json2: new ABI 2026-09-10 14:11:46 +04:00
nmzik 0b4e78c0b2 graphics: execute DB_RENDER_OVERRIDE depth and stencil copies 2026-09-09 15:26:52 +04:00
nmzik 57844a07e2 buffer cache: grow stream reserves toward incoming requests 2026-09-09 15:26:52 +04:00
nmzik ba18551d6e ces: implement CP932 string conversion 2026-09-09 15:26:52 +04:00
nmzik c7b0d77970 loader: port guest fault diagnostics and remove host stack traces
Co-authored-by: Ali Almohaya <AliAlmohaya@gmail.com>
2026-09-09 13:55:53 +04:00
nmzik 1af19eabf0 shader: fix incorrect per-lane VCCZ/EXECZ reads 2026-09-09 13:22:09 +04:00
nmzik 32ea0869e5 shader: implement S_ORN2_SAVEEXEC_B32 2026-09-09 13:11:48 +04:00
nmzik e04007a7c6 shader: implement DS_INC_RTN_U32 and DS_DEC_RTN_U32 2026-09-09 12:56:20 +04:00
frangametv 1a3a15e4cf Fix mount root opens and empty APR prefixes (#439)
* Fix opening mount root directories

* Allow empty APR path prefixes

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-09-09 12:31:23 +04:00
nmzik 679adbfa5e graphics: fix linear render-target pitch alignment 2026-09-09 02:45:59 +02:00
nmzik d285efe3b5 graphics: allow absent programmable restart indices
Co-authored-by: Ettore Sartori <85788613+Ekt0re@users.noreply.github.com>
2026-09-08 21:26:59 +04:00
nmzik a64c8d3205 kernel: implement umtx wait/wake and reject malformed timeouts 2026-09-08 21:26:59 +04:00
nmzik 82c52c3fab window: round FPS in the title 2026-09-08 21:26:59 +04:00
nmzik dd1e90fcd7 video: keep decoding after Flush 2026-09-08 21:26:59 +04:00
nmzik ef0155636a shader: support single and split NGG shaders for PPSA11142 2026-09-08 21:26:59 +04:00
nmzik 9d550fbffa graphics: fix last provoking vertex on PS5 2026-09-08 21:26:59 +04:00
nmzik fcef691e0a shader: drop EmitTrueBool 2026-09-08 21:26:59 +04:00
nmzik 839c172612 shader: reuse operands and remove duplicate helpers 2026-09-08 21:26:59 +04:00
nmzik 9f49ac8249 shader: reuse SPIR-V helpers and memory resources 2026-09-08 21:26:59 +04:00
nmzik fde550ef66 graphics: simplify texture cleanup and swizzle decoding 2026-09-08 21:26:59 +04:00
nmzik 2b3993a595 shader: share emitter helpers 2026-09-08 21:26:59 +04:00
nmzik de3e86791c shader: reuse CFG and validation lookups 2026-09-08 21:26:59 +04:00
nmzik 6f66f77b09 shader: drop unused decoder fields 2026-09-08 21:26:59 +04:00
nmzik d853aba955 graphics: skip temporary cache lookup vectors 2026-09-08 21:26:59 +04:00
nmzik cd62693792 shader: share control flow labels 2026-09-08 21:26:59 +04:00
nmzik cb4c8f3878 shader: decode buffer formats once 2026-09-08 21:26:59 +04:00
nmzik 4d371d5f5f shader: reuse initial SSA types 2026-09-08 21:26:59 +04:00
nmzik 72963b01e1 shader: remove redundant decoder and translator state 2026-09-08 21:26:59 +04:00
nmzik 80a18e82b7 graphics: simplify image allocation 2026-09-08 21:26:58 +04:00
nmzik 574e687734 graphics: drop unused completion overload 2026-09-08 21:26:58 +04:00
nmzik c725ec50ff graphics: clean up draw setup 2026-09-08 21:26:58 +04:00
Brandon Strong c6f6e306e0 shader: raise the dense image resource limit to 64 (#457) 2026-09-08 19:37:41 +04:00
nmzik b847135321 launcher: guard optional Qt Vulkan support on macOS 2026-09-08 04:29:01 +04:00
nmzik ca3dc8792a libs: implement NpCommerce lifecycle 2026-09-08 04:25:35 +04:00
nmzik ac3156df3a graphics: fix Vulkan BC image compatibility checks` 2026-09-07 23:41:19 +02:00
nmzik 6aa6e390ee renderer: skip unsupported primitives (print log) 2026-09-07 15:20:09 +04:00
nmzik e4c10de8b6 launcher: add GPU selection 2026-09-07 15:12:35 +04:00
nmzik b3b3aeef73 graphics: simplify EOP recording 2026-09-07 15:00:52 +04:00
nmzik 056dcee70c graphics: simplify buffer allocations 2026-09-07 15:00:52 +04:00
nmzik 13c5bbe916 graphics: simplify pipeline keys 2026-09-07 15:00:52 +04:00
Beru bbe3bd0304 Audio: support 12-channel AudioOut2 output with SDL (#498)
* Audio: support 12-channel AudioOut2 output via stereo downmix

* Audio: document 7.1.4 downmix matrix and align s16 coefficients

* audio: use shared 12-to-8 channel conversion for SDL

---------

Co-authored-by: Airsoft Project <airsoft@example.com>
Co-authored-by: nmzik <Nmzik@mail.ru>
2026-09-07 12:58:23 +04:00
Tarun f9b279c49d launcher: verify updates against GitHub and check release dates (#482)
* launcher: verify with GitHub when website feed differs and compare tag dates

* launcher: restore kyty_emulator dependency for CI build and install

* launcher: simplify GitHub update verification

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-09-07 12:25:54 +04:00
nmzik b61360a0c0 fix: share thread signal stacks with macOS 2026-09-07 12:17:30 +04:00
Ali Almohaya 27ee6f02d6 fix: windows build failure in UTF-16 conversion (#499) 2026-09-07 11:52:22 +04:00
nmzik 2097ebb414 render: support overlapping fragment depth feedback 2026-09-07 11:15:47 +04:00
nmzik 587df9145f render: validate sampled depth descriptors independently of target history
Comparison textures can carry valid HTILE descriptors before any depth-target binding. Keep encoding checks independent of cached image metadata, matching SDK texture classification and shadPS4 depth promotion. Preserve HTILE address and control validation, and replace cache-history test fixtures with captured first-use coverage.
2026-09-07 11:12:48 +04:00
nmzik 2c5060e14f shader: remove masked-value pass and normalize ancillary fields 2026-09-07 11:12:48 +04:00
nmzik 75aaa963d2 update screenshot 2026-09-07 09:31:15 +04:00
nmzik 34ebfe40c3 shader: report compiled counts by guest stage 2026-09-07 07:34:01 +04:00
nmzik 2a54310876 render: fix depth write state before choosing layouts
Co-authored-by: MehmetCambaz <mcambaz18@gmail.com>
2026-09-07 07:12:58 +04:00
nmzik 8bccd325ec shader: keep mask predicates across 64-bit moves 2026-09-07 07:04:55 +04:00
nmzik ad935311f0 Revert "render: add depth attachment feedback support" 2026-09-07 07:01:53 +04:00
nmzik 19fc0274de shader: validate shared terminal paths in selections 2026-09-07 06:57:55 +04:00
nmzik 6cc9e5de11 shader: fix wave32 VCC halves and scalar mask moves
Co-authored-by: Brandon Strong <brandostrong@gmail.com>
2026-09-07 06:04:40 +04:00
nmzik bf7ca29487 shader: decode VOP3 FMAC source modifiers 2026-09-07 05:25:26 +04:00
nmzik 3cf426662e audio: fix microphone input format decoding 2026-09-07 05:04:15 +04:00
nmzik 1fd07c2c83 shader: assemble point inputs for merged geometry shaders 2026-09-07 05:04:15 +04:00
nmzik f880c58ccc render: add depth attachment feedback support
Co-authored-by: DeathWhispers <56944463+Death-Whispers-U@users.noreply.github.com>
2026-09-07 04:25:10 +04:00
nmzik 49e59e572e shader: separate depth comparison and regular image descriptors
Co-authored-by: Lordix <lordix253634@gmail.com>
Co-authored-by: fxpw <fxpw@outlook.com>
Co-authored-by: Mac <me@itsmemac.com>
2026-09-07 04:06:14 +04:00
nmzik 9d1fc8328f render: allow supported unrestricted float depth uploads
Co-authored-by: fxpw <fxpw@outlook.com>
2026-09-06 22:00:40 +04:00
nmzik c9ff09c7c2 textures: keep native formats unless depth promotion is known
Co-authored-by: Ettore Sartori <85788613+Ekt0re@users.noreply.github.com>
Co-authored-by: Mac <me@itsmemac.com>
2026-09-06 21:40:58 +04:00
nmzik ceb2b664e0 render: reset rasterization defaults on CLEAR_STATE 2026-09-06 21:25:12 +04:00
nmzik b5b4c06179 textures: share depth comparison view geometry 2026-09-06 20:18:31 +04:00
nmzik d70f9c0b2b launcher: add readback option 2026-09-06 19:48:21 +04:00
nmzik e847f82fab shader: initialize pixel position W as a reciprocal 2026-09-06 19:47:43 +04:00
nmzik 807a594c2d textures: keep atlas data across compressed block views 2026-09-06 18:57:26 +04:00
nmzik ced73c56cc shader: fix spilled mesh shader data loads 2026-09-06 17:17:51 +04:00
nmzik 9c6f6fa624 json2: add array and object value lifecycles 2026-09-06 14:48:49 +04:00
nmzik 533176f9ff shader: drop inactive pixel values under whole-quad masks 2026-09-06 14:38:32 +04:00
nmzik 66c1663495 audio: use the shared AAC decoder for Audiodec 2026-09-06 14:16:27 +04:00
nmzik 30c7715d3f audio: separate the decoder interface from AJM jobs 2026-09-06 14:07:12 +04:00
nmzik 093911a1dc audio: check packet buffers only during decode 2026-09-06 14:04:27 +04:00
nmzik d83f1f8235 memory: handle GPU faults at the mapped boundary
Co-authored-by: CheesyPoofs346 <jjs777406@gmail.com>
2026-09-06 11:08:05 +04:00
nmzik 50e78d717d render: use guest polygon modes 2026-09-06 10:56:59 +04:00
nmzik 6ca8201982 textures: handle DCC memory reused as HTile 2026-09-06 10:34:02 +04:00
nmzik 99a87bd65b shader: keep loop branches during selection routing 2026-09-06 10:23:44 +04:00
nmzik f9f8e12c35 shader: add viewport-index exports and indexed raster state
Co-authored-by: Ettore Sartori <85788613+Ekt0re@users.noreply.github.com>
2026-09-06 10:16:38 +04:00
nmzik dcaf4205cb render: track pages for DMA fills and copies 2026-09-06 10:16:27 +04:00
nmzik 4735359466 textures: invalidate stencil links on CPU writes 2026-09-06 09:38:22 +04:00
nmzik 211242452b kernel: use per-thread signal stacks for guest stack faults 2026-09-06 09:28:19 +04:00
nmzik 6ae5cb7b64 system: keep controller focus in overlays 2026-09-06 09:15:29 +04:00
nmzik 997ad60c50 system: keep error dialogs open until dismissed 2026-09-06 08:34:58 +04:00
nmzik 44f982bca7 render: apply DCC clears before binding images
Co-authored-by: Techx3 <56268269+Techx3@users.noreply.github.com>
Co-authored-by: Brandon Strong <brandostrong@gmail.com>
2026-09-06 08:00:59 +04:00
nmzik 0456f5a06b libc: fix UTF-16 printf strings and precision limits 2026-09-06 07:28:19 +04:00
nmzik b346f58b73 shader: read sample IDs from pixel ancillary input 2026-09-06 06:54:38 +04:00
nmzik ace877ce28 shader: lower FMASK loads before binding images 2026-09-06 06:42:23 +04:00
nmzik cf0cbee02d shader: fix vertex attribute identity swizzles 2026-09-06 05:47:20 +04:00
nmzik 98e7eeb72a textures: keep dirty pages during image-to-buffer sync 2026-09-06 05:36:41 +04:00
nmzik 803c124136 textures: reuse range lookups for buffer sync 2026-09-06 05:07:44 +04:00
nmzik d9d17737c3 net: return native SO_ERROR 2026-09-06 05:07:44 +04:00
nmzik 46850f9574 net: fix socket wakeups and readiness checks 2026-09-06 05:00:12 +04:00
nmzik 314d37155a net: add TCP_NODELAY and translate socket errors 2026-09-06 04:51:07 +04:00
nmzik ddcdb654ad net: share native connect and accept 2026-09-06 04:47:15 +04:00
nmzik cdec5c515b net: use native listen on POSIX 2026-09-06 04:45:53 +04:00
nmzik 1eb13dfa5e render: call Vulkan diagnostics and capability checks directly 2026-09-06 04:11:46 +04:00
nmzik dda628ca81 render: simplify command and resource ownership 2026-09-06 04:05:35 +04:00
nmzik 13ad9f510d render: clean up cache and image internals 2026-09-06 03:55:13 +04:00
nmzik 4c769dfbf9 render: simplify buffer and memory tracking ownership 2026-09-06 03:46:34 +04:00
nmzik ccd19b3e56 render: choose depth layouts independently of load clears
Co-authored-by: DeathWhispers <56944463+Death-Whispers-U@users.noreply.github.com>
2026-09-06 03:35:56 +04:00
nmzik 81d0ea5697 render: ignore stale export formats with no pixel shader 2026-09-05 23:36:42 +04:00
nmzik 43de8bfaac shader: cache integer dependency checks 2026-09-05 20:35:18 +04:00
nmzik 86b539a9ea tests: clear BDA page tables before transfer updates 2026-09-05 16:04:58 +04:00
nmzik 81a5dd612f shader: fix embedded vertex fetch swizzles 2026-09-05 16:00:46 +04:00
nmzik 9c00c7077b shader: keep per-invocation mesh exports out of shared memory 2026-09-05 15:48:29 +04:00
nmzik 49ff962f69 shader: add conditional 64-bit scalar moves
Co-authored-by: shadowbeat070 <70843316+shadowbeat070@users.noreply.github.com>
2026-09-05 15:38:51 +04:00
nmzik c83aac966e textures: keep incompatible mip layouts separate 2026-09-05 15:24:07 +04:00
nmzik 9918dc2591 render: set merged GS user data from shader registers
Co-authored-by: shadowbeat070 <70843316+shadowbeat070@users.noreply.github.com>
2026-09-05 15:08:20 +04:00
nmzik 3ab372ccec render: build indexed triangles for merged ES/GS shaders
Co-authored-by: shadowbeat070 <70843316+shadowbeat070@users.noreply.github.com>
2026-09-05 14:59:28 +04:00
nmzik 843c0c59be render: use Vulkan-Hpp setup defaults 2026-09-05 14:42:14 +04:00
nmzik d93812b0bd render: simplify pool wrapping and scissor clipping 2026-09-05 14:37:11 +04:00
nmzik 1c68c94c05 render: remove redundant cache setup 2026-09-05 14:37:04 +04:00
nmzik c66060be10 render: simplify pipeline setup 2026-09-05 14:36:52 +04:00
nmzik e7b269a9f6 render: clean up image setup and tiler recording 2026-09-05 14:36:42 +04:00
nmzik d5b19850fb render: clean up texture transfers and compute fills 2026-09-05 13:20:52 +04:00
nmzik e7fe8192bb tests: wait for interrupt callbacks before the next queue
Co-authored-by: Vyas Devgna <vyasdevgna@gmail.com>
2026-09-05 13:20:16 +04:00
nmzik ebe0979563 shader: share runtime value checks 2026-09-05 13:16:54 +04:00
nmzik a379304362 present: wait for image acquisition before transitioning 2026-09-05 12:40:54 +04:00
nmzik bec7c510c2 render: use native clears for stencil fill shaders 2026-09-05 12:36:13 +04:00
nmzik 6a187ac67e render: upload the full stride-zero vertex attribute
Co-authored-by: Brandon Strong <brandostrong@gmail.com>
2026-09-05 12:17:39 +04:00
nmzik 9641b51925 render: fix tiled depth comparison textures
Co-authored-by: Ettore Sartori <85788613+Ekt0re@users.noreply.github.com>
Co-authored-by: Mac <me@itsmemac.com>
2026-09-05 11:44:11 +04:00
nmzik b96a30ed88 shader: keep fragment layer values under lane masks
Co-authored-by: shadowbeat070 <70843316+shadowbeat070@users.noreply.github.com>
2026-09-05 11:43:49 +04:00
nmzik 2ec0e9e8f3 shader: fix packed image address reads 2026-09-05 11:32:32 +04:00
nmzik 51afce3a97 shader: zero-extend unsigned SOPK comparisons 2026-09-05 10:38:29 +04:00
nmzik dea80f34ca shader: detect full buffer fills from uniform stores
Co-authored-by: Techx3 <56268269+Techx3@users.noreply.github.com>
2026-09-05 10:34:30 +04:00
nmzik 994271e2f6 renderdoc: start and stop captures on the present thread 2026-09-05 09:54:42 +04:00
nmzik 59902d1fd8 shader: skip resources in untaken uniform branches
Co-authored-by: GodsWill <GodsWill@users.noreply.github.com>
Co-authored-by: Techx3 <56268269+Techx3@users.noreply.github.com>
2026-09-05 09:38:50 +04:00
nmzik b92f0a5458 render: share layouts with sampled attachments
Co-authored-by: DeathWhispers <56944463+Death-Whispers-U@users.noreply.github.com>
2026-09-05 08:54:41 +04:00
nmzik 251f6d6121 shader: fix returns and descriptor placement 2026-09-05 08:54:35 +04:00
nmzik 0d8c83a5cb tests: enable Vulkan gather and derivative features 2026-09-05 08:54:14 +04:00
nmzik 3624d96c78 render: fix depth mapping for -1 to 1 viewports 2026-09-05 08:40:05 +04:00
nmzik 3213934d42 shader: run merged geometry stages as mesh shaders
Co-authored-by: Brandon Strong <brandostrong@gmail.com>
Co-authored-by: fxpw <fxpw@outlook.com>
Co-authored-by: shadowbeat070 <70843316+shadowbeat070@users.noreply.github.com>
2026-09-05 08:32:23 +04:00
nmzik 246212789f agc: merge resources from both shader stages 2026-09-05 07:39:30 +04:00
nmzik c7f7fd974b textures: use the backing format for alias uploads
Co-authored-by: Lordix <lordix253634@gmail.com>
2026-09-05 07:30:05 +04:00
nmzik 5cf2f5767a render: fix volume attachment slice bounds
Co-authored-by: SueryRD <the.ai.tester2@gmail.com>
Co-authored-by: Techx3 <56268269+Techx3@users.noreply.github.com>
2026-09-05 07:11:46 +04:00
nmzik e8e580cf6c fix ge 2026-09-05 06:53:59 +04:00
nmzik 74a78f37d0 renderer: grow repeatedly joined buffer ranges (perf) 2026-09-05 06:30:31 +04:00
nmzik 8d3ebb5a55 renderer: widen buffer readback windows
Co-authored-by: Ali Almohaya <17254073+Almo7aya@users.noreply.github.com>
2026-09-05 05:44:42 +04:00
nmzik 3628d2b4c1 renderer: remove dynamic draw state from pipeline keys 2026-09-05 04:41:41 +04:00
nmzik d96d0eeb18 libPad: ABIs 2026-09-04 07:42:23 +02:00
nmzik bd401a1407 shader: ignore inactive auxiliary position exports 2026-09-04 07:42:23 +02:00
nmzik 070730be0a kernel: report PS5 Base operation mode 2026-09-04 07:42:23 +02:00
nmzik 94e7d0a189 renderer: accept inactive coarse HTILE; drop dead MRT filter 2026-09-04 07:42:23 +02:00
nmzik c28b71f8e0 gpu: centralize depth shading-rate handling 2026-09-04 05:55:28 +02:00
nmzik 27f015ecd1 Revert "graphics: preserve unrestricted viewport depth ranges"
This reverts commit eccd6f6cac.
2026-09-04 05:22:17 +02:00
nmzik 8596627ced shader: share SPIR-V atomic update lowering 2026-09-04 05:10:31 +02:00
nmzik d4cca82a22 libs: stub WebBrowserDialogGetStatus 2026-09-04 05:07:58 +02:00
nmzik dd9ecd5f65 Revert "shader: separate comparison image bindings"
This reverts commit d762d24f73.
2026-09-04 03:09:00 +02:00
nmzik 81b0c1302d Revert "graphics: create depth images for comparison textures"
This reverts commit 0ce19357f6.
2026-09-04 03:08:56 +02:00
Tarun b9b0b87545 Add update checker to launcher (#478)
launcher: add release update checker

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-09-04 02:38:02 +02:00
nmzik 040b2b9653 tests: align GPU fixtures with binding architecture 2026-09-04 02:06:06 +02:00
nmzik eccd6f6cac graphics: preserve unrestricted viewport depth ranges 2026-09-04 02:06:06 +02:00
nmzik 0ce19357f6 graphics: create depth images for comparison textures 2026-09-04 02:06:06 +02:00
nmzik d762d24f73 shader: separate comparison image bindings 2026-09-04 02:06:06 +02:00
nmzik eb917463ad fix File abstraction destructor 2026-09-04 02:06:06 +02:00
Mehmet Cambaz c2189de88f controller: give the DualShock 4 the DualSense pad path and release p… (#453)
controller: give the DualShock 4 the DualSense pad path and release pads on exit
2026-09-04 00:10:57 +02:00
GodsWill Dev 2fe5c150bc shader: implement BUFFER_ATOMIC_CMPSWAP (#357)
shader: implement RDNA2 buffer atomic compare swap

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-09-03 23:34:34 +02:00
nmzik 5b8e3b51b0 cross-vendor TLS fix: 0x66 prefixes are forced into 64bit call on AMD 2026-09-03 23:03:48 +02:00
nmzik f27a136430 Refactor(simplify) PM4 draw submission arguments 2026-09-03 22:23:13 +02:00
nmzik fb4d97e8a9 graphics: fix PS5 NGG vertex and instance draw offsets
Refs: https://github.com/KytyPS5/KytyPS5/issues/130
2026-09-03 21:52:02 +02:00
nmzik 5ffcd28ca4 launcher: fix rare use after free bug 2026-09-03 11:32:32 +02:00
nmzik b3c8f91a84 graphics: implement RDNA2 buffer atomic swap x2 2026-09-03 10:17:04 +02:00
nmzik c78a5a9fdf graphics: unify atomic feature and width handling 2026-09-03 05:45:45 +02:00
nmzik 858c18468b graphics: implement RDNA2 buffer atomic OR x2 2026-09-03 05:39:05 +02:00
nmzik cd74809086 launcher: fix light mode, group settings into resizable sections 2026-09-03 04:13:34 +02:00
Brandon Strong e21c5f37d0 graphics: honour DCC fixed clear codes on 16-bit and float colour targets (#471)
* Honour DCC fixed clear codes on 16-bit and float colour targets

* tests: DCC fixed clear codes materialise on an RGBA16F target

* graphics: remove fixed clear format comment

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-09-03 03:41:28 +02:00
Brandon Strong 2d5023fda2 shader: support IMAGE_ATOMIC_SWAP (#456) 2026-09-03 03:37:55 +02:00
nmzik 98200fed19 shader: rework resource specialization and optimize pipeline caching 2026-09-03 03:04:17 +02:00
nmzik c48a8bd6ae shader: evaluate uniform first-lane sampler descriptors 2026-09-03 03:04:17 +02:00
Brandon Strong 16ea36eb4b libkernel: register scePthreadRwlockTryrdlock and the timed rwlock variants (#472)
* libkernel: register scePthreadRwlockTryrdlock and the timed rwlock variants

* fix: initialize static rwlocks in newly registered APIs

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-09-03 01:58:38 +02:00
Brandon Strong 8f6f65f4c9 libs: implement Json Value::referValue by key and Value::toString (#455) 2026-09-03 01:58:23 +02:00
Brandon Strong b81f1fc774 libs: implement sceConvertKeycodeGetImeKeyboardType (#469)
* libs: implement sceConvertKeycodeGetImeKeyboardType

* fix: correct ConvertKeycode error codes

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-09-03 01:57:10 +02:00
Brandon Strong c85bd45604 kernel: implement sceKernelClearVirtualRangeName (#466) 2026-09-03 01:50:14 +02:00
nmzik 5c86f894be shader: simplify typed image bindings 2026-09-02 15:45:16 +02:00
nmzik 86e3c90e32 shader: simplify image resource semantics 2026-09-02 15:45:15 +02:00
nmzik 93be8c201b shader: unify SPIR-V image dimension 2026-09-02 15:44:39 +02:00
nmzik 894bc7de3c shader: support signed sampled images 2026-09-02 15:39:30 +02:00
nmzik fc91fd2b1a libs: simplify ABI registration facades 2026-09-02 02:06:14 +04:00
nmzik a06a005124 controller: simplify input facade API 2026-09-02 02:06:14 +04:00
nmzik e9425e101d shader: add missing RDNA2 ALU opcodes
Add missing scalar and vector opcodes with compute tests.

Original work by @Pouare514 in #176.

Co-authored-by: Pouare514 <julienaulycee@gmail.com>
2026-09-02 01:56:55 +04:00
CheesyPoofs3460 04b404f3c9 controller: enable the DualSense HIDAPI driver, light bar and adaptive triggers (#437)
* controller: enable the DualSense HIDAPI driver, light bar and adaptive triggers

Three additions. SDL was opening a DualSense through the generic gamepad path, so SDL_GameControllerHasLED and SDL_GameControllerGetNumTouchpads both reported nothing and no touchpad events ever arrived - enabling the PS5 HIDAPI driver before SDL_InitSubSystem is what makes the light bar and the existing touchpad support reachable. PadSetLightBar validated its arguments and returned OK without touching the pad; it now drives the LED. PadSetTriggerEffect did the same; it now translates the mode and parameters into a DualSense trigger block and sends it.

* controller: fix DualSense effects

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-09-02 00:53:19 +04:00
nmzik 80225015c5 renderer: enable storage for color images 2026-09-01 23:54:17 +04:00
nmzik 0c4dfd565e renderer: emulate clip-disabled screen-space positions 2026-09-01 21:39:11 +04:00
nmzik 0c8d7a1e49 shader: DPP row-xmask 2026-09-01 21:02:19 +04:00
nmzik a2150c70bb network: implement Linux getsockname 2026-09-01 20:50:57 +04:00
nmzik 160cf5352c http: new abi 2026-09-01 20:50:57 +04:00
nmzik 3b6b3c2040 pm4: handle reserved depth control fields 2026-09-01 20:50:57 +04:00
nmzik 63dd3917e2 reduce runtime logging 2026-09-01 20:50:57 +04:00
nmzik 2333c235f1 loader: TLS patch fix 2026-09-01 20:50:57 +04:00
nmzik dd062ceeeb prevent Escape from exiting 2026-09-01 07:50:37 +04:00
nmzik e591a66b67 Revert "shader: preserve raw VCC bits in S_MOV_B64 (#418)"
This reverts commit 6758d67942.

An EXEC pair loses its mask provenance and falls into the raw high-word path. The saved all-ones high word then keeps waterfall branches true and wedges GPU work.
2026-09-01 07:50:37 +04:00
Brandon Strong b8a459e83d graphics: do not arm a fast clear from a read-modify-write dispatch (#428)
* graphics: do not arm a fast clear from a read-modify-write dispatch

* tests: cover compute metadata clear classification

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-09-01 05:48:06 +04:00
nmzik 7684c343d6 guest_gpu: fix private AGC register regression 2026-09-01 04:24:47 +04:00
CheesyPoofs3460 e0c055fd74 renderer: decode R32_SFLOAT packed colour clears (#436)
* renderer: decode R32_SFLOAT packed colour clears

DecodePackedColorClear handled R32Uint, R32Sint and the 8/10-bit formats but fell through to the default false case for R32Sfloat. metadata_clear_supported then went false, the clear value was discarded, and the target kept its previous contents. Decode the packed word as float bits, matching DecodePackedDepthClear directly below, and reject non-finite patterns rather than materializing them.

* renderer: preserve all R32_SFLOAT clear bits

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-09-01 03:37:55 +04:00
nmzik d1eee7b3a9 emulate dualsense touchpad + refactor (ps1 emulation) 2026-09-01 02:21:47 +04:00
nmzik 1342c6f1e1 shader: took fixes from PR 427
- apply c8f34f9's ResourceTracking portability fix
- complete V_CMP_LT_U64 and S_FLBIT_I32_B32 support
- add the sceAmprCommandBufferWaitOnAddress NID from f625a47
- add decoder and compute tests for both shader operations

Co-authored-by: Mac <me@itsmemac.com>
2026-08-31 23:49:21 +04:00
GodsWill Dev 6453bafd1d renderer: ignore inactive stencil registers for depth-only targets (#425)
graphics: ignore inactive Hi-Stencil state

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-08-31 22:39:44 +04:00
nmzik beb8047083 remove truly unknown Kyty era abi 2026-08-31 21:01:24 +04:00
nmzik 1df06e230d guest_gpu: remove stale PS4/GCN era gpu registers 2026-08-31 20:58:35 +04:00
nmzik 39a34fa343 graphics: consolidate validation guest checks 2026-08-31 11:06:51 +04:00
nmzik 96c64d113e shader: trust recompiler stage metadata 2026-08-31 10:30:58 +04:00
nmzik 66ca225c76 shader: require explicit recompiler resource data 2026-08-31 10:26:08 +04:00
nmzik 0de4cfbf80 graphics: add PS5 FMASK texture formats 2026-08-31 10:11:02 +04:00
nmzik 42980fe6df graphics: accept texture-compatible FMASK compression 2026-08-31 10:01:16 +04:00
nmzik 1592cf2b1b shader: accept SDWA byte source for reverse shift 2026-08-31 09:53:26 +04:00
nmzik a9166f8546 shader: canonicalize out-of-range image formats 2026-08-31 08:16:05 +04:00
nmzik b77978fd1e agc: correct Trinity mode ABI 2026-08-31 08:16:00 +04:00
nmzik 4330cb9462 agc: preserve caller state during initialization 2026-08-31 08:15:36 +04:00
nmzik af8aecfdde shader: remove recompiler error-string propagation 2026-08-31 05:31:41 +04:00
francoisatt 13533bd053 cli: add --gpu <index> to select a Vulkan physical deviceFeature gpu select (#417)
* cli: add --gpu <index> to select a Vulkan physical device

Select the Vulkan physical device by enumeration index, defaulting to
automatic selection (-1). Invalid or out-of-range indices fall back to
automatic selection with a clear message, and the selected device is
logged.

Co-Authored-By: Claude <noreply@anthropic.com>

* cli: reject invalid --gpu index, translate comments, apply clang-format

An invalid --gpu index now prints an error and exits with code 1 (usage),
matching --user-id / --present-mode / --console-language. The automatic
fallback is kept only for out-of-range indices detected at runtime.
Comments translated to English and the touched files brought in line
with clang-format (pre-commit v22.1.3).

Co-Authored-By: Claude <noreply@anthropic.com>

* cli: simplify Vulkan device selection

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: nmzik <Nmzik@mail.ru>
2026-08-31 03:43:17 +04:00
Mehmet Cambaz cd0f0a428a graphics: quiet two misleading render diagnostics (#416)
* graphics: quiet two misleading render diagnostics

The three PM4 register-offset normalization messages logged once per occurrence with no
limit. They are printed in the colour reserved for problems, and normalizing the offset is
routine, so a short session buries the log in them: PAC-MAN WORLD 2 Re-PAC (PPSA18189)
emitted 24969 of them in about a minute, a fifth of a megabyte and 1.9% of every line
written. Rate-limit all three the way the surrounding diagnostics in these files already
are, which keeps the first occurrences without drowning what follows.

The EQAA check warned whenever a control register was set, including on single-sample
targets where those controls do nothing. That title never multisamples -- all 128 of its
render targets are samples=1 -- yet it still produced the warning, pointing at a cause that
could not apply. Return early when multisampling is off, matching how the neighbouring
sample-location check already reads msaa_num_samples.

Log output only; no rendering behaviour changes.

* graphics: silence normalized offset diagnostics

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-08-31 03:33:32 +04:00
nomolao2-cell 6758d67942 shader: preserve raw VCC bits in S_MOV_B64 (#418)
* shader: preserve raw VCC bits in S_MOV_B64

* fix(shader): centralize scalar U64 mask provenance

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-08-31 03:04:16 +04:00
nmzik dc5b7c19a6 Revert "fix(agc): honor top bound for single-ended buffers"
This reverts commit 1469c53048.
2026-08-31 01:24:55 +04:00
nmzik 2a54306e8b agc: implement async command buffer jump 2026-08-30 23:55:05 +04:00
nmzik 7a6aaafe52 agc: expose async copy and wait packet sizes 2026-08-30 23:49:08 +04:00
nmzik 1469c53048 fix(agc): honor top bound for single-ended buffers 2026-08-30 23:39:18 +04:00
GodsWill Dev 9992ab18fc shader: preserve untouched half in VOP1 B16 writes (#370)
shader: preserve native 16-bit destinations

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-08-30 19:33:26 +04:00
Brandon Strong 18af08460f shader: take the high half per lane in V_PK_FMAC_F16 (#404)
Co-authored-by: nmzik <Nmzik@mail.ru>
2026-08-30 15:08:22 +04:00
nmzik 39ee9972b8 shader: V_CMPX_CLASS_F32 2026-08-30 14:32:07 +04:00
YuhiAida e500333bcd fix(agc): implement AgcDcbCopyDataGetSize (#410)
Register b5u0Jzm8TF8 for SpongeBob PPSA26893 using the native zero-argument, uint64_t size-helper ABI.

Adapted from PR #410.
2026-08-30 13:59:16 +04:00
nmzik 4498d75b9b add agc ver 13 2026-08-30 13:29:49 +04:00
Brandon Strong 1df53b169f kernel: stop sign-extending batch-map protection and type (#405) 2026-08-30 01:46:43 +04:00
Mehmet Cambaz ff61c1cecd shader: implement V_SIN_F16 (#399)
Co-authored-by: nmzik <Nmzik@mail.ru>
2026-08-30 01:32:49 +04:00
nmzik 60a01817ce loader: add support for etaHEN cheats 2026-08-29 20:48:05 +04:00
nmzik 1a87cfedb5 shader: implement V_COS_F16 2026-08-29 19:23:19 +04:00
nmzik 5bd447d2a2 shader: implement DS_BPERMUTE_B32
Co-authored-by: Techx3 <56268269+Techx3@users.noreply.github.com>
2026-08-29 19:23:19 +04:00
Rogelio J Gomes a4fc58e908 input: PC-style DualSense mouse/keyboard mapping (#213)
input: add mouse-to-right-stick mapping and sensitivity

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-08-29 17:27:23 +04:00
nacimoualla 4e8e335b7b macOS: full support — MoltenVK auto-discovery, portability fix, and KytyPS5.app bundle (#394)
* macOS: auto-discover bundled MoltenVK on startup

On macOS the Vulkan loader comes from MoltenVK. SDL's default
probe only searches system paths, so a bundled libMoltenVK.dylib
next to the executable is invisible under the hardened runtime.

Probe it explicitly via SDL_GetBasePath() before falling back to
SDL's default search. Respect SDL_VULKAN_LIBRARY overrides and
log which loader is used. Update README to reflect that no
environment variable is required for bundled builds.

Co-Authored-By: internal-model

* window: fix Vulkan portability enumeration on macOS

MoltenVK requires VK_KHR_portability_enumeration and
VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR to surface
portability devices via enumeratePhysicalDevices. Without the flag
the adapter is hidden on some driver versions, causing
"Could not find suitable device" failures.

Add the instance extension and flag when available, and add
diagnostic logs for all MoltenVK fallbacks (depthClipEnable,
colorWriteEnable, depthBounds, fragmentShaderBarycentric)
so black-screen diagnostics are actionable.

* macOS: add KytyPS5.app bundle packaging

Add a proper macOS application bundle when the launcher is built.
launcher becomes KytyPS5.app (CFBundleIdentifier org.kytyps5.kytyps5)
with KytyPS5 as the executable, and kyty_emulator is installed as a
helper inside Contents/MacOS so QCoreApplication::applicationDirPath()
finds it. MoltenVK is auto-discovered via SDL_GetBasePath() in that
directory, so no SDL_VULKAN_LIBRARY is required.

- src/launcher/Info.plist.in: minimal bundle plist (version from
  PROJECT_VERSION, LSMinimumSystemVersion 13.0).
- src/launcher/CMakeLists.txt: set MACOSX_BUNDLE, BUNDLE DESTINATION,
  install helper, re-sign helper with JIT entitlements, and invoke
  macdeployqt when available. Keep flat kyty_emulator for CLI.
- .github/workflows/build.yml: bundle MoltenVK into
  KytyPS5.app/Contents/MacOS when present, verify bundle artifacts
  (file/lipo/codesign), and handle bundle paths in the release zip.
- README.md: document bundle double-click and MoltenVK locations.

* launcher: fix bundle rpath for Qt frameworks

The bundle executable had @rpath references to Qt frameworks but no
LC_RPATH, causing dyld to abort at launch:

  Library not loaded: @rpath/QtConcurrent.framework
  Reason: no LC_RPATH's found

Set INSTALL_RPATH to @executable_path/../Frameworks and
BUILD_WITH_INSTALL_RPATH so the built and installed bundles
resolve Qt from Contents/Frameworks. Verified via otool -l
(LC_RPATH now present) and macdeployqt now succeeds without
"Cannot resolve rpath" errors.

* launcher: add Import game button

Add a prominent Import button to ConfigurationListWidget that lets
users select a game folder (containing eboot.bin) or a folder
containing multiple games via QFileDialog. Handles:

- Single game folder selected: adds its parent to game_dirs (Scan
  searches subdirectories, so parent is needed)
- Folder with multiple games: adds the selected folder
- Deduplication via PathKey/NormalizeGameDirectories, writes
  settings, rescans, and selects the imported game if found
- Shows info/warning dialogs when no games are found

UI: QToolButton with SP_DirOpenIcon and text Import beside the
existing toolbar, styled with a blue background for visibility.
Logic in ConfigurationListWidget::import_game().

* macOS: fix bundled loader and artifact packaging

* Revert "launcher: add Import game button"

This reverts commit 2f670ef95c.

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-08-29 17:08:54 +04:00
Mehmet Cambaz 947576363e kernel: explain a commit-limit failure at startup (#395)
When CreateFileMapping cannot reserve the guest backing store the log only
carries the raw Win32 error, which gives no clue that the paging file is the
thing to change. Print the size that was asked for and say so directly when the
failure is ERROR_NO_SYSTEM_RESOURCES or ERROR_COMMITMENT_LIMIT.
2026-08-29 16:20:36 +04:00
nmzik 9da390bc0a general: explicit SEC_COMMIT (Windows), default printf logging to silent 2026-08-29 15:31:20 +04:00
nmzik ef639610e7 shader: allow SDWA add-with-carry 2026-08-29 15:31:20 +04:00
Brandon Strong 6c3b562822 graphics: support Standard64KB color target arrays (#315)
graphics: support Standard64KB render target arrays

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-08-29 15:18:44 +04:00
nmzik f1413569ce fix windows build 2026-08-29 14:46:54 +04:00
nmzik fcc9dff5b9 shader: DS_WRITE_B16_D16_HI 2026-08-29 14:40:13 +04:00
nmzik d9ae3ed64c shader: V_FFBH_I32 2026-08-29 14:03:57 +04:00
nmzik 618926b124 network: implement resolver destruction 2026-08-29 13:40:56 +04:00
nmzik dca7ece2ca shader: legalize 1D level-zero gathers 2026-08-29 13:32:20 +04:00
nmzik ccecebfeff loader: report unhandled host exceptions 2026-08-29 13:01:57 +04:00
nmzik 1752f1382f graphical: add per-game Vulkan pipeline caching (driver-side improvements only for now)
Co-authored-by: Ferran <ferran.duarri@me.com>
2026-08-29 12:28:48 +04:00
nmzik 53a59434d8 shader: implement V_CMP_EQ_U64 2026-08-29 11:26:05 +04:00
GodsWill Dev 18b6c9059b shader: support DS_READ_U16_D16_HI (#356)
Decode the high-half D16 LDS read and route it through the existing unsigned-short load lowering. Represent the destination as a high-half partial write so the low 16 bits of the VGPR remain intact. Add captured-instruction decode coverage and a Vulkan execution regression that verifies the preserved half.

Co-authored-by: SueryRD <the.ai.tester2@gmail.com>
2026-08-29 10:39:45 +04:00
GodsWill Dev 715539804b shader: accept SDWA for VOP1 bit operations (#360)
Allow byte, word, and full-dword SDWA source selection for V_NOT_B32 and V_FFBL_B32. Add captured instruction tests that verify decoding, IR extraction, SPIR-V generation, and runtime results.

Co-authored-by: SueryRD <the.ai.tester2@gmail.com>
2026-08-29 10:28:28 +04:00
nmzik b02eb28fd1 shader: support SDWA byte left-shift counts 2026-08-29 10:03:13 +04:00
nmzik 07f1e77d23 shader: support SDWA byte shift counts 2026-08-29 10:03:13 +04:00
Mehmet Cambaz 6980e0863d controller: forward guest vibration to SDL rumble (#365)
Scale the SDK 8-bit motor levels to SDL’s 16-bit range and use SDL’s maximum effect duration. Keep lookup and rumble under the controller lock so hot unplug cannot invalidate the SDL pointer.
2026-08-29 04:49:20 +04:00
Mehmet Cambaz 42bfeec2e9 emulator: run cleanup handlers on the quick_exit path (#334)
Run() registers KytyClose with atexit(), but Execute() ends the process with
std::quick_exit(), which invokes at_quick_exit handlers only. Nothing registered
one, so the cleanup never ran and neither did the emergency shutdown handlers
that close open guest files and flush the log.

Register a quick-exit handler that runs the emergency shutdown. It deliberately
skips RuntimeLinker::Clear(): guest threads are still live at that point and
tearing the linker down there deadlocks against a thread parked in a condition
wait.
2026-08-29 04:44:40 +04:00
GodsWill Dev 795743ce22 graphics: accept the encoded GE_CNTL group range (#363)
graphics: stop rejecting valid GE_CNTL group sizes

GE_CNTL group sizes control guest geometry-engine scheduling rather than host wave width. Do not reject the supported vertex path for compiler-selected values above 64, and remove the corresponding stale debug warnings.
2026-08-29 04:31:35 +04:00
GodsWill Dev ccddd6fb94 user: make the local profile configurable (#347)
user: make the local user ID configurable

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-08-29 04:27:49 +04:00
nmzik e559771a08 libc: isolate guest setenv from host environment. Fix linux debugging 2026-08-29 03:57:09 +04:00
nmzik b870a77176 network: enable IPv4 UDP sockets on POSIX 2026-08-29 03:57:09 +04:00
nmzik 62eaead3a3 add configurable Vulkan present modes
Co-authored-by: Techx3 <56268269+Techx3@users.noreply.github.com>
2026-08-29 03:57:09 +04:00
nmzik d7808d9cb4 add configurable local user name
Co-authored-by: Techx3 <56268269+Techx3@users.noreply.github.com>
2026-08-29 03:57:09 +04:00
nmzik 8267c422b5 launcher: add 1440p/2160p
Co-authored-by: Techx3 <56268269+Techx3@users.noreply.github.com>
2026-08-29 03:57:09 +04:00
nmzik b46e141762 dev: add Linux overrides to VS Code launch configurations 2026-08-29 03:55:29 +04:00
nmzik cfa140fb12 window: create Vulkan surface visible on main thread 2026-08-29 01:31:02 +04:00
Chai T c52bf450f5 fiber: save contexts without compiler frames 2026-08-28 05:33:46 +04:00
Chai T 4cc2f00273 libc: isolate guest tm from host ABI 2026-08-28 05:18:27 +04:00
nmzik ade32e7ba7 kernel: implement AIO request polling 2026-08-27 22:01:13 +02:00
nmzik cc5c0ec6b8 graphics: support PS5 1D color render targets 2026-08-27 14:47:17 +02:00
nmzik c167375fe1 shader: centralize program compilation and permutation caching 2026-08-27 13:37:46 +02:00
nmzik 65871a53a6 graphics: collapse redundant Vulkan and command buffer types 2026-08-27 06:22:15 +02:00
nmzik 1ff580498c shader: support V_CMPX_NGT_F16 SDWA 2026-08-27 04:25:11 +02:00
nmzik ae896d0bf6 shader: support V_CMPX_GT_U16 SDWA 2026-08-27 04:13:12 +02:00
nmzik e738535294 graphics: add RDNA2 FLAT BDA buffer cache and faults 2026-08-27 03:45:41 +02:00
nmzik 8072718462 graphics: replace command fences with timeline reuse 2026-08-26 10:03:43 +02:00
nmzik 7adade0df5 Revert "graphics: require unrestricted depth ranges"
This reverts commit 7012634f32.
2026-08-26 09:04:06 +02:00
nmzik ab50c10d08 graphics: split shader translation into explicit opcode dispatchers 2026-08-26 08:49:39 +02:00
nmzik ffa69d48de shader: remove second IR layer 2026-08-26 08:49:39 +02:00
nmzik e2c840cb23 agc: fix abis 2026-08-26 01:39:10 +02:00
nmzik fa891536df graphics: do not copy PM4 streams & route executed packet interrupts properly 2026-08-25 23:22:54 +02:00
nmzik 7012634f32 graphics: require unrestricted depth ranges 2026-08-25 03:11:12 +02:00
nmzik 663b524fb3 Revert "loader: preserve TLS patch instruction boundaries"
This reverts commit ffd07dbfce.
2026-08-25 02:46:02 +02:00
nmzik 0b3302af70 audio: parse NGS2 ATRAC9 waveform metadata 2026-08-24 08:42:07 +02:00
nmzik ffd07dbfce loader: preserve TLS patch instruction boundaries 2026-08-24 07:06:59 +02:00
nmzik 6eed46b024 renderer: simplify image view cache 2026-08-24 01:31:15 +02:00
nmzik e6ad87072d renderer: avoid speculative buffer LRU touches 2026-08-24 01:12:41 +02:00
nmzik dd2fbd6c45 tests: cover large host buffer copies 2026-08-24 00:52:53 +02:00
nmzik 1779142805 renderer: invalidate buffers on memory unmap 2026-08-24 00:40:02 +02:00
nmzik 186621c6ff renderer: use LRU buffer cache collection 2026-08-24 00:17:02 +02:00
nmzik 11d4c0d2a2 renderer: synchronize bounded buffer downloads 2026-08-23 19:22:17 +02:00
nmzik aa69b5b184 renderer: rewrite buffer lookup around page index 2026-08-23 19:22:17 +02:00
nmzik cb378365e1 renderer: avoid allocating for dirty range probes 2026-08-23 19:22:17 +02:00
nmzik 30fa9dddc5 renderer: respect buffer ownership in image downloads 2026-08-23 19:22:17 +02:00
nmzik 4d8d3b6d25 renderer: batch buffer cache uploads 2026-08-23 19:22:17 +02:00
nmzik 523cc17ffe renderer: keep small buffer uploads nonblocking 2026-08-23 19:22:17 +02:00
nmzik 825e5f1162 renderer: defer clean buffer destruction on unmap 2026-08-23 19:22:17 +02:00
nmzik 3c016bead1 renderer: defer texture destruction on unmap 2026-08-23 17:08:59 +02:00
nmzik 800a7719cf target Vulkan 1.3 for bundled shaders 2026-08-23 16:51:37 +02:00
nmzik e3fb05c1a8 logging: report build and host details at startup 2026-08-23 16:47:15 +02:00
nmzik bc9c70d50f shader: implement RDNA2 V_LSHLREV_B64 2026-08-23 16:39:01 +02:00
nmzik a8fe4e7a2d renderer: honor null pixel shaders in depth-only draws 2026-08-23 04:23:59 +02:00
nmzik bed19e5d8c shader: preserve concurrent subword buffer stores
Co-authored-by: Senaxx <Senaxx@users.noreply.github.com>
2026-08-23 03:53:47 +02:00
nmzik 4adbf40861 renderer: simplify dynamic params 2026-08-23 02:14:58 +02:00
nmzik 8d01fb1c18 shader: DS_READ_U16_D16, V_LSHRREV_B64, 2026-08-23 01:19:47 +02:00
nmzik a610528075 shader: V_CMPX_NE_I64 2026-08-23 00:59:44 +02:00
nmzik 3e25eb0998 Fix wave64 LDS synchronization on subgroup32 hosts 2026-08-23 00:46:37 +02:00
nmzik 0d92ce49da shader: support RDNA2 V_CMPX_NE_U64 2026-08-22 04:38:13 +02:00
nmzik 4179bb5b06 shader: route inner shared exits first 2026-08-22 04:00:37 +02:00
nmzik d581703ab4 shader: preserve folded control-flow values 2026-08-22 03:31:59 +02:00
nmzik 9241fdc32a shader: align float semantics with RDNA2 default mode 2026-08-22 03:16:45 +02:00
nmzik a2baaccc6e shader: fix auxiliary position exports 2026-08-22 02:58:35 +02:00
nmzik c130d74efc graphics: synthesize always-visible occlusion query results 2026-08-22 01:47:46 +02:00
nmzik 5e64efce4f graphics: support RDNA2 custom pixel interpolation
Co-authored-by: Senaxx <Senaxx@users.noreply.github.com>
2026-08-21 23:33:40 +02:00
nmzik 17c2b4cc7d fix regression TryReadBacking 2026-08-21 22:45:40 +02:00
nmzik bad6726f5e Rewrite descriptor bindings and unify graphics push constants 2026-08-21 22:28:10 +02:00
nmzik 26c4168160 refactor(renderer): simplify buffer and texture cache ownership 2026-08-21 20:11:38 +02:00
nmzik 49ea1680f8 graphics: use per-invocation shader masks 2026-08-21 08:03:22 +02:00
nmzik 79443aa104 shader: decode compressed UNORM16 MRT exports 2026-08-21 05:23:09 +02:00
nmzik 342fae06a6 graphics: name game Vulkan resources in debug dumps 2026-08-21 04:48:43 +02:00
nmzik 7022afa86e commandProcessor: WriteData fix 2026-08-21 03:32:49 +02:00
nmzik a44dd88806 agc: new ABI 2026-08-21 03:32:49 +02:00
nmzik d0a4c908a1 shader: align address-memory buffer bindings 2026-08-21 03:32:49 +02:00
nmzik 61dd8a3031 shader: accept byte-selected CNDMASK SDWA operands 2026-08-21 03:32:49 +02:00
nmzik 770bdb9571 shader: separate formatless storage from image atomics
Co-authored-by: shadowbeat070 <70843316+shadowbeat070@users.noreply.github.com>
Co-authored-by: Senaxx <Senaxx@users.noreply.github.com>
2026-08-21 03:32:49 +02:00
nmzik 719e20d470 shader: support bit-packed image surfaces 2026-08-21 03:32:49 +02:00
nmzik fedd1a4335 gpu: describe packed 11-11-10 uint textures 2026-08-21 03:32:49 +02:00
nmzik ebd47081ca agc: initialize interpolant mapping registers 2026-08-21 03:32:49 +02:00
nmzik 1546e93d67 gpu: handle native blend-color register writes 2026-08-21 03:32:49 +02:00
nmzik 94325b5ed6 launcher: window title fix 2026-08-21 03:32:49 +02:00
nmzik 86dbf89188 agc: emit native wait-on-address packets 2026-08-21 03:32:48 +02:00
nmzik f119e4baca gpu: handle partial guard-band register ranges 2026-08-21 03:32:48 +02:00
nmzik 494467406a gpu: route direct shader register ranges through handlers 2026-08-21 03:32:48 +02:00
nmzik 0966938dc8 shader: honor RDNA2 128-bit image descriptors 2026-08-21 03:32:48 +02:00
nmzik bc5709e1bd agc: new ABIs 2026-08-21 03:32:48 +02:00
nmzik 767d0b7da9 videoout: support PS5 auxiliary buses 2026-08-21 03:32:48 +02:00
nmzik d5410a93c8 graphics: preserve FP16 inline constants 2026-08-21 03:32:48 +02:00
nmzik 129c64235f graphics: implement RDNA2 D16 image packing 2026-08-21 03:32:48 +02:00
nmzik 1190d5de7d graphics: honor read-only stencil targets 2026-08-21 03:32:48 +02:00
nmzik 8021150ea2 graphics: preserve coherent layered depth layouts 2026-08-21 03:32:48 +02:00
nmzik 88c351f0fa shader: canonicalize SampleAdjust sampler scratch bits 2026-08-21 03:32:48 +02:00
nmzik e78bda60a0 graphics: accept texture-compatible FMASK metadata mode 2026-08-21 03:32:48 +02:00
nmzik 22bdafecbb graphics: preserve raw D16 uint texture reads 2026-08-21 03:32:48 +02:00
nmzik 6f9ed6ffe5 graphics: support depth targets with read-only backing 2026-08-21 03:32:48 +02:00
nmzik fbdc1e8714 shader: implement RDNA2 scalar quad-mask reduction 2026-08-21 03:32:48 +02:00
nmzik bac6bf65af renderdoc: fix 2026-08-21 03:32:48 +02:00
nmzik 5ad7d0ebc2 graphics: grow undersized render target backings 2026-08-21 03:32:48 +02:00
nmzik 7f66a61801 shader: reject rejoining early-exit routes 2026-08-21 03:32:48 +02:00
nmzik 2bd9f4124f shader: structurize nested early-exit tails 2026-08-21 03:32:48 +02:00
nmzik 705fc93363 shader: initialize compute EXEC from active subgroup 2026-08-21 03:32:48 +02:00
nmzik 77db9164b8 graphics: continue compute on native subgroup size 2026-08-21 03:32:48 +02:00
Senaxx a42e3bb09e graphics: derive compute wave size from dispatch mode 2026-08-21 03:32:48 +02:00
nmzik 69156b2f0e graphics: accept independent stencil mask writes 2026-08-21 03:32:48 +02:00
Senaxx 56a15c2036 Implement RDNA2 per-invocation scratch memory 2026-08-21 03:32:47 +02:00
nmzik 2db0b3cfa7 shader: fix shared-terminal selection merges 2026-08-21 03:32:47 +02:00
nmzik 41bfba515c shader: dump original RDNA2 binaries in graphics debug mode 2026-08-21 03:32:47 +02:00
nmzik 4710522e87 shader: canonicalize CFG loop headers 2026-08-21 03:32:47 +02:00
nmzik 85cf965d54 refactor(shader): centralize typed resource metadata 2026-08-21 03:32:47 +02:00
nmzik 87166eed94 refactor(shader): reduce dispatcher state overhead 2026-08-21 03:32:47 +02:00
nmzik 6e9f162bd4 refactor(shader): compact paired 64-bit lowering 2026-08-21 03:32:47 +02:00
nmzik 8063822243 refactor(shader): preserve native scalar memory operations 2026-08-21 03:32:47 +02:00
nmzik c236ba713d refactor(shader): preserve native wide shared operations 2026-08-21 03:32:47 +02:00
nmzik c9e942a972 refactor(shader): compact whole-quad mask lowering 2026-08-21 03:32:47 +02:00
nmzik 5383972e96 refactor(shader): preserve native wide buffer operations 2026-08-21 03:32:47 +02:00
nmzik 3ea2099245 refactor(shader): simplify buffer access emission 2026-08-21 03:32:47 +02:00
nmzik 49145c1902 refactor(shader): emit structured phis natively 2026-08-21 03:32:47 +02:00
nmzik d34e30d892 refactor(shader): emit SPIR-V declarations on demand 2026-08-21 03:32:47 +02:00
nmzik e1bcc298a0 refactor(shader): remove register-state compatibility paths 2026-08-21 03:32:47 +02:00
nmzik 33545ca6c4 test(shader): establish SPIR-V size baselines 2026-08-21 03:32:47 +02:00
nmzik 562f8a0895 fix(renderdoc): capture complete guest frames 2026-08-21 03:32:47 +02:00
Senaxx 7e42513faf perf(shader): cache analysis (#259)
perf(shader): cache SPIR-V requirement analysis

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-08-19 00:50:13 +02:00
nmzik 596ecdcca0 Fix shader CFG structurization for nested early exits 2026-08-19 00:14:51 +02:00
nmzik 5d83ce82af renderer: track and materialize deferred DCC clears
Co-authored-by: shadowbeat070 <70843316+shadowbeat070@users.noreply.github.com>
2026-08-18 19:10:36 +02:00
shadowbeat070 4fb72e9db7 graphics: add --gpu-assisted-validation and report fatal VkResults (#268)
* graphics: report the VkResult when a submit or fence wait fails

* graphics: add a --gpu-assisted-validation flag

* graphics: imply Vulkan validation for GPU-assisted validation

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-08-18 14:44:48 +02:00
Stefanos Costa c4ca8f4bf8 shader: fix the Linux and macOS build (#285)
* fixed linux build
- added correct uint long translation
-  replaced throw with non-constexpr function so that it fails in case of malformed table

* shader: remove redundant opcode table comment

* shader: use EXIT for invalid opcode tables

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-08-18 14:41:48 +02:00
Hashim Khan a4b970d97d launcher: explain unsupported mods-style patch JSON (#248)
When a _Patches file has no patches array (often a shadPS4/ETAHen mods
list), show a clear status instead of "Loaded 0 patch(es)". Fixes #174.
2026-08-18 14:22:40 +02:00
nmzik 8cfc9cd7a8 renderer: execute attachmentless PS side-effect draws 2026-08-18 14:03:36 +02:00
nmzik e39162fc52 shader: remove validation from program cache key 2026-08-18 14:03:36 +02:00
Hashim Khan 6bf69297c6 launcher: keep window open when game folder prompt is dismissed (#245)
Calling QApplication::quit() after the user closes the first-run game
folder dialog can segfault during nested modal shutdown. Leave the
launcher open so settings can still be configured. Fixes #121.
2026-08-18 04:18:56 +02:00
SoporteChilemat 95d282854d Build audio_out2_port_tests with kyty_tests (#242) 2026-08-18 04:08:16 +02:00
nmzik c59a4565bc renderer: simplify texture cache queries
Remove the duplicate texture page-overlap check and avoid shared-owner refcount traffic for already validated query candidates.
2026-08-18 03:53:45 +02:00
nmzik 79e424182b renderer: simplify image buffer owner lookup 2026-08-18 03:53:45 +02:00
nmzik fe867d03f6 renderer: remove duplicate buffer containment checks 2026-08-18 03:53:45 +02:00
nmzik ae4e695425 renderer: remove duplicate texture candidate checks 2026-08-18 03:53:45 +02:00
nmzik 6407add888 renderer: align texture overlap retirement 2026-08-18 03:53:45 +02:00
nmzik 840d742230 renderer: align buffer synchronization flow 2026-08-18 03:53:45 +02:00
nmzik a798e12d7f renderer: reuse buffer overlap merge for images 2026-08-18 03:53:45 +02:00
nmzik d80e914b34 renderer: align buffer overlap merging 2026-08-18 03:53:45 +02:00
nmzik 395c34ecab renderer: recreate insufficient texture cache matches 2026-08-18 03:53:45 +02:00
nmzik 1e8317159e renderer: align maybe-dirty image handling 2026-08-18 03:53:45 +02:00
nmzik d0e08496be renderer: handle clean DMA copies before overlap checks 2026-08-18 03:53:45 +02:00
nmzik 377fb8f50a shader: use ISA-style decoder opcode names 2026-08-18 03:53:45 +02:00
nmzik 4220a747cb libc: remove duplicate Mtx ABI implementations
No idea why these were reimplemented in the first place at all. The loaded guest libc already provides them; Kyty only needs the lower libkernel pthread imports.
2026-08-18 03:53:45 +02:00
nmzik e24f29d514 renderer: diagnostics 2026-08-18 03:53:45 +02:00
nmzik 54aa8efc98 libc: match PS5 mutex unlock result semantics
Co-authored-by: shadowbeat070 <70843316+shadowbeat070@users.noreply.github.com>
2026-08-18 03:53:45 +02:00
nmzik 89fdb1214a agc: ignore empty multi-DCB submissions
Co-authored-by: shadowbeat070 <70843316+shadowbeat070@users.noreply.github.com>
2026-08-18 03:53:45 +02:00
nmzik 01275fb211 shader_recompiler: rename/clean up typed SSA SPIR-V emitter 2026-08-18 03:53:45 +02:00
nmzik 5970c4ef95 shader_recompiler: remove legacy SPIR-V emitter 2026-08-18 03:53:44 +02:00
nmzik 24b40d4c03 renderer: add warning log 2026-08-18 03:53:44 +02:00
nmzik 146253afb6 renderer&guest_gpu: minor cleanup 2026-08-18 03:53:44 +02:00
nmzik c759236ccb renderer: support depth-compatible uint image views 2026-08-18 03:53:44 +02:00
nmzik ce39238210 renderer: preserve requested depth stencil view aspects 2026-08-18 03:53:44 +02:00
nmzik 330889e50b shader: implement RDNA2 frexp mantissa 2026-08-18 03:53:44 +02:00
nmzik 1be9568a02 shader: implement RDNA2 frexp exponent 2026-08-18 03:53:44 +02:00
nmzik 8ce06ccdf6 shader: route nested shared regions 2026-08-18 03:53:44 +02:00
nmzik 1dbac4fd79 shader: repair nested merge structurization 2026-08-18 03:53:44 +02:00
nmzik d80fbea51d shader: resolve subtractive dword SETPC tables 2026-08-18 03:53:44 +02:00
shadowbeat070 e239210279 Rewrite RenderDoc capture flow and host exceptions 2026-08-18 03:53:44 +02:00
nmzik e7c8bcb3a4 recompiler: deduplication cleanup 2026-08-18 03:53:44 +02:00
nmzik 0f3540b1ff shader: unify stage input metadata 2026-08-18 03:53:44 +02:00
nmzik 5ea92d95a7 add playgo hack 2026-08-18 03:53:44 +02:00
nmzik 5a32e270ad kernel: export scePthreadCancel 2026-08-18 03:53:44 +02:00
nmzik e857e332ac graphics: handle PS5 DMA_DATA prefetch 2026-08-18 03:53:44 +02:00
nmzik 44302cbf96 shader: implement RDNA2 V_MED3_I16 2026-08-18 03:53:44 +02:00
nmzik 6b306f64d5 graphics: execute valid PM4 rewind packets 2026-08-18 03:53:44 +02:00
nmzik e1366eb91d graphics: resolve Standard4KB color targets 2026-08-18 03:53:44 +02:00
nmzik 2a1a8e72e3 shader: preserve exec-masked FLAT address roots 2026-08-18 03:53:44 +02:00
nmzik 191cdff231 graphics: support tiled render target mip views 2026-08-18 03:53:43 +02:00
nmzik 7d8ee8b6b5 audio: provide live NGS2 system info 2026-08-18 03:53:43 +02:00
nmzik 01a1036640 audio: retire destroyed NGS2 racks 2026-08-18 03:53:43 +02:00
nmzik 7850cbeaef rename legacy Graphics -> Agc 2026-08-18 03:53:43 +02:00
nmzik af931d73c7 remove logging in hot path 2026-08-18 03:53:43 +02:00
nmzik 3a7cd93765 agc: ABIs fix - EventWrite/WriteData 2026-08-18 03:53:43 +02:00
nmzik a34bcbd951 agc: ABIs fix - acb/dcb 2026-08-18 03:53:43 +02:00
nmzik b0bd6470f3 graphics: accept AGC vertex-buffer-only shaders 2026-08-18 03:53:43 +02:00
nmzik 93398d6d0f graphics: sign-extend vector bitfield extracts 2026-08-18 03:53:43 +02:00
nmzik 4e343408dc graphics: size compute LDS from shader state 2026-08-18 03:53:43 +02:00
nmzik 1375d650a7 graphics: support RDNA2 dependency waits 2026-08-18 03:53:43 +02:00
nmzik d7f1bcaa19 graphics: support signed 16-bit integer packing 2026-08-18 03:53:43 +02:00
nmzik 2bb396f58f graphics: support SDWA arithmetic right shifts 2026-08-18 03:53:43 +02:00
nmzik af1ab60786 graphics: intersect texture views with resource mips 2026-08-18 03:53:43 +02:00
nmzik 430de9bd15 graphics: support dynamic indirect image tables 2026-08-18 03:53:43 +02:00
nmzik 1c4171c9eb graphics: accept SDWA byte conversion sources 2026-08-18 03:53:43 +02:00
nmzik 443bbcbf90 graphics: separate scalar address bindings 2026-08-18 03:53:43 +02:00
nmzik 83ee040b4d graphics: specialize invariant indirect image tables 2026-08-18 03:53:43 +02:00
Senaxx 980d89f739 graphics: support dynamic storage mip writes 2026-08-18 03:53:43 +02:00
Senaxx f785974cc1 graphics: accept storage mip ranges 2026-08-18 03:53:43 +02:00
nmzik 547b9b96cc graphics: upload sparse PRT image backing 2026-08-18 03:53:43 +02:00
nmzik 989477efad graphics: derive pixel stage activity from shader outputs 2026-08-18 03:53:43 +02:00
nmzik 6d273e4d9c graphics: accept forced HTile resummarization 2026-08-18 03:53:43 +02:00
Senaxx d7fd4a2864 graphics: accept asymmetric Z clip state 2026-08-18 03:53:42 +02:00
nmzik 5e27a28ab0 shader: fix missing homogeneous semantics 2026-08-18 03:53:42 +02:00
nmzik 67e550f2e7 agc: implement owner resource unregister 2026-08-18 03:53:42 +02:00
nmzik aec9b97b0c dialog: implement common dialog usage query 2026-08-18 03:53:42 +02:00
nmzik e4a95b2c26 playgo: reject missing package metadata 2026-08-18 03:53:42 +02:00
nmzik 6e82c376f6 kernel: allow renaming open save files 2026-08-18 03:53:42 +02:00
nmzik 4f1bc505cc graphics: support depth-tiled color targets 2026-08-18 03:53:42 +02:00
nmzik 484433b180 shader: fix V_ADD_NC_U32 2026-08-18 03:53:42 +02:00
nmzik 70f6af407e new ABI stubs 2026-08-18 03:53:42 +02:00
nmzik 7556a74f19 shader: implement s_bfe_i32 2026-08-18 03:53:42 +02:00
nmzik b4809e7170 Fix SPIR-V float control contract (Preserve FP32 Inf and NaN) 2026-08-18 03:53:42 +02:00
nmzik 0df20eb300 fix opcode regression 2026-08-18 03:53:42 +02:00
nmzik 5bfdf4267e Optimize decoder 2026-08-18 03:53:42 +02:00
nmzik f3cdf217ea shader: evaluate unsigned min in runtime descriptors 2026-08-18 03:53:42 +02:00
nmzik f453a752bb shader: snapshot wide SMEM sources before writes 2026-08-18 03:53:42 +02:00
nmzik 28a913894d graphics: implement RDNA2 64-bit first-set-bit 2026-08-18 03:53:42 +02:00
nmzik 0ffacf22e6 graphics: accept phi-mediated SRT cycles 2026-08-18 03:53:42 +02:00
nmzik 13e87a8e58 graphics: implement RDNA2 alignbyte shader opcode 2026-08-18 03:53:42 +02:00
nmzik 30d57bed06 graphics: honor primitive restart state 2026-08-18 03:53:42 +02:00
nmzik 965c30956d graphics: clamp storage buffers to committed memory 2026-08-18 03:53:42 +02:00
nmzik 09fec6815f shader: handle disabled RDNA2 traps 2026-08-18 03:53:42 +02:00
nmzik 00bd19194a shader: mask vector carry outputs by exec 2026-08-18 03:53:42 +02:00
nmzik 4a7bc55afa shader: implement RDNA2 subrev borrow 2026-08-18 03:53:42 +02:00
nmzik 9c316e6988 shader: implement RDNA2 v_cmp_gt_u64 2026-08-18 03:53:42 +02:00
nmzik a3c3cbb722 agc: fix async DMA data ABI 2026-08-18 03:53:42 +02:00
nmzik b42380ced6 shader_recompiler: add SSA 2026-08-18 03:53:41 +02:00
Hashim Khan bc2f077c37 launcher: quote emulator paths that contain spaces (#244)
* launcher: quote emulator paths that contain spaces

Run the Linux helper script as a bash file argument instead of bash -c,
and build a properly quoted cmd.exe /K command on Windows so install
folders like "Sony Playstation 5" still launch. Fixes #179.

* launcher: fix cmd command quoting

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-08-16 22:13:12 +02:00
Hashim Khan 498d63b620 docs: fix mismatched screenshot alt texts in README (#249)
Align Neptunia ReVerse, Hellboy, and Paleo Pines image alts with their
captions so screen readers and link previews describe the right titles.
2026-08-16 22:05:07 +02:00
Hashim Khan 566a45017e window: toggle borderless fullscreen with F11 and Alt+Enter (#246)
* window: toggle borderless fullscreen with F11 and Alt+Enter

Match the existing SDL_WINDOW_FULLSCREEN_DESKTOP startup path so testers
can switch modes at runtime. Reserve F11 in host input mappings. Fixes #217.

* window: consume fullscreen hotkey input

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-08-15 04:07:07 +02:00
nmzik 7a40dad90f agc: ABI fixes 2026-08-11 17:44:57 +02:00
nmzik a9e843b38e ci: link IME common code into dialog tests 2026-08-11 16:48:20 +02:00
nmzik 9a76719544 gpu: validate depth and cube texture descriptors
Accept SDK-valid depth sampler modulation and validate cube storage images as complete six-layer groups.
2026-08-11 16:45:32 +02:00
nmzik 472c8213db gpu: accept CB/DB release without GL2 writeback 2026-08-11 16:12:38 +02:00
nmzik a4f9c022ff ampr: make virtual address range query non-destructive 2026-08-11 16:12:38 +02:00
nmzik 97514884b1 Unify stack walking 2026-08-11 16:12:38 +02:00
nmzik 4980efa9b7 refactor(subsystems&ime): RAII lifecycle 2026-08-11 16:12:38 +02:00
nmzik 34cf130e4d Refactor PM4 control register decoding 2026-08-11 16:12:38 +02:00
nmzik 21aa7b66ce graphics: replace raw GPU enum values with typed formats 2026-08-11 16:12:38 +02:00
nmzik 11b95bed20 graphics: simplify render target format and color mapping resolution 2026-08-11 16:12:38 +02:00
Ali Almohaya ca7c8f0074 agc: fix linux build of gs oversubscription clamps (#232) 2026-08-11 07:38:22 +02:00
Pouare514 d7063d0b81 vulkan: remove validation layer configuration from device creation (#221)
* vulkan: remove validation layer configuration from device creation

* Remove accidental dependency gitlinks

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-08-09 23:05:31 +02:00
nmzik 091e6b31dc avplayer: decode media on bounded worker queues 2026-08-09 06:49:25 +02:00
nmzik 4cd6132758 gpu: allow byte-granular memory DMA 2026-08-09 05:31:18 +02:00
nmzik 9c263a9886 gpu: accept disabled default clip planes 2026-08-09 05:23:43 +02:00
nmzik c11fc96019 pad: accept system remote-control port 2026-08-09 05:15:40 +02:00
nmzik 4f2b5eb749 libSystemService fixes 2026-08-09 04:44:43 +02:00
nmzik d7013dc2b3 add left/right joystick remapping 2026-08-09 04:24:47 +02:00
nmzik 0bbe301120 add website/compatibility db 2026-08-09 04:08:32 +02:00
nmzik 37aa6f88b0 ime: implement libIme and shared host overlay 2026-08-09 02:58:49 +02:00
nmzik e3890febaa agc: new abi 2026-08-09 01:32:32 +02:00
nmzik a4da2a9f00 json2: implement typed Value constructor 2026-08-09 01:09:41 +02:00
nmzik 3005a210c6 renderer: ignore inactive HTile depth address 2026-08-08 23:55:45 +02:00
nmzik 027433fcdc Update game status report form 2026-08-08 21:19:22 +02:00
DeathWhispers 7ff9e4907f Don't declare colorWriteEnable dynamic state on depth-only pipelines (#160)
fix(gpu): drop colorWriteEnable dynamic state on depth-only pipelines

Pipelines were created with VK_DYNAMIC_STATE_COLOR_WRITE_ENABLE_EXT
unconditionally on non-Apple platforms, but the draw path only calls
vkCmdSetColorWriteEnableEXT when there is at least one color attachment.
A depth-only draw therefore reached vkCmdDrawIndexed with the dynamic
state declared and never set, which violates
VUID-vkCmdDrawIndexed-None-07749.

With validation enabled the error is fatal, so any title that issues a
depth-only pass aborts. The launcher enables validation by default
(vulkan_validation_enabled = true), so this is the default configuration:
PAC-MAN WORLD Re-PAC crashes from the launcher while the same build runs
normally with --vulkan-validation false.

Gate the declaration on the same color_count the draw path uses. Both
sides read state.color_count from the same draw, so the two conditions
are now identical by construction.
2026-08-08 08:21:18 +02:00
Stefanos Costa 87428d7a4b kernel: do not release a waiter on a zero-count syncOnAddress wake (linux only) (#168)
* kernel: do not release a waiter on a zero-count syncOnAddress wake

sceKernelSyncOnAddressWake with a count of 0 must release no waiters. On
Linux it released exactly one.

WakeLinux passes the count straight to FUTEX_WAKE, which does not treat 0
as "wake nobody": the kernel's wake loop tests `if (++ret >= nr_wake) break`
after waking a waiter, so any waiter present is released before the loop can
break. A standalone futex program confirms it -- FUTEX_WAKE with val = 0
returns 1, and the waiter observes its wait return 0 with the word unchanged.

WakePortable already short-circuits count == 0, so the two backends of the
same ABI disagreed, with only the Linux one wrong.

TestWakeZeroIsNoOp in SyncOnAddressTests covers exactly this and fails on
Linux without the fix (15 consecutive failures on the assertion "zero-count
wake releases no waiters"); with the fix the suite passes 15 consecutive runs.

* kernel: shorten zero-count futex comment

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-08-08 08:17:56 +02:00
Ali Almohaya 822ffba313 feat: identify build provenance in the crash log report (#196)
* feat: identify build provenance in the crash log report

* cmake: reuse git version dependency target

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-08-08 08:16:49 +02:00
Ali Almohaya 3c850b65c8 fix: stop a connected controller from disabling keyboard input (#194)
fix(input): stop a connected controller from disabling keyboard input
2026-08-08 08:05:52 +02:00
nmzik 698c9f802f renderer: remove global BufferCache locking 2026-08-08 08:02:35 +02:00
nmzik 1d5f3c8f66 gpu emulation: remove unnecessary Vulkan synchronization 2026-08-08 01:21:03 +02:00
nmzik ec78afb966 Revert "gpu: queue AGC suspend points"
This reverts commit 90bf3c9236.
2026-08-07 23:58:09 +02:00
nmzik 3a7656336e fix regression properly (fix pthread init abi) 2026-08-07 21:39:16 +02:00
nmzik 90bf3c9236 gpu: queue AGC suspend points 2026-08-07 21:02:31 +02:00
nmzik d4f8338937 renderer: lower masked stencil xor exactly 2026-08-07 19:13:21 +02:00
nmzik 5125cd09c7 growable command buffer pool 2026-08-07 18:26:42 +02:00
nmzik 67cfec9063 shader: remove redundant runtime descriptor provenance walks (perf) 2026-08-07 18:08:40 +02:00
nmzik 81e52df7bf precompute scissor rules (optimization) 2026-08-07 17:54:00 +02:00
nmzik 4b26d03dba fix pthread init abi 2026-08-07 17:51:59 +02:00
nmzik 216c580d13 perf: limit high-resolution sleep busy-waiting 2026-08-07 17:44:55 +02:00
nmzik 7907a50817 minor optimizations 2026-08-07 09:26:37 +02:00
nmzik 769edf470b allow partial releases 2026-08-07 05:32:17 +02:00
nmzik 68fffdfb66 fix macos build 2026-08-07 05:32:12 +02:00
nmzik 26781e6fea fix(windows): add experimental guest red-zone protection.
Port the static instruction patcher from shadPS4.
2026-08-07 05:19:14 +02:00
nmzik d5c95bc3ee kernel: coalesce fragmented Windows placeholders before reuse 2026-08-07 03:13:01 +02:00
nmzik ace549ab21 reduce complexity of buffer overlap detection 2026-08-06 23:46:47 +02:00
nmzik 0cbae39e41 remove double locking. small perf boost 2026-08-06 23:23:28 +02:00
nmzik e9f5da27f8 gpu: implement polygon offset
Co-authored-by: Pouare514 <julienaulycee@gmail.com>
2026-08-06 22:02:19 +02:00
nmzik 3052dac82e gpu: correct HS, PS, GS and compute resource register decoding 2026-08-06 21:21:47 +02:00
nmzik 2bb0483473 shader: add missing attributes 2026-08-06 20:32:14 +02:00
nmzik 389fd1e5be refactor gpu: consolidate texture tile layout calculations 2026-08-06 20:03:42 +02:00
nmzik a76f3ac2fe gpu_defs: add missing layouts 2026-08-06 18:18:07 +02:00
nmzik 2fc4855f29 fix renderDoc 2026-08-06 16:55:53 +02:00
nmzik 869329ee68 renderer: minor optimizations 2026-08-05 19:08:18 +02:00
nmzik b2963aa6e0 graphics: make DispatchDirect asynchronous 2026-08-05 14:49:45 +02:00
nmzik 9859b3e1d6 defer image refresh to final acquisition 2026-08-05 12:52:36 +02:00
nmzik cd19fa283f Implement IME dialog overlay 2026-08-05 05:14:16 +02:00
nmzik b6af7c73ec graphics: support Standard256B storage textures 2026-08-05 05:09:28 +02:00
nmzik ac64d202af shader: implement BUFFER_ATOMIC_FMAX 2026-08-05 02:59:28 +02:00
nmzik df44ad3fac shader: implement BUFFER_ATOMIC_FMIN, unhandled IR opcode now fails 2026-08-05 02:59:28 +02:00
nmzik 0a2f4814ac refactor(shader): centralize opcode metadata and lookup paths 2026-08-05 02:59:28 +02:00
nmzik e6b4707a5d renderer: support R8 uint render targets 2026-08-05 02:59:28 +02:00
nmzik 9a3468e3a0 shader: implement V_MIN_U32 2026-08-05 02:59:28 +02:00
nmzik 73da43a7be shader: implement V_CNDMASK_B32 2026-08-05 02:59:28 +02:00
nmzik aa88d94755 shader: implement V_SUB_NC_U32 2026-08-05 02:59:27 +02:00
nmzik 51562cd8d2 tests: use valid image descriptors in shader CFG cases 2026-08-05 02:59:27 +02:00
nmzik 822ca3c10b shader: implement S_CMP_EQ_U64 2026-08-05 02:59:27 +02:00
nmzik 2b6fd699e7 shader: implement V_CMP_EQ_I64 2026-08-05 02:59:27 +02:00
nmzik b9aa0dc3b3 fix KernelLseek lock leak
Co-authored-by: Stefanos Costa <stefanos.costa1999@gmail.com>
2026-08-05 02:25:05 +02:00
591 changed files with 180589 additions and 83652 deletions
+37
View File
@@ -0,0 +1,37 @@
# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json
# Keep inherited review profiles, automatic reviews, tools, and pre-merge checks.
inheritance: true
reviews:
# Trim supplemental output and keep the remaining walkthrough collapsed.
high_level_summary: false
review_status: false
review_details: false
collapse_walkthrough: true
changed_files_summary: false
sequence_diagrams: false
estimate_code_review_effort: false
related_issues: false
related_prs: false
in_progress_fortune: false
poem: false
enable_prompt_for_ai_agents: false
# Hide standard finishing-touch controls; this also disables their commands.
finishing_touches:
docstrings:
enabled: false
unit_tests:
enabled: false
simplify:
enabled: false
autofix:
enabled: false
fix_ci:
enabled: false
resolve_merge_conflict:
enabled: false
chat:
art: false
@@ -1,6 +1,6 @@
name: Game Emulation Bug Report
description: Report KytyPS5 game boot, crash, freeze, rendering, audio, input, or gameplay behavior problems.
title: "[GAME BUG]: "
name: Game Emulation Status Report
description: Submit a KytyPS5 game compatibility result, including boot, rendering, audio, input, or gameplay behavior.
title: "[GAME STATUS]: "
body:
- type: markdown
attributes:
@@ -10,6 +10,7 @@ body:
Before submitting, please:
- Search existing issues first.
- Re-test with a clean game dump.
- Use the latest KytyPS5 build available to you.
- Attach the complete log file instead of edited snippets.
- type: markdown
@@ -44,6 +45,28 @@ body:
validations:
required: true
- type: dropdown
id: compatibility-status
attributes:
label: Compatibility status
description: Select the furthest point the game consistently reaches on this build.
options:
- "Doesn't boot"
- Logo
- Main menu
- In game
validations:
required: true
- type: markdown
attributes:
value: |
**Status guide**
- **Doesn't boot:** The game does not show its first logo or startup screen.
- **Logo:** The game shows a logo or startup screen but does not reach the main menu.
- **Main menu:** The game reaches its menus but does not enter gameplay.
- **In game:** The game reaches controllable gameplay, even if bugs prevent completion.
- type: input
id: regression-builds
attributes:
@@ -54,22 +77,22 @@ body:
- type: markdown
attributes:
value: |
## Problem details
## Test result
- type: textarea
id: what-happened
attributes:
label: What happened?
description: Describe the failure or incorrect behavior as directly as possible.
placeholder: "Example: The game reaches the main menu, then freezes after selecting Continue."
label: Result details
description: Describe what worked, what failed, and any visible or audible problems.
placeholder: "Example: The game reaches the main menu, then freezes after selecting Continue. Audio plays correctly until the freeze."
validations:
required: true
- type: textarea
id: steps-to-reproduce
attributes:
label: Steps to reproduce
description: List the shortest path that triggers the problem from a fresh KytyPS5 start.
label: Steps to reproduce the result
description: List the shortest path to the reported status or failure from a fresh KytyPS5 start.
placeholder: |
1. Open KytyPS5.
2. Boot the game.
@@ -81,7 +104,7 @@ body:
id: expected-behavior
attributes:
label: Expected behavior
description: Explain what should happen at the same point in the game.
description: Explain what should happen at the same point in the game. If there is no known problem, write "No known issue".
placeholder: "Example: The save should load and gameplay should continue normally."
validations:
required: true
+146 -51
View File
@@ -6,7 +6,12 @@ on:
branches: [ main, master ]
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
env:
SCCACHE_GHA_ENABLED: "true"
KYTY_BUILD_ORIGIN: ${{ github.repository != 'KytyPS5/KytyPS5' && 'Fork' || github.event_name == 'push' && 'Official' || 'Source' }}
KYTY_BUILD_REPOSITORY: ${{ github.repository }}
@@ -38,9 +43,6 @@ jobs:
- name: Setup Visual Studio environment
uses: ilammy/msvc-dev-cmd@v1
- name: Setup Ninja
uses: seanmiddleditch/gha-setup-ninja@v5
- name: Locate vcpkg
id: vcpkg
shell: pwsh
@@ -78,6 +80,9 @@ jobs:
arch: win64_msvc2022_64
cache: true
- name: Setup sccache
uses: mozilla-actions/sccache-action@v0.0.11
- name: Verify toolchain
shell: cmd
run: |
@@ -100,17 +105,23 @@ jobs:
-DKYTY_RELEASE_TAG=${{ needs.metadata.outputs.release_tag }} ^
-DCMAKE_C_COMPILER=clang-cl ^
-DCMAKE_CXX_COMPILER=clang-cl ^
-DCMAKE_C_COMPILER_LAUNCHER=sccache ^
-DCMAKE_CXX_COMPILER_LAUNCHER=sccache ^
-DCMAKE_PREFIX_PATH="%Qt6_DIR%"
- name: Build
shell: cmd
run: |
cmake --build _Build/windows --target launcher audio_out2_port_tests virtual_memory_allocation_tests --parallel
cmake --build _Build/windows --target launcher ^
audio_out2_port_tests pad_haptics_tests controller_settings_tests host_input_tests ime_dialog_tests lru_cache_tests virtual_memory_allocation_tests ^
shader_recompiler_compute_tests ^
resource_tracking_tests scalar_provenance_tests ^
resource_materialization_tests shader_vertex_metadata_tests archive_file_tests avplayer_file_tests --parallel
- name: Test
shell: cmd
run: |
ctest --test-dir _Build/windows --output-on-failure -R "^(audio_out2_port|virtual_memory_allocation)$"
ctest --test-dir _Build/windows --output-on-failure -R "^(audio_out2_port|pad_haptics|controller_settings|host_input|ime_dialog|lru_cache|resource_tracking|scalar_provenance|resource_materialization|shader_vertex_metadata|archive_file|avplayer_file|virtual_memory_allocation)$"
- name: Install
shell: cmd
@@ -145,7 +156,7 @@ jobs:
- name: Install build dependencies
shell: bash
run: brew install glslang ninja
run: brew install glslang
- name: Install Qt 6.10.3
uses: jurplel/install-qt-action@v4
@@ -156,6 +167,9 @@ jobs:
arch: clang_64
cache: true
- name: Setup sccache
uses: mozilla-actions/sccache-action@v0.0.11
- name: Verify toolchain
shell: bash
run: |
@@ -180,20 +194,25 @@ jobs:
-DCMAKE_OSX_ARCHITECTURES=x86_64 \
-DCMAKE_C_COMPILER=clang \
-DCMAKE_CXX_COMPILER=clang++ \
-DCMAKE_C_COMPILER_LAUNCHER=sccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=sccache \
-DCMAKE_PREFIX_PATH="$QT_ROOT_DIR"
- name: Build
shell: bash
run: |
cmake --build _Build/macos \
--target launcher audio_out2_port_tests virtual_memory_allocation_tests \
--target launcher audio_out2_port_tests pad_haptics_tests controller_settings_tests host_input_tests ime_dialog_tests lru_cache_tests virtual_memory_allocation_tests \
memory_tracker_tests page_manager_tests shader_recompiler_compute_tests \
resource_tracking_tests scalar_provenance_tests \
resource_materialization_tests shader_vertex_metadata_tests archive_file_tests avplayer_file_tests \
--parallel
- name: Test
shell: bash
run: |
ctest --test-dir _Build/macos --output-on-failure \
-R '^(audio_out2_port|virtual_memory_allocation)$'
-R '^(audio_out2_port|pad_haptics|controller_settings|host_input|ime_dialog|lru_cache|memory_tracker|page_manager|resource_tracking|scalar_provenance|resource_materialization|shader_vertex_metadata|archive_file|avplayer_file|virtual_memory_allocation)$'
- name: Install
shell: bash
@@ -208,34 +227,68 @@ jobs:
run: |
archive="$RUNNER_TEMP/MoltenVK-macos.tar"
package="$RUNNER_TEMP/MoltenVK"
install_dir="_Build/macos/install"
app_dir="$install_dir/KytyPS5.app"
moltenvk="$install_dir/libMoltenVK.dylib"
curl --fail --location --retry 3 \
--output "$archive" \
"https://github.com/KhronosGroup/MoltenVK/releases/download/$MOLTENVK_VERSION/MoltenVK-macos.tar"
echo "$MOLTENVK_SHA256 $archive" | shasum -a 256 --check
tar -xf "$archive" -C "$RUNNER_TEMP"
test -d "$app_dir"
install -m 755 \
"$package/MoltenVK/dynamic/dylib/macOS/libMoltenVK.dylib" \
_Build/macos/install/libMoltenVK.dylib
install -m 644 "$package/LICENSE" _Build/macos/install/LICENSE.MoltenVK
codesign --force --sign - --timestamp=none _Build/macos/install/libMoltenVK.dylib
"$moltenvk"
install -m 644 "$package/LICENSE" "$install_dir/LICENSE.MoltenVK"
codesign --force --sign - --timestamp=none "$moltenvk"
install -d -m 755 "$app_dir/Contents/Frameworks" "$app_dir/Contents/Resources"
install -m 755 "$moltenvk" "$app_dir/Contents/Frameworks/libMoltenVK.dylib"
install -m 644 "$package/LICENSE" "$app_dir/Contents/Resources/LICENSE.MoltenVK"
codesign --force --sign - --timestamp=none "$app_dir"
- name: Verify artifacts
shell: bash
run: |
file _Build/macos/install/launcher
file _Build/macos/install/kyty_emulator
file _Build/macos/install/libMoltenVK.dylib
lipo _Build/macos/install/launcher -verify_arch x86_64
lipo _Build/macos/install/kyty_emulator -verify_arch x86_64
lipo _Build/macos/install/libMoltenVK.dylib -verify_arch x86_64
codesign --verify --strict _Build/macos/install/kyty_emulator
codesign --verify --strict _Build/macos/install/libMoltenVK.dylib
install_dir="_Build/macos/install"
app_dir="$install_dir/KytyPS5.app"
test -d "$app_dir"
for binary in \
"$install_dir/kyty_emulator" \
"$install_dir/libMoltenVK.dylib" \
"$app_dir/Contents/MacOS/KytyPS5" \
"$app_dir/Contents/MacOS/kyty_emulator" \
"$app_dir/Contents/MacOS/kyty_updater" \
"$app_dir/Contents/Frameworks/libMoltenVK.dylib"; do
file "$binary"
lipo "$binary" -verify_arch x86_64
done
for binary in \
"$install_dir/kyty_emulator" \
"$install_dir/libMoltenVK.dylib" \
"$app_dir/Contents/MacOS/KytyPS5" \
"$app_dir/Contents/MacOS/kyty_emulator" \
"$app_dir/Contents/MacOS/kyty_updater" \
"$app_dir/Contents/Frameworks/libMoltenVK.dylib"; do
codesign --verify --strict "$binary"
done
codesign --verify --deep --strict --verbose=2 "$app_dir"
- name: Package macOS artifacts
shell: bash
run: |
install_dir="_Build/macos/install"
archive="$RUNNER_TEMP/KytyPS5-macOS-x86_64.zip"
(
cd "$install_dir"
zip -qry "$archive" .
)
unzip -t "$archive"
- name: Upload macOS artifacts
uses: actions/upload-artifact@v4
with:
name: KytyPS5-macOS-x86_64
path: _Build/macos/install/**
path: ${{ runner.temp }}/KytyPS5-macOS-x86_64.zip
if-no-files-found: error
linux:
@@ -270,8 +323,9 @@ jobs:
libxkbcommon-dev \
libxrandr-dev \
libxss-dev \
libxtst-dev \
lld \
ninja-build \
pkg-config \
wayland-protocols
- name: Install Qt 6.10.3
@@ -283,6 +337,9 @@ jobs:
arch: linux_gcc_64
cache: true
- name: Setup sccache
uses: mozilla-actions/sccache-action@v0.0.11
- name: Verify toolchain
shell: bash
run: |
@@ -307,10 +364,12 @@ jobs:
-DKYTY_RELEASE_TAG="${{ needs.metadata.outputs.release_tag }}" \
-DCMAKE_C_COMPILER=clang \
-DCMAKE_CXX_COMPILER=clang++ \
-DCMAKE_C_COMPILER_LAUNCHER=sccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=sccache \
-DCMAKE_PREFIX_PATH="$Qt6_DIR" 2>&1 | tee _Build/configure.log
exit "${PIPESTATUS[0]}"
- name: Verify SDL2 backends
- name: Verify SDL3 backends
shell: bash
run: |
status=0
@@ -329,14 +388,16 @@ jobs:
run: |
cmake --build _Build/linux \
--target launcher page_manager_tests memory_tracker_tests \
audio_out2_port_tests virtual_memory_allocation_tests \
audio_out2_port_tests pad_haptics_tests controller_settings_tests host_input_tests ime_dialog_tests lru_cache_tests virtual_memory_allocation_tests \
resource_tracking_tests scalar_provenance_tests \
resource_materialization_tests shader_vertex_metadata_tests archive_file_tests avplayer_file_tests \
--parallel
- name: Test
shell: bash
run: |
ctest --test-dir _Build/linux --output-on-failure \
-R '^(audio_out2_port|page_manager|memory_tracker|virtual_memory_allocation)$'
-R '^(audio_out2_port|pad_haptics|controller_settings|host_input|ime_dialog|lru_cache|memory_tracker|page_manager|resource_tracking|scalar_provenance|resource_materialization|shader_vertex_metadata|archive_file|avplayer_file|virtual_memory_allocation)$'
- name: Install
shell: bash
@@ -346,11 +407,12 @@ jobs:
- name: Verify artifacts
shell: bash
run: |
file _Build/linux/install/launcher
file _Build/linux/install/kyty_launcher
file _Build/linux/install/kyty_emulator
test -x _Build/linux/install/kyty_updater
file _Build/linux/install/kyty_emulator | grep -q "ELF 64-bit LSB .*x86-64"
ldd _Build/linux/install/kyty_emulator > /dev/null
readelf -d _Build/linux/install/launcher | grep -q 'RPATH.*\$ORIGIN/lib'
readelf -d _Build/linux/install/kyty_launcher | grep -q 'RPATH.*\$ORIGIN/lib'
while IFS= read -r -d '' binary; do
while read -r dependency; do
test -e "_Build/linux/install/lib/$dependency"
@@ -359,8 +421,8 @@ jobs:
sed -n 's/.*Shared library: \[\(libQt6[^]]*\|libicu[^]]*\)\].*/\1/p'
)
done < <(
find _Build/linux/install/launcher _Build/linux/install/plugins \
-type f \( -name launcher -o -name '*.so' \) -print0
find _Build/linux/install/kyty_launcher _Build/linux/install/plugins \
-type f \( -name kyty_launcher -o -name '*.so' \) -print0
)
_Build/linux/install/kyty_emulator --help > /dev/null
@@ -373,7 +435,13 @@ jobs:
release:
name: Release KytyPS5
if: github.event_name == 'push' && github.repository == 'KytyPS5/KytyPS5'
if: >-
always() &&
github.event_name == 'push' &&
github.repository == 'KytyPS5/KytyPS5' &&
(needs.windows.result == 'success' ||
needs.macos.result == 'success' ||
needs.linux.result == 'success')
needs: [metadata, windows, macos, linux]
runs-on: ubuntu-latest
permissions:
@@ -382,34 +450,56 @@ jobs:
RELEASE_NAME: ${{ needs.metadata.outputs.release_tag }}
steps:
- name: Download builds
- name: Download Windows build
if: needs.windows.result == 'success'
uses: actions/download-artifact@v4
with:
path: artifacts
name: KytyPS5-Windows-x64
path: artifacts/KytyPS5-Windows-x64
- name: Package builds
- name: Download macOS build
if: needs.macos.result == 'success'
uses: actions/download-artifact@v4
with:
name: KytyPS5-macOS-x86_64
path: artifacts/KytyPS5-macOS-x86_64
- name: Download Linux build
if: needs.linux.result == 'success'
uses: actions/download-artifact@v4
with:
name: KytyPS5-Linux-x86_64
path: artifacts/KytyPS5-Linux-x86_64
- name: Package Windows build
if: needs.windows.result == 'success'
shell: bash
run: |
windows_dir="artifacts/KytyPS5-Windows-x64"
macos_dir="artifacts/KytyPS5-macOS-x86_64"
linux_dir="artifacts/KytyPS5-Linux-x86_64"
test -d "$windows_dir"
test -d "$macos_dir"
test -d "$linux_dir"
chmod a+x \
"$macos_dir/launcher" \
"$macos_dir/kyty_emulator" \
"$macos_dir/libMoltenVK.dylib" \
"$linux_dir/launcher" \
"$linux_dir/kyty_emulator"
(
cd "$windows_dir"
zip -r "$GITHUB_WORKSPACE/$RELEASE_NAME-Windows-x64.zip" .
)
(
cd "$macos_dir"
zip -r "$GITHUB_WORKSPACE/$RELEASE_NAME-macOS-x86_64.zip" .
)
- name: Package macOS build
if: needs.macos.result == 'success'
shell: bash
run: |
macos_archive="artifacts/KytyPS5-macOS-x86_64/KytyPS5-macOS-x86_64.zip"
test -f "$macos_archive"
cp "$macos_archive" "$RELEASE_NAME-macOS-x86_64.zip"
- name: Package Linux build
if: needs.linux.result == 'success'
shell: bash
run: |
linux_dir="artifacts/KytyPS5-Linux-x86_64"
test -d "$linux_dir"
chmod a+x \
"$linux_dir/kyty_launcher" \
"$linux_dir/kyty_emulator" \
"$linux_dir/kyty_updater"
tar -C "$linux_dir" -czf \
"$GITHUB_WORKSPACE/$RELEASE_NAME-Linux-x86_64.tar.gz" .
@@ -418,11 +508,16 @@ jobs:
env:
GH_TOKEN: ${{ github.token }}
run: |
assets=(
"$RELEASE_NAME-Windows-x64.zip"
"$RELEASE_NAME-macOS-x86_64.zip"
"$RELEASE_NAME-Linux-x86_64.tar.gz"
)
assets=()
for artifact in \
"$RELEASE_NAME-Windows-x64.zip" \
"$RELEASE_NAME-macOS-x86_64.zip" \
"$RELEASE_NAME-Linux-x86_64.tar.gz"; do
if [[ -f "$artifact" ]]; then
assets+=("$artifact")
fi
done
test "${#assets[@]}" -gt 0
if gh release view "$RELEASE_NAME" --repo "$GITHUB_REPOSITORY" > /dev/null 2>&1; then
gh release upload "$RELEASE_NAME" "${assets[@]}" \
--clobber \
+1
View File
@@ -5,3 +5,4 @@ build/
_Build/vscode-clang/
_Build/
cmake-build-debug/
_PipelineCache/
+7 -4
View File
@@ -1,7 +1,7 @@
[submodule "3rdparty/SDL2"]
path = 3rdparty/SDL2
[submodule "3rdparty/SDL3"]
path = 3rdparty/SDL3
url = https://github.com/libsdl-org/SDL.git
branch = SDL2
branch = release-3.4.x
[submodule "3rdparty/magic_enum"]
path = 3rdparty/magic_enum
url = https://github.com/Neargye/magic_enum.git
@@ -22,7 +22,7 @@
url = https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git
[submodule "3rdparty/ffmpeg-core"]
path = 3rdparty/ffmpeg-core
url = https://github.com/shadps4-emu/ext-ffmpeg-core.git
url = https://github.com/KytyPS5/ext-ffmpeg-core.git
shallow = true
[submodule "3rdparty/fmt"]
path = 3rdparty/fmt
@@ -39,3 +39,6 @@
[submodule "3rdparty/nlohmann_json"]
path = 3rdparty/nlohmann_json
url = https://github.com/nlohmann/json.git
[submodule "3rdparty/imgui"]
path = 3rdparty/imgui
url = https://github.com/ocornut/imgui.git
+38 -4
View File
@@ -5,12 +5,19 @@
"name": "Debug launcher UI",
"type": "cppvsdbg",
"request": "launch",
"program": "${workspaceFolder}\\_Build\\vscode-clang\\launcher\\launcher.exe",
"program": "${workspaceFolder}\\_Build\\vscode-clang\\launcher\\kyty_launcher.exe",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}\\_Build\\vscode-clang\\launcher",
"environment": [],
"externalConsole": false
"externalConsole": false,
"linux": {
"type": "cppdbg",
"program": "${workspaceFolder}/_Build/vscode-clang/launcher/kyty_launcher",
"cwd": "${workspaceFolder}/_Build/vscode-clang/launcher",
"MIMode": "gdb",
"miDebuggerPath": "/usr/bin/gdb"
}
},
{
"name": "Debug kyty_emulator",
@@ -25,13 +32,40 @@
"stopAtEntry": false,
"cwd": "${workspaceFolder}\\_Build\\vscode-clang",
"environment": [],
"externalConsole": true
"externalConsole": true,
"linux": {
"type": "cppdbg",
"program": "${workspaceFolder}/_Build/vscode-clang/kyty_emulator",
"cwd": "${workspaceFolder}/_Build/vscode-clang",
"externalConsole": false,
"MIMode": "gdb",
"miDebuggerPath": "/usr/bin/gdb",
"setupCommands": [
{
"description": "Pass Kyty's internal signals to its handlers",
"text": "handle SIG37 SIGSEGV SIGBUS SIGILL nostop noprint pass",
"ignoreFailures": false
}
]
}
},
{
"name": "Attach to running kyty_emulator",
"type": "cppvsdbg",
"request": "attach",
"processId": "${command:pickProcess}"
"processId": "${command:pickProcess}",
"linux": {
"type": "cppdbg",
"MIMode": "gdb",
"miDebuggerPath": "/usr/bin/gdb",
"setupCommands": [
{
"description": "Pass Kyty's internal signals to its handlers",
"text": "handle SIG37 SIGSEGV SIGBUS SIGILL nostop noprint pass",
"ignoreFailures": false
}
]
}
}
]
}
+6 -4
View File
@@ -2,15 +2,17 @@
"cmake.sourceDirectory": "${workspaceFolder}",
"cmake.buildDirectory": "${workspaceFolder}/_Build/vscode-clang",
"cmake.generator": "Ninja",
"cmake.useVsDeveloperEnvironment": "always",
"cmake.environment": {
"CC": "clang-cl",
"CXX": "clang-cl",
"PATH": "${env:ProgramFiles}/Microsoft Visual Studio/18/Community/VC/Tools/Llvm/x64/bin;${env:ProgramFiles}/Microsoft Visual Studio/18/Community/Common7/IDE/CommonExtensions/Microsoft/CMake/Ninja;${env:PATH}"
"CXX": "clang-cl"
},
"cmake.configureSettings": {
"CMAKE_C_COMPILER": "clang-cl",
"CMAKE_CXX_COMPILER": "clang-cl",
"CMAKE_PREFIX_PATH": "C:/Qt/6.11.0/msvc2022_64"
}
},
"C_Cpp.default.intelliSenseMode": "windows-clang-x64",
"C_Cpp.default.compileCommands": "${workspaceFolder}/_Build/vscode-clang/compile_commands.json",
"C_Cpp.default.cppStandard": "c++20"
}
+119 -1
View File
@@ -2,8 +2,103 @@ set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
add_subdirectory(cpuinfo)
include(FetchContent)
# The Bluetooth DualSense transports speaker audio as fixed-size Opus packets.
set(kyty_build_testing_saved "${BUILD_TESTING}")
set(BUILD_TESTING OFF)
set(OPUS_BUILD_PROGRAMS OFF CACHE BOOL "" FORCE)
set(OPUS_INSTALL_PKG_CONFIG_MODULE OFF CACHE BOOL "" FORCE)
set(OPUS_INSTALL_CMAKE_CONFIG_MODULE OFF CACHE BOOL "" FORCE)
if(MSVC AND CMAKE_C_COMPILER_ID STREQUAL "Clang")
# Opus assumes MSVC accepts SSE4.1 intrinsics without per-file flags, but
# clang-cl rejects them in its baseline x64 files. Its AVX2 dispatch also
# depends on the SSE4.1 declarations, so retain the x64 SSE2 baseline only.
set(OPUS_X86_MAY_HAVE_SSE4_1 OFF CACHE BOOL "" FORCE)
set(OPUS_X86_MAY_HAVE_AVX2 OFF CACHE BOOL "" FORCE)
endif()
FetchContent_Declare(opus
GIT_REPOSITORY https://github.com/xiph/opus.git
GIT_TAG ddbe48383984d56acd9e1ab6a090c54ca6b735a6
GIT_SHALLOW FALSE)
FetchContent_MakeAvailable(opus)
set(BUILD_TESTING "${kyty_build_testing_saved}")
install(FILES "${opus_SOURCE_DIR}/COPYING" DESTINATION "licenses/opus")
# The guest instruction patcher needs a decoder/encoder and a small
# trampoline assembler. Pin the same revisions used by shadPS4's implementation.
set(XBYAK_BUILD_TESTS OFF CACHE BOOL "" FORCE)
FetchContent_Declare(
xbyak
GIT_REPOSITORY https://github.com/herumi/xbyak.git
GIT_TAG 44a72f369268f7d552650891b296693e91db86bb
GIT_SHALLOW FALSE
)
set(ZYDIS_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
set(ZYDIS_BUILD_TOOLS OFF CACHE BOOL "" FORCE)
set(ZYDIS_BUILD_TESTS OFF CACHE BOOL "" FORCE)
set(ZYDIS_BUILD_DOXYGEN OFF CACHE BOOL "" FORCE)
FetchContent_Declare(
zydis
GIT_REPOSITORY https://github.com/zyantific/zydis.git
GIT_TAG 120e0e705f8e3b507dc49377ac2879979f0d545c
GIT_SUBMODULES_RECURSE TRUE
GIT_SHALLOW FALSE
)
FetchContent_MakeAvailable(xbyak zydis)
target_compile_definitions(xbyak INTERFACE XBYAK_NO_EXCEPTION)
# ZArchive provides random-access reads for compressed game dumps. Build only
# the reader/writer library and its zstd dependency; the command-line tool is
# not part of KytyPS5's runtime distribution.
set(ZSTD_BUILD_PROGRAMS OFF CACHE BOOL "" FORCE)
set(ZSTD_BUILD_SHARED OFF CACHE BOOL "" FORCE)
set(ZSTD_BUILD_STATIC ON CACHE BOOL "" FORCE)
set(ZSTD_BUILD_TESTS OFF CACHE BOOL "" FORCE)
set(ZSTD_LEGACY_SUPPORT OFF CACHE BOOL "" FORCE)
set(ZSTD_MULTITHREAD_SUPPORT OFF CACHE BOOL "" FORCE)
FetchContent_Declare(
zstd
GIT_REPOSITORY https://github.com/facebook/zstd.git
GIT_TAG f8745da6ff1ad1e7bab384bd1f9d742439278e99
GIT_SHALLOW FALSE
SOURCE_SUBDIR build/cmake
)
FetchContent_Declare(
zarchive_source
GIT_REPOSITORY https://github.com/Exzap/ZArchive.git
GIT_TAG d2c717730092c7bf8cbb033b12fd4001b7c4d932
GIT_SHALLOW FALSE
PATCH_COMMAND "${GIT_EXECUTABLE}" apply --ignore-whitespace
"${CMAKE_CURRENT_SOURCE_DIR}/patches/zarchive-reader.patch"
SOURCE_SUBDIR kyty-library-only
)
FetchContent_MakeAvailable(zstd zarchive_source)
add_library(zarchive STATIC
"${zarchive_source_SOURCE_DIR}/src/zarchivereader.cpp"
"${zarchive_source_SOURCE_DIR}/src/zarchivewriter.cpp"
"${zarchive_source_SOURCE_DIR}/src/sha_256.c"
)
add_library(ZArchive::zarchive ALIAS zarchive)
target_include_directories(zarchive SYSTEM PUBLIC "${zarchive_source_SOURCE_DIR}/include")
target_include_directories(zarchive PRIVATE "${zstd_SOURCE_DIR}/lib")
target_link_libraries(zarchive PRIVATE libzstd_static)
target_compile_features(zarchive PRIVATE cxx_std_20)
if(MSVC)
target_compile_options(zarchive PRIVATE /W0)
else()
target_compile_options(zarchive PRIVATE -w)
endif()
set(SDL_SHARED OFF CACHE BOOL "" FORCE)
add_subdirectory(SDL2)
if(APPLE)
# SDL's built-in iconv fallback does not support CP932.
set(SDL_SYSTEM_ICONV ON CACHE BOOL "Use system iconv for CP932 conversion" FORCE)
endif()
add_subdirectory(SDL3)
add_library(Vulkan-Headers INTERFACE)
add_library(Vulkan::Headers ALIAS Vulkan-Headers)
@@ -11,6 +106,25 @@ target_include_directories(Vulkan-Headers INTERFACE
"${CMAKE_CURRENT_SOURCE_DIR}/Vulkan-Headers/include"
)
add_library(imgui STATIC
imgui/imgui.cpp
imgui/imgui_draw.cpp
imgui/imgui_tables.cpp
imgui/imgui_widgets.cpp
imgui/backends/imgui_impl_vulkan.cpp
)
target_include_directories(imgui PUBLIC
"${CMAKE_CURRENT_SOURCE_DIR}/imgui"
"${CMAKE_CURRENT_SOURCE_DIR}/imgui/backends"
)
target_compile_definitions(imgui PRIVATE IMGUI_IMPL_VULKAN_NO_PROTOTYPES)
target_link_libraries(imgui PUBLIC Vulkan::Headers)
if(MSVC)
target_compile_options(imgui PRIVATE /W0)
else()
target_compile_options(imgui PRIVATE -w)
endif()
set(SPIRV_SKIP_TESTS ON CACHE BOOL "" FORCE)
set(SPIRV_SKIP_EXECUTABLES ON CACHE BOOL "" FORCE)
set(SKIP_SPIRV_TOOLS_INSTALL ON CACHE BOOL "" FORCE)
@@ -41,6 +155,9 @@ set(SPDLOG_BUILD_WARNINGS OFF CACHE BOOL "" FORCE)
set(SPDLOG_INSTALL OFF CACHE BOOL "" FORCE)
set(SPDLOG_FMT_EXTERNAL ON CACHE BOOL "" FORCE)
set(SPDLOG_NO_EXCEPTIONS ON CACHE BOOL "" FORCE)
if(WIN32)
set(SPDLOG_WCHAR_FILENAMES ON CACHE BOOL "" FORCE)
endif()
add_subdirectory(spdlog EXCLUDE_FROM_ALL)
if (NOT TARGET FFmpeg::ffmpeg)
@@ -72,6 +189,7 @@ endif()
set(TRACY_STATIC ON CACHE BOOL "" FORCE)
set(TRACY_ENABLE ON CACHE BOOL "" FORCE)
set(TRACY_NO_CRASH_HANDLER ON CACHE BOOL "" FORCE)
set(TRACY_ON_DEMAND ON CACHE BOOL "" FORCE)
set(TRACY_DELAYED_INIT ON CACHE BOOL "" FORCE)
set(TRACY_MANUAL_LIFETIME ON CACHE BOOL "" FORCE)
-1
Submodule 3rdparty/SDL2 deleted from 4b69833bc5
Vendored Submodule
+1
Submodule 3rdparty/SDL3 added at fa2c02bb6e
+1 -1
View File
@@ -14,7 +14,7 @@
#include <cpuinfo/internal-api.h>
#include <cpuinfo/log.h>
/* Polyfill recent CPUFAMILY_ARM_* values for older SDKs */
/* Polyfill recent CPUFAMILY_ARM_* values for older platform headers */
#ifndef CPUFAMILY_ARM_MONSOON_MISTRAL
#define CPUFAMILY_ARM_MONSOON_MISTRAL 0xE81E7EF6
#endif
Vendored Submodule
+1
Submodule 3rdparty/imgui added at f1cc2ae15e
+100
View File
@@ -0,0 +1,100 @@
--- a/include/zarchive/zarchivecommon.h
+++ b/include/zarchive/zarchivecommon.h
@@ -256,7 +256,7 @@
bool IsWithinValidRange(uint64_t fileSize) const
{
- return (offset + size) <= fileSize;
+ return offset <= fileSize && size <= fileSize - offset;
}
};
--- a/src/zarchivereader.cpp
+++ b/src/zarchivereader.cpp
@@ -14,6 +14,7 @@
static bool _ifstream_readBytes(std::ifstream& file, uint64_t offset, void* buffer, uint32_t size)
{
+ file.clear();
file.seekg(offset, std::ios_base::beg);
file.read((char*)buffer, size);
return file.gcount() == size;
@@ -80,9 +81,27 @@
// verify file tree
if (fileTree[0].IsFile())
return nullptr; // first entry must be root directory
- auto rootName = GetName(nameTable, fileTree[0].GetNameOffset());
- if (!rootName.empty())
+ if (fileTree[0].GetNameOffset() != 0x7FFFFFFF)
return nullptr; // root node must not have a name
+ const uint64_t dataCapacity = (uint64_t)offsetRecords.size() * _ZARCHIVE::ENTRIES_PER_OFFSETRECORD * _ZARCHIVE::COMPRESSED_BLOCK_SIZE;
+ for (size_t i = 0; i < fileTree.size(); ++i)
+ {
+ auto& entry = fileTree[i];
+ if (i != 0)
+ {
+ auto name = GetName(nameTable, entry.GetNameOffset());
+ if (name.empty() || name == "." || name == ".." || name.find_first_of("/\\") != std::string_view::npos || name.find('\0') != std::string_view::npos)
+ return nullptr;
+ }
+ if (entry.IsFile())
+ {
+ if (entry.GetFileOffset() > dataCapacity || entry.GetFileSize() > dataCapacity - entry.GetFileOffset())
+ return nullptr;
+ }
+ else if (entry.directoryRecord.nodeStartIndex > fileTree.size() ||
+ entry.directoryRecord.count > fileTree.size() - entry.directoryRecord.nodeStartIndex)
+ return nullptr;
+ }
// read meta data
// todo
@@ -238,7 +257,7 @@
uint32_t stepSize = std::min<uint32_t>(remainingBytes, _ZARCHIVE::COMPRESSED_BLOCK_SIZE - blockOffset);
CacheBlock* block = GetCachedBlock(blockIdx);
if (!block)
- return 0;
+ return bytesToRead - remainingBytes;
std::memcpy(bufferU8, block->data + blockOffset, stepSize);
rawReadOffset += stepSize;
remainingBytes -= stepSize;
@@ -325,14 +344,18 @@
// determine offset and size of compressed block
auto& record = m_offsetRecords[recordIndex];
uint64_t offset = record.baseOffset;
+ if (offset > m_compressedDataSize)
+ return false;
for (uint32_t i = 0; i < recordSubIndex; i++)
{
- offset += (uint64_t)record.size[i];
- offset++;
+ const uint64_t size = (uint64_t)record.size[i] + 1;
+ if (size > m_compressedDataSize - offset)
+ return false;
+ offset += size;
}
uint32_t compressedSize = (uint32_t)record.size[recordSubIndex] + 1;
// load file data
- if ((offset + compressedSize) > m_compressedDataSize)
+ if (compressedSize > m_compressedDataSize - offset)
return false;
offset += m_compressedDataOffset;
if (compressedSize == _ZARCHIVE::COMPRESSED_BLOCK_SIZE)
@@ -350,7 +373,7 @@
// returns empty view on failure
std::string_view ZArchiveReader::GetName(const std::vector<uint8_t>& nameTable, uint32_t nameOffset)
{
- if (nameOffset == 0x7FFFFFFF || nameOffset > nameTable.size())
+ if (nameOffset == 0x7FFFFFFF || nameOffset >= nameTable.size())
return "";
// parse header
uint16_t nameLength = nameTable[nameOffset] & 0x7F;
@@ -359,7 +382,7 @@
// extended 2-byte length
if (nameOffset + 1 >= nameTable.size())
return "";
- nameLength |= ((uint16_t)nameTable[nameOffset] << 7);
+ nameLength |= ((uint16_t)nameTable[nameOffset + 1] << 7);
nameOffset += 2;
}
else
+875
View File
@@ -0,0 +1,875 @@
/******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2015-2026 Baldur Karlsson
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
#pragma once
//////////////////////////////////////////////////////////////////////////////////////////////////
//
// Documentation for the API is available at https://renderdoc.org/docs/in_application_api.html
//
#if !defined(RENDERDOC_NO_STDINT)
#include <stdint.h>
#endif
#if defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER)
#define RENDERDOC_CC __cdecl
#elif defined(__linux__) || defined(__FreeBSD__) || defined(__sun__) || defined(__OpenBSD__)
#define RENDERDOC_CC
#elif defined(__APPLE__)
#define RENDERDOC_CC
#else
#error "Unknown platform"
#endif
#ifdef __cplusplus
extern "C" {
#endif
//////////////////////////////////////////////////////////////////////////////////////////////////
// Constants not used directly in below API
// This is a GUID/magic value used for when applications pass a path where shader debug
// information can be found to match up with a stripped shader.
// the define can be used like so: const GUID RENDERDOC_ShaderDebugMagicValue =
// RENDERDOC_ShaderDebugMagicValue_value
#define RENDERDOC_ShaderDebugMagicValue_struct \
{ \
0xeab25520, 0x6670, 0x4865, 0x84, 0x29, 0x6c, 0x8, 0x51, 0x54, 0x00, 0xff \
}
// as an alternative when you want a byte array (assuming x86 endianness):
#define RENDERDOC_ShaderDebugMagicValue_bytearray \
{ \
0x20, 0x55, 0xb2, 0xea, 0x70, 0x66, 0x65, 0x48, 0x84, 0x29, 0x6c, 0x8, 0x51, 0x54, 0x00, 0xff \
}
// truncated version when only a uint64_t is available (e.g. Vulkan tags):
#define RENDERDOC_ShaderDebugMagicValue_truncated 0x48656670eab25520ULL
// this is a magic value for vulkan user tags to indicate which dispatchable API objects are which
// for object annotations
#define RENDERDOC_APIObjectAnnotationHelper 0xfbb3b337b664d0adULL
//////////////////////////////////////////////////////////////////////////////////////////////////
// RenderDoc capture options
//
typedef enum RENDERDOC_CaptureOption
{
// Allow the application to enable vsync
//
// Default - enabled
//
// 1 - The application can enable or disable vsync at will
// 0 - vsync is force disabled
eRENDERDOC_Option_AllowVSync = 0,
// Allow the application to enable fullscreen
//
// Default - enabled
//
// 1 - The application can enable or disable fullscreen at will
// 0 - fullscreen is force disabled
eRENDERDOC_Option_AllowFullscreen = 1,
// Record API debugging events and messages
//
// Default - disabled
//
// 1 - Enable built-in API debugging features and records the results into
// the capture, which is matched up with events on replay
// 0 - no API debugging is forcibly enabled
eRENDERDOC_Option_APIValidation = 2,
eRENDERDOC_Option_DebugDeviceMode = 2, // deprecated name of this enum
// Capture CPU callstacks for API events
//
// Default - disabled
//
// 1 - Enables capturing of callstacks
// 0 - no callstacks are captured
eRENDERDOC_Option_CaptureCallstacks = 3,
// When capturing CPU callstacks, only capture them from actions.
// This option does nothing without the above option being enabled
//
// Default - disabled
//
// 1 - Only captures callstacks for actions.
// Ignored if CaptureCallstacks is disabled
// 0 - Callstacks, if enabled, are captured for every event.
eRENDERDOC_Option_CaptureCallstacksOnlyDraws = 4,
eRENDERDOC_Option_CaptureCallstacksOnlyActions = 4,
// Specify a delay in seconds to wait for a debugger to attach, after
// creating or injecting into a process, before continuing to allow it to run.
//
// 0 indicates no delay, and the process will run immediately after injection
//
// Default - 0 seconds
//
eRENDERDOC_Option_DelayForDebugger = 5,
// Verify buffer access. This includes checking the memory returned by a Map() call to
// detect any out-of-bounds modification, as well as initialising buffers with undefined contents
// to a marker value to catch use of uninitialised memory.
//
// NOTE: This option is only valid for OpenGL and D3D11. Explicit APIs such as D3D12 and Vulkan do
// not do the same kind of interception & checking and undefined contents are really undefined.
//
// Default - disabled
//
// 1 - Verify buffer access
// 0 - No verification is performed, and overwriting bounds may cause crashes or corruption in
// RenderDoc.
eRENDERDOC_Option_VerifyBufferAccess = 6,
// The old name for eRENDERDOC_Option_VerifyBufferAccess was eRENDERDOC_Option_VerifyMapWrites.
// This option now controls the filling of uninitialised buffers with 0xdddddddd which was
// previously always enabled
eRENDERDOC_Option_VerifyMapWrites = eRENDERDOC_Option_VerifyBufferAccess,
// Hooks any system API calls that create child processes, and injects
// RenderDoc into them recursively with the same options.
//
// Default - disabled
//
// 1 - Hooks into spawned child processes
// 0 - Child processes are not hooked by RenderDoc
eRENDERDOC_Option_HookIntoChildren = 7,
// By default RenderDoc only includes resources in the final capture necessary
// for that frame, this allows you to override that behaviour.
//
// Default - disabled
//
// 1 - all live resources at the time of capture are included in the capture
// and available for inspection
// 0 - only the resources referenced by the captured frame are included
eRENDERDOC_Option_RefAllResources = 8,
// **NOTE**: As of RenderDoc v1.1 this option has been deprecated. Setting or
// getting it will be ignored, to allow compatibility with older versions.
// In v1.1 the option acts as if it's always enabled.
//
// By default RenderDoc skips saving initial states for resources where the
// previous contents don't appear to be used, assuming that writes before
// reads indicate previous contents aren't used.
//
// Default - disabled
//
// 1 - initial contents at the start of each captured frame are saved, even if
// they are later overwritten or cleared before being used.
// 0 - unless a read is detected, initial contents will not be saved and will
// appear as black or empty data.
eRENDERDOC_Option_SaveAllInitials = 9,
// In APIs that allow for the recording of command lists to be replayed later,
// RenderDoc may choose to not capture command lists before a frame capture is
// triggered, to reduce overheads. This means any command lists recorded once
// and replayed many times will not be available and may cause a failure to
// capture.
//
// NOTE: This is only true for APIs where multithreading is difficult or
// discouraged. Newer APIs like Vulkan and D3D12 will ignore this option
// and always capture all command lists since the API is heavily oriented
// around it and the overheads have been reduced by API design.
//
// 1 - All command lists are captured from the start of the application
// 0 - Command lists are only captured if their recording begins during
// the period when a frame capture is in progress.
eRENDERDOC_Option_CaptureAllCmdLists = 10,
// Mute API debugging output when the API validation mode option is enabled
//
// Default - enabled
//
// 1 - Mute any API debug messages from being displayed or passed through
// 0 - API debugging is displayed as normal
eRENDERDOC_Option_DebugOutputMute = 11,
// Option to allow vendor extensions to be used even when they may be
// incompatible with RenderDoc and cause corrupted replays or crashes.
//
// Default - inactive
//
// No values are documented, this option should only be used when absolutely
// necessary as directed by a RenderDoc developer.
eRENDERDOC_Option_AllowUnsupportedVendorExtensions = 12,
// Define a soft memory limit which some APIs may aim to keep overhead under where
// possible. Anything above this limit will where possible be saved directly to disk during
// capture.
// This will cause increased disk space use (which may cause a capture to fail if disk space is
// exhausted) as well as slower capture times.
//
// Not all memory allocations may be deferred like this so it is not a guarantee of a memory
// limit.
//
// Units are in MBs, suggested values would range from 200MB to 1000MB.
//
// Default - 0 Megabytes
eRENDERDOC_Option_SoftMemoryLimit = 13,
} RENDERDOC_CaptureOption;
// Sets an option that controls how RenderDoc behaves on capture.
//
// Returns 1 if the option and value are valid
// Returns 0 if either is invalid and the option is unchanged
typedef int(RENDERDOC_CC *pRENDERDOC_SetCaptureOptionU32)(RENDERDOC_CaptureOption opt, uint32_t val);
typedef int(RENDERDOC_CC *pRENDERDOC_SetCaptureOptionF32)(RENDERDOC_CaptureOption opt, float val);
// Gets the current value of an option as a uint32_t
//
// If the option is invalid, 0xffffffff is returned
typedef uint32_t(RENDERDOC_CC *pRENDERDOC_GetCaptureOptionU32)(RENDERDOC_CaptureOption opt);
// Gets the current value of an option as a float
//
// If the option is invalid, -FLT_MAX is returned
typedef float(RENDERDOC_CC *pRENDERDOC_GetCaptureOptionF32)(RENDERDOC_CaptureOption opt);
typedef enum RENDERDOC_InputButton
{
// '0' - '9' matches ASCII values
eRENDERDOC_Key_0 = 0x30,
eRENDERDOC_Key_1 = 0x31,
eRENDERDOC_Key_2 = 0x32,
eRENDERDOC_Key_3 = 0x33,
eRENDERDOC_Key_4 = 0x34,
eRENDERDOC_Key_5 = 0x35,
eRENDERDOC_Key_6 = 0x36,
eRENDERDOC_Key_7 = 0x37,
eRENDERDOC_Key_8 = 0x38,
eRENDERDOC_Key_9 = 0x39,
// 'A' - 'Z' matches ASCII values
eRENDERDOC_Key_A = 0x41,
eRENDERDOC_Key_B = 0x42,
eRENDERDOC_Key_C = 0x43,
eRENDERDOC_Key_D = 0x44,
eRENDERDOC_Key_E = 0x45,
eRENDERDOC_Key_F = 0x46,
eRENDERDOC_Key_G = 0x47,
eRENDERDOC_Key_H = 0x48,
eRENDERDOC_Key_I = 0x49,
eRENDERDOC_Key_J = 0x4A,
eRENDERDOC_Key_K = 0x4B,
eRENDERDOC_Key_L = 0x4C,
eRENDERDOC_Key_M = 0x4D,
eRENDERDOC_Key_N = 0x4E,
eRENDERDOC_Key_O = 0x4F,
eRENDERDOC_Key_P = 0x50,
eRENDERDOC_Key_Q = 0x51,
eRENDERDOC_Key_R = 0x52,
eRENDERDOC_Key_S = 0x53,
eRENDERDOC_Key_T = 0x54,
eRENDERDOC_Key_U = 0x55,
eRENDERDOC_Key_V = 0x56,
eRENDERDOC_Key_W = 0x57,
eRENDERDOC_Key_X = 0x58,
eRENDERDOC_Key_Y = 0x59,
eRENDERDOC_Key_Z = 0x5A,
// leave the rest of the ASCII range free
// in case we want to use it later
eRENDERDOC_Key_NonPrintable = 0x100,
eRENDERDOC_Key_Divide,
eRENDERDOC_Key_Multiply,
eRENDERDOC_Key_Subtract,
eRENDERDOC_Key_Plus,
eRENDERDOC_Key_F1,
eRENDERDOC_Key_F2,
eRENDERDOC_Key_F3,
eRENDERDOC_Key_F4,
eRENDERDOC_Key_F5,
eRENDERDOC_Key_F6,
eRENDERDOC_Key_F7,
eRENDERDOC_Key_F8,
eRENDERDOC_Key_F9,
eRENDERDOC_Key_F10,
eRENDERDOC_Key_F11,
eRENDERDOC_Key_F12,
eRENDERDOC_Key_Home,
eRENDERDOC_Key_End,
eRENDERDOC_Key_Insert,
eRENDERDOC_Key_Delete,
eRENDERDOC_Key_PageUp,
eRENDERDOC_Key_PageDn,
eRENDERDOC_Key_Backspace,
eRENDERDOC_Key_Tab,
eRENDERDOC_Key_PrtScrn,
eRENDERDOC_Key_Pause,
eRENDERDOC_Key_Max,
} RENDERDOC_InputButton;
// Sets which key or keys can be used to toggle focus between multiple windows
//
// If keys is NULL or num is 0, toggle keys will be disabled
typedef void(RENDERDOC_CC *pRENDERDOC_SetFocusToggleKeys)(RENDERDOC_InputButton *keys, int num);
// Sets which key or keys can be used to capture the next frame
//
// If keys is NULL or num is 0, captures keys will be disabled
typedef void(RENDERDOC_CC *pRENDERDOC_SetCaptureKeys)(RENDERDOC_InputButton *keys, int num);
typedef enum RENDERDOC_OverlayBits
{
// This single bit controls whether the overlay is enabled or disabled globally
eRENDERDOC_Overlay_Enabled = 0x1,
// Show the average framerate over several seconds as well as min/max
eRENDERDOC_Overlay_FrameRate = 0x2,
// Show the current frame number
eRENDERDOC_Overlay_FrameNumber = 0x4,
// Show a list of recent captures, and how many captures have been made
eRENDERDOC_Overlay_CaptureList = 0x8,
// Default values for the overlay mask
eRENDERDOC_Overlay_Default = (eRENDERDOC_Overlay_Enabled | eRENDERDOC_Overlay_FrameRate |
eRENDERDOC_Overlay_FrameNumber | eRENDERDOC_Overlay_CaptureList),
// Enable all bits
eRENDERDOC_Overlay_All = 0x7ffffff,
// Disable all bits
eRENDERDOC_Overlay_None = 0,
} RENDERDOC_OverlayBits;
// returns the overlay bits that have been set
typedef uint32_t(RENDERDOC_CC *pRENDERDOC_GetOverlayBits)(void);
// sets the overlay bits with an and & or mask
typedef void(RENDERDOC_CC *pRENDERDOC_MaskOverlayBits)(uint32_t And, uint32_t Or);
// this function will attempt to remove RenderDoc's hooks in the application.
//
// Note: that this can only work correctly if done immediately after
// the module is loaded, before any API work happens. RenderDoc will remove its
// injected hooks and shut down. Behaviour is undefined if this is called
// after any API functions have been called, and there is still no guarantee of
// success.
typedef void(RENDERDOC_CC *pRENDERDOC_RemoveHooks)(void);
// DEPRECATED: compatibility for code compiled against pre-1.4.1 headers.
typedef pRENDERDOC_RemoveHooks pRENDERDOC_Shutdown;
// This function will unload RenderDoc's crash handler.
//
// If you use your own crash handler and don't want RenderDoc's handler to
// intercede, you can call this function to unload it and any unhandled
// exceptions will pass to the next handler.
typedef void(RENDERDOC_CC *pRENDERDOC_UnloadCrashHandler)(void);
// Sets the capture file path template
//
// pathtemplate is a UTF-8 string that gives a template for how captures will be named
// and where they will be saved.
//
// Any extension is stripped off the path, and captures are saved in the directory
// specified, and named with the filename and the frame number appended. If the
// directory does not exist it will be created, including any parent directories.
//
// If pathtemplate is NULL, the template will remain unchanged
//
// Example:
//
// SetCaptureFilePathTemplate("my_captures/example");
//
// Capture #1 -> my_captures/example_frame123.rdc
// Capture #2 -> my_captures/example_frame456.rdc
typedef void(RENDERDOC_CC *pRENDERDOC_SetCaptureFilePathTemplate)(const char *pathtemplate);
// returns the current capture path template, see SetCaptureFileTemplate above, as a UTF-8 string
typedef const char *(RENDERDOC_CC *pRENDERDOC_GetCaptureFilePathTemplate)(void);
// DEPRECATED: compatibility for code compiled against pre-1.1.2 headers.
typedef pRENDERDOC_SetCaptureFilePathTemplate pRENDERDOC_SetLogFilePathTemplate;
typedef pRENDERDOC_GetCaptureFilePathTemplate pRENDERDOC_GetLogFilePathTemplate;
// returns the number of captures that have been made
typedef uint32_t(RENDERDOC_CC *pRENDERDOC_GetNumCaptures)(void);
// This function returns the details of a capture, by index. New captures are added
// to the end of the list.
//
// filename will be filled with the absolute path to the capture file, as a UTF-8 string
// pathlength will be written with the length in bytes of the filename string
// timestamp will be written with the time of the capture, in seconds since the Unix epoch
//
// Any of the parameters can be NULL and they'll be skipped.
//
// The function will return 1 if the capture index is valid, or 0 if the index is invalid
// If the index is invalid, the values will be unchanged
//
// Note: when captures are deleted in the UI they will remain in this list, so the
// capture path may not exist anymore.
typedef uint32_t(RENDERDOC_CC *pRENDERDOC_GetCapture)(uint32_t idx, char *filename,
uint32_t *pathlength, uint64_t *timestamp);
// Sets the comments associated with a capture file. These comments are displayed in the
// UI program when opening.
//
// filePath should be a path to the capture file to add comments to. If set to NULL or ""
// the most recent capture file created made will be used instead.
// comments should be a NULL-terminated UTF-8 string to add as comments.
//
// Any existing comments will be overwritten.
typedef void(RENDERDOC_CC *pRENDERDOC_SetCaptureFileComments)(const char *filePath,
const char *comments);
// returns 1 if the RenderDoc UI is connected to this application, 0 otherwise
typedef uint32_t(RENDERDOC_CC *pRENDERDOC_IsTargetControlConnected)(void);
// DEPRECATED: compatibility for code compiled against pre-1.1.1 headers.
// This was renamed to IsTargetControlConnected in API 1.1.1, the old typedef is kept here for
// backwards compatibility with old code, it is castable either way since it's ABI compatible
// as the same function pointer type.
typedef pRENDERDOC_IsTargetControlConnected pRENDERDOC_IsRemoteAccessConnected;
// This function will launch the Replay UI associated with the RenderDoc library injected
// into the running application.
//
// if connectTargetControl is 1, the Replay UI will be launched with a command line parameter
// to connect to this application
// cmdline is the rest of the command line, as a UTF-8 string. E.g. a captures to open
// if cmdline is NULL, the command line will be empty.
//
// returns the PID of the replay UI if successful, 0 if not successful.
typedef uint32_t(RENDERDOC_CC *pRENDERDOC_LaunchReplayUI)(uint32_t connectTargetControl,
const char *cmdline);
// RenderDoc can return a higher version than requested if it's backwards compatible,
// this function returns the actual version returned. If a parameter is NULL, it will be
// ignored and the others will be filled out.
typedef void(RENDERDOC_CC *pRENDERDOC_GetAPIVersion)(int *major, int *minor, int *patch);
// Requests that the replay UI show itself (if hidden or not the current top window). This can be
// used in conjunction with IsTargetControlConnected and LaunchReplayUI to intelligently handle
// showing the UI after making a capture.
//
// This will return 1 if the request was successfully passed on, though it's not guaranteed that
// the UI will be on top in all cases depending on OS rules. It will return 0 if there is no current
// target control connection to make such a request, or if there was another error
typedef uint32_t(RENDERDOC_CC *pRENDERDOC_ShowReplayUI)(void);
//////////////////////////////////////////////////////////////////////////
// Capturing functions
//
// A device pointer is a pointer to the API's root handle.
//
// This would be an ID3D11Device, HGLRC/GLXContext, ID3D12Device, etc
typedef void *RENDERDOC_DevicePointer;
// A window handle is the OS's native window handle
//
// This would be an HWND, GLXDrawable, etc
typedef void *RENDERDOC_WindowHandle;
// A helper macro for Vulkan, where the device handle cannot be used directly.
//
// Passing the VkInstance to this macro will return the RENDERDOC_DevicePointer to use.
//
// Specifically, the value needed is the dispatch table pointer, which sits as the first
// pointer-sized object in the memory pointed to by the VkInstance. Thus we cast to a void** and
// indirect once.
#define RENDERDOC_DEVICEPOINTER_FROM_VKINSTANCE(inst) (*((void **)(inst)))
// This sets the RenderDoc in-app overlay in the API/window pair as 'active' and it will
// respond to keypresses. Neither parameter can be NULL
typedef void(RENDERDOC_CC *pRENDERDOC_SetActiveWindow)(RENDERDOC_DevicePointer device,
RENDERDOC_WindowHandle wndHandle);
// capture the next frame on whichever window and API is currently considered active
typedef void(RENDERDOC_CC *pRENDERDOC_TriggerCapture)(void);
// capture the next N frames on whichever window and API is currently considered active
typedef void(RENDERDOC_CC *pRENDERDOC_TriggerMultiFrameCapture)(uint32_t numFrames);
// When choosing either a device pointer or a window handle to capture, you can pass NULL.
// Passing NULL specifies a 'wildcard' match against anything. This allows you to specify
// any API rendering to a specific window, or a specific API instance rendering to any window,
// or in the simplest case of one window and one API, you can just pass NULL for both.
//
// In either case, if there are two or more possible matching (device,window) pairs it
// is undefined which one will be captured.
//
// Note: for headless rendering you can pass NULL for the window handle and either specify
// a device pointer or leave it NULL as above.
// Immediately starts capturing API calls on the specified device pointer and window handle.
//
// If there is no matching thing to capture (e.g. no supported API has been initialised),
// this will do nothing.
//
// The results are undefined (including crashes) if two captures are started overlapping,
// even on separate devices and/oror windows.
typedef void(RENDERDOC_CC *pRENDERDOC_StartFrameCapture)(RENDERDOC_DevicePointer device,
RENDERDOC_WindowHandle wndHandle);
// Returns whether or not a frame capture is currently ongoing anywhere.
//
// This will return 1 if a capture is ongoing, and 0 if there is no capture running
typedef uint32_t(RENDERDOC_CC *pRENDERDOC_IsFrameCapturing)(void);
// Ends capturing immediately.
//
// This will return 1 if the capture succeeded, and 0 if there was an error capturing.
typedef uint32_t(RENDERDOC_CC *pRENDERDOC_EndFrameCapture)(RENDERDOC_DevicePointer device,
RENDERDOC_WindowHandle wndHandle);
// Ends capturing immediately and discard any data stored without saving to disk.
//
// This will return 1 if the capture was discarded, and 0 if there was an error or no capture
// was in progress
typedef uint32_t(RENDERDOC_CC *pRENDERDOC_DiscardFrameCapture)(RENDERDOC_DevicePointer device,
RENDERDOC_WindowHandle wndHandle);
// Only valid to be called between a call to StartFrameCapture and EndFrameCapture. Gives a custom
// title to the capture produced which will be displayed in the UI.
//
// If multiple captures are ongoing, this title will be applied to the first capture to end after
// this call. The second capture to end will have no title, unless this function is called again.
//
// Calling this function has no effect if no capture is currently running, and if it is called
// multiple times only the last title will be used.
typedef void(RENDERDOC_CC *pRENDERDOC_SetCaptureTitle)(const char *title);
// Annotations API:
//
// These functions allow you to specify annotations either on a per-command level, or a per-object
// level.
//
// Basic types of annotations are supported, as well as vector versions and references to API objects.
//
// The annotations are stored as keys, with the key being a dot-separated path allowing arbitrary
// nesting and user organisation. The keys are sorted in human order so `foo.2.bar` will be displayed
// before `foo.10.bar` to allow creation of arrays if desired.
//
// Deleting an annotation can be done by assigning an empty value to it.
// the type of an annotation value, or Empty to delete an annotation
typedef enum RENDERDOC_AnnotationType
{
eRENDERDOC_Empty,
eRENDERDOC_Bool,
eRENDERDOC_Int32,
eRENDERDOC_UInt32,
eRENDERDOC_Int64,
eRENDERDOC_UInt64,
eRENDERDOC_Float,
eRENDERDOC_Double,
eRENDERDOC_String,
eRENDERDOC_APIObject,
eRENDERDOC_AnnotationMax = 0x7FFFFFFF,
} RENDERDOC_AnnotationType;
// a union with vector annotation value data
typedef union RENDERDOC_AnnotationVectorValue
{
bool boolean[4];
int32_t int32[4];
int64_t int64[4];
uint32_t uint32[4];
uint64_t uint64[4];
float float32[4];
double float64[4];
} RENDERDOC_AnnotationVectorValue;
// a union with scalar annotation value data
typedef union RENDERDOC_AnnotationValue
{
bool boolean;
int32_t int32;
int64_t int64;
uint32_t uint32;
uint64_t uint64;
float float32;
double float64;
RENDERDOC_AnnotationVectorValue vector;
const char *string;
void *apiObject;
} RENDERDOC_AnnotationValue;
// a struct for specifying a GL object, as we don't have pointers we can use so instead we specify a
// pointer to this struct giving both the type and the name
typedef struct RENDERDOC_GLResourceReference
{
// this is the same GLenum identifier as passed to glObjectLabel
uint32_t identifier;
uint32_t name;
} GLResourceReference;
// simple C++ helpers to avoid the need for a temporary objects for value passing and GL object specification
#ifdef __cplusplus
struct RDGLObjectHelper
{
RENDERDOC_GLResourceReference gl;
RDGLObjectHelper(uint32_t identifier, uint32_t name)
{
gl.identifier = identifier;
gl.name = name;
}
operator RENDERDOC_GLResourceReference *() { return &gl; }
};
struct RDAnnotationHelper
{
RENDERDOC_AnnotationValue val;
RDAnnotationHelper(bool b) { val.boolean = b; }
RDAnnotationHelper(int32_t i) { val.int32 = i; }
RDAnnotationHelper(int64_t i) { val.int64 = i; }
RDAnnotationHelper(uint32_t i) { val.uint32 = i; }
RDAnnotationHelper(uint64_t i) { val.uint64 = i; }
RDAnnotationHelper(float f) { val.float32 = f; }
RDAnnotationHelper(double d) { val.float64 = d; }
RDAnnotationHelper(const char *s) { val.string = s; }
operator RENDERDOC_AnnotationValue *() { return &val; }
};
#endif
// The device is specified in the same way as other API calls that take a RENDERDOC_DevicePointer
// to specify the device.
//
// The object or queue/commandbuffer will depend on the graphics API in question.
//
// Return value:
// 0 - The annotation was applied successfully.
// 1 - The device is unknown/invalid
// 2 - The device is valid but the annotation is not supported for API-specific reasons, such as an
// unrecognised or invalid object or queue/commandbuffer
// 3 - The call is ill-formed or invalid e.g. empty is specified with a value pointer, or non-empty
// is specified with a NULL value pointer
typedef uint32_t(RENDERDOC_CC *pRENDERDOC_SetObjectAnnotation)(RENDERDOC_DevicePointer device,
void *object, const char *key,
RENDERDOC_AnnotationType valueType,
uint32_t valueVectorWidth,
const RENDERDOC_AnnotationValue *value);
typedef uint32_t(RENDERDOC_CC *pRENDERDOC_SetCommandAnnotation)(
RENDERDOC_DevicePointer device, void *queueOrCommandBuffer, const char *key,
RENDERDOC_AnnotationType valueType, uint32_t valueVectorWidth,
const RENDERDOC_AnnotationValue *value);
//////////////////////////////////////////////////////////////////////////////////////////////////
// RenderDoc API versions
//
// RenderDoc uses semantic versioning (http://semver.org/).
//
// MAJOR version is incremented when incompatible API changes happen.
// MINOR version is incremented when functionality is added in a backwards-compatible manner.
// PATCH version is incremented when backwards-compatible bug fixes happen.
//
// Note that this means the API returned can be higher than the one you might have requested.
// e.g. if you are running against a newer RenderDoc that supports 1.0.1, it will be returned
// instead of 1.0.0. You can check this with the GetAPIVersion entry point
typedef enum RENDERDOC_Version
{
eRENDERDOC_API_Version_1_0_0 = 10000, // RENDERDOC_API_1_0_0 = 1 00 00
eRENDERDOC_API_Version_1_0_1 = 10001, // RENDERDOC_API_1_0_1 = 1 00 01
eRENDERDOC_API_Version_1_0_2 = 10002, // RENDERDOC_API_1_0_2 = 1 00 02
eRENDERDOC_API_Version_1_1_0 = 10100, // RENDERDOC_API_1_1_0 = 1 01 00
eRENDERDOC_API_Version_1_1_1 = 10101, // RENDERDOC_API_1_1_1 = 1 01 01
eRENDERDOC_API_Version_1_1_2 = 10102, // RENDERDOC_API_1_1_2 = 1 01 02
eRENDERDOC_API_Version_1_2_0 = 10200, // RENDERDOC_API_1_2_0 = 1 02 00
eRENDERDOC_API_Version_1_3_0 = 10300, // RENDERDOC_API_1_3_0 = 1 03 00
eRENDERDOC_API_Version_1_4_0 = 10400, // RENDERDOC_API_1_4_0 = 1 04 00
eRENDERDOC_API_Version_1_4_1 = 10401, // RENDERDOC_API_1_4_1 = 1 04 01
eRENDERDOC_API_Version_1_4_2 = 10402, // RENDERDOC_API_1_4_2 = 1 04 02
eRENDERDOC_API_Version_1_5_0 = 10500, // RENDERDOC_API_1_5_0 = 1 05 00
eRENDERDOC_API_Version_1_6_0 = 10600, // RENDERDOC_API_1_6_0 = 1 06 00
eRENDERDOC_API_Version_1_7_0 = 10700, // RENDERDOC_API_1_7_0 = 1 07 00
} RENDERDOC_Version;
// API version changelog:
//
// 1.0.0 - initial release
// 1.0.1 - Bugfix: IsFrameCapturing() was returning false for captures that were triggered
// by keypress or TriggerCapture, instead of Start/EndFrameCapture.
// 1.0.2 - Refactor: Renamed eRENDERDOC_Option_DebugDeviceMode to eRENDERDOC_Option_APIValidation
// 1.1.0 - Add feature: TriggerMultiFrameCapture(). Backwards compatible with 1.0.x since the new
// function pointer is added to the end of the struct, the original layout is identical
// 1.1.1 - Refactor: Renamed remote access to target control (to better disambiguate from remote
// replay/remote server concept in replay UI)
// 1.1.2 - Refactor: Renamed "log file" in function names to just capture, to clarify that these
// are captures and not debug logging files. This is the first API version in the v1.0
// branch.
// 1.2.0 - Added feature: SetCaptureFileComments() to add comments to a capture file that will be
// displayed in the UI program on load.
// 1.3.0 - Added feature: New capture option eRENDERDOC_Option_AllowUnsupportedVendorExtensions
// which allows users to opt-in to allowing unsupported vendor extensions to function.
// Should be used at the user's own risk.
// Refactor: Renamed eRENDERDOC_Option_VerifyMapWrites to
// eRENDERDOC_Option_VerifyBufferAccess, which now also controls initialisation to
// 0xdddddddd of uninitialised buffer contents.
// 1.4.0 - Added feature: DiscardFrameCapture() to discard a frame capture in progress and stop
// capturing without saving anything to disk.
// 1.4.1 - Refactor: Renamed Shutdown to RemoveHooks to better clarify what is happening
// 1.4.2 - Refactor: Renamed 'draws' to 'actions' in callstack capture option.
// 1.5.0 - Added feature: ShowReplayUI() to request that the replay UI show itself if connected
// 1.6.0 - Added feature: SetCaptureTitle() which can be used to set a title for a
// capture made with StartFrameCapture() or EndFrameCapture()
// 1.7.0 - Added feature: SetObjectAnnotation() / SetCommandAnnotation() for adding rich
// annotations to objects and command streams
typedef struct RENDERDOC_API_1_7_0
{
pRENDERDOC_GetAPIVersion GetAPIVersion;
pRENDERDOC_SetCaptureOptionU32 SetCaptureOptionU32;
pRENDERDOC_SetCaptureOptionF32 SetCaptureOptionF32;
pRENDERDOC_GetCaptureOptionU32 GetCaptureOptionU32;
pRENDERDOC_GetCaptureOptionF32 GetCaptureOptionF32;
pRENDERDOC_SetFocusToggleKeys SetFocusToggleKeys;
pRENDERDOC_SetCaptureKeys SetCaptureKeys;
pRENDERDOC_GetOverlayBits GetOverlayBits;
pRENDERDOC_MaskOverlayBits MaskOverlayBits;
// Shutdown was renamed to RemoveHooks in 1.4.1.
// These unions allow old code to continue compiling without changes
union
{
pRENDERDOC_Shutdown Shutdown;
pRENDERDOC_RemoveHooks RemoveHooks;
};
pRENDERDOC_UnloadCrashHandler UnloadCrashHandler;
// Get/SetLogFilePathTemplate was renamed to Get/SetCaptureFilePathTemplate in 1.1.2.
// These unions allow old code to continue compiling without changes
union
{
// deprecated name
pRENDERDOC_SetLogFilePathTemplate SetLogFilePathTemplate;
// current name
pRENDERDOC_SetCaptureFilePathTemplate SetCaptureFilePathTemplate;
};
union
{
// deprecated name
pRENDERDOC_GetLogFilePathTemplate GetLogFilePathTemplate;
// current name
pRENDERDOC_GetCaptureFilePathTemplate GetCaptureFilePathTemplate;
};
pRENDERDOC_GetNumCaptures GetNumCaptures;
pRENDERDOC_GetCapture GetCapture;
pRENDERDOC_TriggerCapture TriggerCapture;
// IsRemoteAccessConnected was renamed to IsTargetControlConnected in 1.1.1.
// This union allows old code to continue compiling without changes
union
{
// deprecated name
pRENDERDOC_IsRemoteAccessConnected IsRemoteAccessConnected;
// current name
pRENDERDOC_IsTargetControlConnected IsTargetControlConnected;
};
pRENDERDOC_LaunchReplayUI LaunchReplayUI;
pRENDERDOC_SetActiveWindow SetActiveWindow;
pRENDERDOC_StartFrameCapture StartFrameCapture;
pRENDERDOC_IsFrameCapturing IsFrameCapturing;
pRENDERDOC_EndFrameCapture EndFrameCapture;
// new function in 1.1.0
pRENDERDOC_TriggerMultiFrameCapture TriggerMultiFrameCapture;
// new function in 1.2.0
pRENDERDOC_SetCaptureFileComments SetCaptureFileComments;
// new function in 1.4.0
pRENDERDOC_DiscardFrameCapture DiscardFrameCapture;
// new function in 1.5.0
pRENDERDOC_ShowReplayUI ShowReplayUI;
// new function in 1.6.0
pRENDERDOC_SetCaptureTitle SetCaptureTitle;
// new functions in 1.7.0
pRENDERDOC_SetObjectAnnotation SetObjectAnnotation;
pRENDERDOC_SetCommandAnnotation SetCommandAnnotation;
} RENDERDOC_API_1_7_0;
typedef RENDERDOC_API_1_7_0 RENDERDOC_API_1_0_0;
typedef RENDERDOC_API_1_7_0 RENDERDOC_API_1_0_1;
typedef RENDERDOC_API_1_7_0 RENDERDOC_API_1_0_2;
typedef RENDERDOC_API_1_7_0 RENDERDOC_API_1_1_0;
typedef RENDERDOC_API_1_7_0 RENDERDOC_API_1_1_1;
typedef RENDERDOC_API_1_7_0 RENDERDOC_API_1_1_2;
typedef RENDERDOC_API_1_7_0 RENDERDOC_API_1_2_0;
typedef RENDERDOC_API_1_7_0 RENDERDOC_API_1_3_0;
typedef RENDERDOC_API_1_7_0 RENDERDOC_API_1_4_0;
typedef RENDERDOC_API_1_7_0 RENDERDOC_API_1_4_1;
typedef RENDERDOC_API_1_7_0 RENDERDOC_API_1_4_2;
typedef RENDERDOC_API_1_7_0 RENDERDOC_API_1_5_0;
typedef RENDERDOC_API_1_7_0 RENDERDOC_API_1_6_0;
//////////////////////////////////////////////////////////////////////////////////////////////////
// RenderDoc API entry point
//
// This entry point can be obtained via GetProcAddress/dlsym if RenderDoc is available.
//
// The name is the same as the typedef - "RENDERDOC_GetAPI"
//
// This function is not thread safe, and should not be called on multiple threads at once.
// Ideally, call this once as early as possible in your application's startup, before doing
// any API work, since some configuration functionality etc has to be done also before
// initialising any APIs.
//
// Parameters:
// version is a single value from the RENDERDOC_Version above.
//
// outAPIPointers will be filled out with a pointer to the corresponding struct of function
// pointers.
//
// Returns:
// 1 - if the outAPIPointers has been filled with a pointer to the API struct requested
// 0 - if the requested version is not supported or the arguments are invalid.
//
typedef int(RENDERDOC_CC *pRENDERDOC_GetAPI)(RENDERDOC_Version version, void **outAPIPointers);
#ifdef __cplusplus
} // extern "C"
#endif
+1724
View File
File diff suppressed because it is too large Load Diff
+1 -1
+299 -81
View File
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.12...4.3)
cmake_minimum_required(VERSION 3.19...4.3)
if(CMAKE_VERSION VERSION_GREATER_EQUAL 4.0)
set(CMAKE_POLICY_VERSION_MINIMUM 3.5 CACHE STRING "Minimum policy version for bundled dependencies")
set(CMAKE_POLICY_VERSION_MINIMUM 3.10 CACHE STRING "Minimum policy version for bundled dependencies")
endif()
get_property(KYTY_GENERATOR_IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
@@ -12,6 +12,22 @@ endif()
project(Kyty)
find_program(SCCACHE_PROGRAM sccache)
find_program(CCACHE_PROGRAM ccache)
foreach(lang IN ITEMS C CXX)
# An explicitly empty launcher disables caching for this language.
if(NOT DEFINED CMAKE_${lang}_COMPILER_LAUNCHER)
if(SCCACHE_PROGRAM)
set(CMAKE_${lang}_COMPILER_LAUNCHER "${SCCACHE_PROGRAM}")
message(STATUS "sccache enabled for ${lang}: ${SCCACHE_PROGRAM}")
elseif(CCACHE_PROGRAM)
set(CMAKE_${lang}_COMPILER_LAUNCHER "${CCACHE_PROGRAM}")
message(STATUS "ccache enabled for ${lang}: ${CCACHE_PROGRAM}")
endif()
endif()
endforeach()
set(KYTY_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src")
set(KYTY_TESTS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/tests")
set(KYTY_THIRD_PARTY_DIR "${CMAKE_CURRENT_SOURCE_DIR}/3rdparty")
@@ -24,6 +40,11 @@ if (NOT (WIN32 OR LINUX OR APPLE))
message(FATAL_ERROR "only Windows, Linux, and macOS builds are supported")
endif()
if(WIN32)
# Prevent Windows headers from defining min/max macros in all targets.
add_compile_definitions(NOMINMAX)
endif()
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
@@ -126,7 +147,7 @@ if (KYTY_LINKER STREQUAL LD AND NOT LINUX)
set(KYTY_LD_OPTIONS "-Wl,--image-base=0x100000000000")
endif()
project(Kyty${KYTY_PROJECT_NAME}${CMAKE_BUILD_TYPE}${KYTY_COMPILER} VERSION 0.2.2)
project(Kyty${KYTY_PROJECT_NAME}${CMAKE_BUILD_TYPE}${KYTY_COMPILER} VERSION 0.3.0)
include_directories(
${KYTY_THIRD_PARTY_DIR}/gtest/include
@@ -203,14 +224,21 @@ file(GLOB kyty_emulator_src CONFIGURE_DEPENDS
"${KYTY_SOURCE_DIR}/graphics/shader/*.h"
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/*.cpp"
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/*.h"
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/cfg/*.cpp"
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/cfg/*.h"
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/decompiler/*.cpp"
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/decompiler/*.h"
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/emitter/*.cpp"
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/emitter/*.h"
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/frontend/cfg/*.cpp"
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/frontend/cfg/*.h"
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/frontend/decode/*.cpp"
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/frontend/decode/*.h"
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/frontend/translate/*.cpp"
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/frontend/translate/*.h"
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/backend/spirv/*.cpp"
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/backend/spirv/*.h"
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/*.cpp"
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/*.h"
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/opcodes/*.cpp"
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/opcodes/*.h"
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/opcodes/*.inc"
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/passes/*.cpp"
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/passes/*.h"
"${KYTY_SOURCE_DIR}/graphics/presentation/*.cpp"
"${KYTY_SOURCE_DIR}/graphics/presentation/*.h"
"${KYTY_SOURCE_DIR}/graphics/presentation/window/*.cpp"
@@ -221,7 +249,7 @@ file(GLOB kyty_emulator_src CONFIGURE_DEPENDS
"${KYTY_SOURCE_DIR}/loader/*.h"
)
find_program(KYTY_GLSLANG_VALIDATOR glslangValidator REQUIRED)
find_program(KYTY_GLSLANG_VALIDATOR NAMES glslangValidator glslang REQUIRED)
set(gpu_tiler_shader_dir "${KYTY_SOURCE_DIR}/graphics/host_gpu/shaders")
set(gpu_tiler_generated_dir "${PROJECT_BINARY_DIR}/gpu_tiler_shaders")
set(gpu_tiler_shader_names
@@ -236,7 +264,7 @@ set(gpu_tiler_shader_names
depth
promote_d16
demote_d16
swap_bgra16
color_transform
)
file(GLOB gpu_tiler_shader_includes CONFIGURE_DEPENDS "${gpu_tiler_shader_dir}/gpu_tiler_*.inc")
foreach(shader_name IN LISTS gpu_tiler_shader_names)
@@ -247,7 +275,7 @@ foreach(shader_name IN LISTS gpu_tiler_shader_names)
add_custom_command(
OUTPUT "${shader_header}"
COMMAND ${CMAKE_COMMAND} -E make_directory "${gpu_tiler_generated_dir}"
COMMAND "${KYTY_GLSLANG_VALIDATOR}" -V --target-env vulkan1.0 -Os
COMMAND "${KYTY_GLSLANG_VALIDATOR}" -V --target-env vulkan1.3 -Os
"-I${gpu_tiler_shader_dir}" -o "${shader_spv}" "${shader_source}"
COMMAND ${CMAKE_COMMAND} -DINPUT=${shader_spv} -DOUTPUT=${shader_header}
-DSYMBOL=${shader_symbol} -P "${KYTY_SOURCE_DIR}/embed_spirv.cmake"
@@ -256,30 +284,46 @@ foreach(shader_name IN LISTS gpu_tiler_shader_names)
)
list(APPEND gpu_tiler_shader_headers "${shader_header}")
endforeach()
set(fault_buffer_shader_source "${gpu_tiler_shader_dir}/fault_buffer_process.comp")
set(fault_buffer_shader_spv "${gpu_tiler_generated_dir}/fault_buffer_process.spv")
set(fault_buffer_shader_header "${gpu_tiler_generated_dir}/fault_buffer_process_spv.h")
add_custom_command(
OUTPUT "${fault_buffer_shader_header}"
COMMAND ${CMAKE_COMMAND} -E make_directory "${gpu_tiler_generated_dir}"
COMMAND "${KYTY_GLSLANG_VALIDATOR}" -V --target-env vulkan1.3 -Os
-DCACHING_PAGEBITS=14 -DMAX_PAGE_FAULTS=1024
-o "${fault_buffer_shader_spv}" "${fault_buffer_shader_source}"
COMMAND ${CMAKE_COMMAND} -DINPUT=${fault_buffer_shader_spv} -DOUTPUT=${fault_buffer_shader_header}
-DSYMBOL=FAULT_BUFFER_PROCESS_SPV -P "${KYTY_SOURCE_DIR}/embed_spirv.cmake"
DEPENDS "${fault_buffer_shader_source}"
VERBATIM
)
list(APPEND kyty_emulator_src "${fault_buffer_shader_header}")
list(APPEND kyty_emulator_src ${gpu_tiler_shader_headers})
set(gpu_blit_generated_dir "${PROJECT_BINARY_DIR}/gpu_blit_shaders")
set(gpu_blit_shader_sources
"${gpu_tiler_shader_dir}/gpu_blit_fs_triangle.vert"
"${gpu_tiler_shader_dir}/gpu_blit_color_to_ms_depth.frag"
)
foreach(shader_source IN LISTS gpu_blit_shader_sources)
get_filename_component(shader_name "${shader_source}" NAME_WE)
function(add_gpu_blit_shader shader_name shader_file)
set(shader_source "${gpu_tiler_shader_dir}/${shader_file}")
set(shader_spv "${gpu_blit_generated_dir}/${shader_name}.spv")
set(shader_header "${gpu_blit_generated_dir}/${shader_name}_spv.h")
string(TOUPPER "${shader_name}_SPV" shader_symbol)
add_custom_command(
OUTPUT "${shader_header}"
COMMAND ${CMAKE_COMMAND} -E make_directory "${gpu_blit_generated_dir}"
COMMAND "${KYTY_GLSLANG_VALIDATOR}" -V --target-env vulkan1.0 -Os
COMMAND "${KYTY_GLSLANG_VALIDATOR}" -V --target-env vulkan1.3 -Os ${ARGN}
"-I${gpu_tiler_shader_dir}" -o "${shader_spv}" "${shader_source}"
COMMAND ${CMAKE_COMMAND} -DINPUT=${shader_spv} -DOUTPUT=${shader_header}
-DSYMBOL=${shader_symbol} -P "${KYTY_SOURCE_DIR}/embed_spirv.cmake"
DEPENDS "${shader_source}"
VERBATIM
)
list(APPEND gpu_blit_shader_headers "${shader_header}")
endforeach()
set(gpu_blit_shader_headers ${gpu_blit_shader_headers} "${shader_header}" PARENT_SCOPE)
endfunction()
add_gpu_blit_shader(gpu_blit_fs_triangle gpu_blit_fs_triangle.vert)
add_gpu_blit_shader(gpu_blit_color_to_ms_depth gpu_blit_color_to_ms_depth.frag)
add_gpu_blit_shader(gpu_video_out_overlay gpu_video_out_overlay.frag)
add_gpu_blit_shader(gpu_imgui_hdr gpu_video_out_overlay.frag -DIMGUI_HDR=1)
list(APPEND kyty_emulator_src ${gpu_blit_shader_headers})
list(APPEND kyty_emulator_src
@@ -292,36 +336,23 @@ if (KYTY_CLANG_CL)
set_source_files_properties(${kyty_emulator_src} PROPERTIES COMPILE_FLAGS "-Wno-pragma-pack -Wno-deprecated-declarations -D_TIMESPEC_DEFINED")
endif()
set(kyty_emulator_link_libraries common Vulkan::Headers spirv-tools-opt spirv-tools SDL2-static xxhash FFmpeg::ffmpeg fmt::fmt nlohmann_json::nlohmann_json LibAtrac9 kyty_git_version)
set(kyty_emulator_link_libraries common Vulkan::Headers spirv-tools-opt spirv-tools SDL3::SDL3-static imgui xxhash FFmpeg::ffmpeg fmt::fmt nlohmann_json::nlohmann_json LibAtrac9 kyty_git_version Zydis::Zydis xbyak::xbyak opus)
# Linux system libraries required by the static FFmpeg archive.
# Linux system libraries.
if(LINUX)
find_package(Threads REQUIRED)
list(APPEND kyty_emulator_link_libraries m ${CMAKE_DL_LIBS} Threads::Threads)
# Optional FFmpeg dependencies.
find_package(ZLIB)
if(ZLIB_FOUND)
list(APPEND kyty_emulator_link_libraries ZLIB::ZLIB)
endif()
find_library(KYTY_BZ2_LIBRARY bz2)
if(KYTY_BZ2_LIBRARY)
list(APPEND kyty_emulator_link_libraries ${KYTY_BZ2_LIBRARY})
endif()
find_library(KYTY_LZMA_LIBRARY lzma)
if(KYTY_LZMA_LIBRARY)
list(APPEND kyty_emulator_link_libraries ${KYTY_LZMA_LIBRARY})
endif()
endif()
set(inc_headers
${KYTY_SOURCE_DIR}
${KYTY_THIRD_PARTY_DIR}/SDL2/include
${KYTY_THIRD_PARTY_DIR}/VulkanMemoryAllocator/include
${KYTY_THIRD_PARTY_DIR}/SPIRV-Tools/include
${KYTY_THIRD_PARTY_DIR}/SPIRV-Headers/include
${KYTY_THIRD_PARTY_DIR}/fmt/include
${KYTY_THIRD_PARTY_DIR}/xxhash
${KYTY_THIRD_PARTY_DIR}/xxHash
${KYTY_THIRD_PARTY_DIR}/cpuinfo/include
${KYTY_THIRD_PARTY_DIR}/renderdoc
${KYTY_THIRD_PARTY_DIR}/stb
)
@@ -366,25 +397,66 @@ add_kyty_full_emulator_test(shader_cfg_tests "${KYTY_TESTS_DIR}/shaderCfgTests.c
add_executable(scalar_provenance_tests EXCLUDE_FROM_ALL
"${KYTY_TESTS_DIR}/ScalarProvenanceTests.cpp"
"${KYTY_SOURCE_DIR}/graphics/guest_gpu/gpu_format.cpp"
"${KYTY_SOURCE_DIR}/graphics/host_gpu/hostMemory.cpp"
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/ReadLaneElimination.cpp"
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/ScalarProvenance.cpp"
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/SrtWalker.cpp"
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/passes/ReadLaneElimination.cpp"
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/passes/ResourceMaterialization.cpp"
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/passes/SrtWalker.cpp"
)
target_link_libraries(scalar_provenance_tests fmt::fmt)
target_link_libraries(scalar_provenance_tests fmt::fmt xbyak::xbyak)
target_include_directories(scalar_provenance_tests PRIVATE ${inc_headers})
add_executable(page_manager_tests EXCLUDE_FROM_ALL
"${KYTY_TESTS_DIR}/PageManagerTests.cpp"
"${KYTY_SOURCE_DIR}/graphics/host_gpu/pageManager.cpp"
)
target_link_libraries(page_manager_tests common)
target_include_directories(page_manager_tests PRIVATE ${inc_headers})
add_executable(archive_file_tests EXCLUDE_FROM_ALL
"${KYTY_TESTS_DIR}/ArchiveFileTests.cpp"
)
target_link_libraries(archive_file_tests common ZArchive::zarchive)
target_include_directories(archive_file_tests PRIVATE ${inc_headers})
add_executable(trophy_system_tests EXCLUDE_FROM_ALL
"${KYTY_TESTS_DIR}/TrophySystemTests.cpp"
)
target_link_libraries(trophy_system_tests common)
target_include_directories(trophy_system_tests PRIVATE ${inc_headers})
add_executable(avplayer_file_tests EXCLUDE_FROM_ALL
"${KYTY_TESTS_DIR}/AvPlayerFileTests.cpp"
"${KYTY_SOURCE_DIR}/loader/timer.cpp"
)
target_link_libraries(avplayer_file_tests common FFmpeg::ffmpeg ZArchive::zarchive)
target_include_directories(avplayer_file_tests PRIVATE ${inc_headers})
add_executable(vdecsw_tests EXCLUDE_FROM_ALL
"${KYTY_TESTS_DIR}/VdecswTests.cpp"
"${KYTY_SOURCE_DIR}/libs/videoDec2Decoder.cpp"
"${KYTY_SOURCE_DIR}/loader/timer.cpp"
)
target_link_libraries(vdecsw_tests common FFmpeg::ffmpeg)
target_include_directories(vdecsw_tests PRIVATE ${inc_headers})
add_executable(bit_array_tests EXCLUDE_FROM_ALL
"${KYTY_TESTS_DIR}/BitArrayTests.cpp"
)
target_include_directories(bit_array_tests PRIVATE ${inc_headers})
add_executable(lru_cache_tests EXCLUDE_FROM_ALL
"${KYTY_TESTS_DIR}/LruCacheTests.cpp"
)
target_include_directories(lru_cache_tests PRIVATE ${inc_headers})
add_executable(ime_dialog_tests EXCLUDE_FROM_ALL
"${KYTY_TESTS_DIR}/ImeDialogTests.cpp"
"${KYTY_SOURCE_DIR}/libs/imeCommon.cpp"
"${KYTY_SOURCE_DIR}/libs/imeDialog.cpp"
)
target_include_directories(ime_dialog_tests PRIVATE ${inc_headers})
add_executable(memory_tracker_tests EXCLUDE_FROM_ALL
"${KYTY_TESTS_DIR}/MemoryTrackerTests.cpp"
"${KYTY_SOURCE_DIR}/graphics/host_gpu/pageManager.cpp"
@@ -400,40 +472,29 @@ add_executable(shader_vertex_metadata_tests EXCLUDE_FROM_ALL
)
target_include_directories(shader_vertex_metadata_tests PRIVATE ${inc_headers})
add_executable(shader_stage_runtime_tests EXCLUDE_FROM_ALL
"${KYTY_TESTS_DIR}/ShaderStageRuntimeTests.cpp"
add_executable(resource_materialization_tests EXCLUDE_FROM_ALL
"${KYTY_TESTS_DIR}/ResourceMaterializationTests.cpp"
"${KYTY_SOURCE_DIR}/graphics/guest_gpu/gpu_format.cpp"
"${KYTY_SOURCE_DIR}/graphics/host_gpu/hostMemory.cpp"
"${KYTY_SOURCE_DIR}/graphics/shader/shaderStageRuntime.cpp"
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/ResourceMaterialization.cpp"
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/ScalarProvenance.cpp"
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/SrtWalker.cpp"
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/passes/ResourceMaterialization.cpp"
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/passes/SrtWalker.cpp"
)
target_link_libraries(shader_stage_runtime_tests fmt::fmt)
target_include_directories(shader_stage_runtime_tests PRIVATE ${inc_headers})
target_link_libraries(resource_materialization_tests fmt::fmt xbyak::xbyak)
target_include_directories(resource_materialization_tests PRIVATE ${inc_headers})
add_executable(resource_tracking_tests EXCLUDE_FROM_ALL
"${KYTY_TESTS_DIR}/ResourceTrackingTests.cpp"
"${KYTY_SOURCE_DIR}/graphics/guest_gpu/gpu_format.cpp"
"${KYTY_SOURCE_DIR}/graphics/host_gpu/hostMemory.cpp"
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/ScalarProvenance.cpp"
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/SrtWalker.cpp"
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/SrtPatcher.cpp"
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/ResourceTracking.cpp"
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/ResourceMaterialization.cpp"
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/ShaderInfoCollection.cpp"
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/BindingLayout.cpp"
"${KYTY_SOURCE_DIR}/graphics/shader/shaderPixelParameter.cpp"
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/passes/SrtWalker.cpp"
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/passes/ResourceTracking.cpp"
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/passes/ResourceMaterialization.cpp"
"${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/passes/ShaderInfoCollection.cpp"
)
target_link_libraries(resource_tracking_tests fmt::fmt)
target_link_libraries(resource_tracking_tests fmt::fmt xbyak::xbyak)
target_include_directories(resource_tracking_tests PRIVATE ${inc_headers})
add_executable(resource_mutex_tests EXCLUDE_FROM_ALL
"${KYTY_TESTS_DIR}/ResourceMutexTests.cpp"
"${KYTY_SOURCE_DIR}/graphics/host_gpu/renderer/cache/resourceMutex.cpp"
)
target_link_libraries(resource_mutex_tests common)
target_include_directories(resource_mutex_tests PRIVATE ${inc_headers})
add_executable(audio_out2_port_tests EXCLUDE_FROM_ALL
"${KYTY_TESTS_DIR}/AudioOut2PortTests.cpp"
"${KYTY_SOURCE_DIR}/libs/libAudio2.cpp"
@@ -442,6 +503,57 @@ add_executable(audio_out2_port_tests EXCLUDE_FROM_ALL
target_link_libraries(audio_out2_port_tests common fmt::fmt)
target_include_directories(audio_out2_port_tests PRIVATE ${inc_headers})
add_executable(audio_out_timing_tests EXCLUDE_FROM_ALL "${KYTY_TESTS_DIR}/AudioOutTimingTests.cpp")
target_link_libraries(audio_out_timing_tests common fmt::fmt SDL3::SDL3-static)
target_include_directories(audio_out_timing_tests PRIVATE ${inc_headers})
add_executable(ngs2_sampler_tests EXCLUDE_FROM_ALL
"${KYTY_TESTS_DIR}/Ngs2SamplerTests.cpp"
"${KYTY_SOURCE_DIR}/loader/timer.cpp"
)
target_link_libraries(ngs2_sampler_tests common fmt::fmt LibAtrac9)
target_include_directories(ngs2_sampler_tests PRIVATE ${inc_headers})
add_executable(pad_haptics_tests EXCLUDE_FROM_ALL
"${KYTY_TESTS_DIR}/PadHapticsTests.cpp"
)
target_link_libraries(pad_haptics_tests common fmt::fmt SDL3::SDL3-static opus)
target_include_directories(pad_haptics_tests PRIVATE ${inc_headers})
add_executable(controller_settings_tests EXCLUDE_FROM_ALL
"${KYTY_TESTS_DIR}/ControllerSettingsTests.cpp"
)
target_link_libraries(controller_settings_tests common fmt::fmt SDL3::SDL3-static)
target_include_directories(controller_settings_tests PRIVATE ${inc_headers})
add_executable(host_input_tests EXCLUDE_FROM_ALL "${KYTY_TESTS_DIR}/HostInputTests.cpp")
target_link_libraries(host_input_tests common fmt::fmt SDL3::SDL3-static)
target_include_directories(host_input_tests PRIVATE ${inc_headers})
add_executable(save_data_memory_tests EXCLUDE_FROM_ALL
"${KYTY_TESTS_DIR}/SaveDataMemoryTests.cpp"
)
target_link_libraries(save_data_memory_tests common fmt::fmt)
target_include_directories(save_data_memory_tests PRIVATE ${inc_headers})
add_executable(png_enc_tests EXCLUDE_FROM_ALL "${KYTY_TESTS_DIR}/PngEncTests.cpp")
target_link_libraries(png_enc_tests common fmt::fmt)
target_include_directories(png_enc_tests PRIVATE ${inc_headers})
add_executable(ces_tests EXCLUDE_FROM_ALL "${KYTY_TESTS_DIR}/CesTests.cpp")
target_link_libraries(ces_tests common fmt::fmt SDL3::SDL3-static)
target_include_directories(ces_tests PRIVATE ${inc_headers})
add_executable(save_data_dialog_tests EXCLUDE_FROM_ALL
"${KYTY_TESTS_DIR}/SaveDataDialogTests.cpp"
"${KYTY_SOURCE_DIR}/libs/dialog.cpp"
)
target_link_libraries(save_data_dialog_tests common fmt::fmt)
target_include_directories(save_data_dialog_tests PRIVATE ${inc_headers})
add_kyty_full_emulator_test(http_uri_parse_tests
"${KYTY_TESTS_DIR}/HttpUriParseTests.cpp")
add_executable(event_queue_lifetime_tests EXCLUDE_FROM_ALL
"${KYTY_TESTS_DIR}/EventQueueLifetimeTests.cpp"
"${KYTY_SOURCE_DIR}/kernel/eventQueue.cpp"
@@ -450,6 +562,10 @@ add_executable(event_queue_lifetime_tests EXCLUDE_FROM_ALL
target_link_libraries(event_queue_lifetime_tests common fmt::fmt)
target_include_directories(event_queue_lifetime_tests PRIVATE ${inc_headers})
add_kyty_full_emulator_test(kernel_file_system_tests
"${KYTY_TESTS_DIR}/KernelFileSystemTests.cpp")
target_link_libraries(kernel_file_system_tests ZArchive::zarchive)
add_executable(sync_on_address_tests EXCLUDE_FROM_ALL
"${KYTY_TESTS_DIR}/SyncOnAddressTests.cpp"
"${KYTY_SOURCE_DIR}/kernel/syncOnAddress.cpp"
@@ -475,7 +591,7 @@ set(gpu_test_ms_depth_header
add_custom_command(
OUTPUT "${gpu_test_ms_depth_header}"
COMMAND ${CMAKE_COMMAND} -E make_directory "${gpu_test_generated_dir}"
COMMAND "${KYTY_GLSLANG_VALIDATOR}" -V --target-env vulkan1.0 -Os
COMMAND "${KYTY_GLSLANG_VALIDATOR}" -V --target-env vulkan1.3 -Os
-o "${gpu_test_ms_depth_spv}" "${gpu_test_ms_depth_source}"
COMMAND ${CMAKE_COMMAND} -DINPUT=${gpu_test_ms_depth_spv}
-DOUTPUT=${gpu_test_ms_depth_header} -DSYMBOL=GPU_TEST_MS_DEPTH_SPV
@@ -499,22 +615,56 @@ if(NOT KYTY_CLANG_CL)
endif()
if(BUILD_TESTING)
add_test(NAME emulator_user_name_cli
COMMAND $<TARGET_FILE:kyty_emulator> --help --user-name 1234567890123456)
add_test(NAME emulator_user_name_too_long
COMMAND $<TARGET_FILE:kyty_emulator> --help --user-name 12345678901234567)
set_tests_properties(emulator_user_name_too_long PROPERTIES WILL_FAIL TRUE)
add_test(NAME emulator_present_mode_cli
COMMAND $<TARGET_FILE:kyty_emulator> --help --present-mode Immediate)
add_test(NAME emulator_present_mode_invalid
COMMAND $<TARGET_FILE:kyty_emulator> --help --present-mode Invalid)
set_tests_properties(emulator_present_mode_invalid PROPERTIES WILL_FAIL TRUE)
add_test(NAME ime_dialog COMMAND $<TARGET_FILE:ime_dialog_tests>)
add_test(NAME shader_cfg COMMAND $<TARGET_FILE:shader_cfg_tests>)
add_test(NAME scalar_provenance COMMAND $<TARGET_FILE:scalar_provenance_tests>)
add_test(NAME image_page_table COMMAND $<TARGET_FILE:image_page_table_tests>)
add_test(NAME memory_tracker COMMAND $<TARGET_FILE:memory_tracker_tests>)
add_test(NAME page_manager COMMAND $<TARGET_FILE:page_manager_tests>)
add_test(NAME archive_file COMMAND $<TARGET_FILE:archive_file_tests>)
add_test(NAME trophy_system COMMAND $<TARGET_FILE:trophy_system_tests>)
add_test(NAME avplayer_file COMMAND $<TARGET_FILE:avplayer_file_tests>)
add_test(NAME vdecsw COMMAND $<TARGET_FILE:vdecsw_tests>)
add_test(NAME bit_array COMMAND $<TARGET_FILE:bit_array_tests>)
add_test(NAME lru_cache COMMAND $<TARGET_FILE:lru_cache_tests>)
add_test(NAME shader_vertex_metadata COMMAND $<TARGET_FILE:shader_vertex_metadata_tests>)
add_test(NAME shader_stage_runtime COMMAND $<TARGET_FILE:shader_stage_runtime_tests>)
add_test(NAME resource_materialization COMMAND $<TARGET_FILE:resource_materialization_tests>)
add_test(NAME resource_tracking COMMAND $<TARGET_FILE:resource_tracking_tests>)
add_test(NAME resource_mutex COMMAND $<TARGET_FILE:resource_mutex_tests>)
add_test(NAME event_queue_lifetime COMMAND $<TARGET_FILE:event_queue_lifetime_tests>)
add_test(NAME kernel_file_system COMMAND $<TARGET_FILE:kernel_file_system_tests>)
add_test(NAME sync_on_address COMMAND $<TARGET_FILE:sync_on_address_tests>)
add_test(NAME audio_out2_port COMMAND $<TARGET_FILE:audio_out2_port_tests>)
add_test(NAME audio_out_timing COMMAND $<TARGET_FILE:audio_out_timing_tests>)
add_test(NAME ngs2_sampler COMMAND $<TARGET_FILE:ngs2_sampler_tests>)
add_test(NAME pad_haptics COMMAND $<TARGET_FILE:pad_haptics_tests>)
add_test(NAME controller_settings COMMAND $<TARGET_FILE:controller_settings_tests>)
add_test(NAME host_input COMMAND $<TARGET_FILE:host_input_tests>)
add_test(NAME save_data_memory COMMAND $<TARGET_FILE:save_data_memory_tests>)
add_test(NAME png_enc COMMAND $<TARGET_FILE:png_enc_tests>)
add_test(NAME ces COMMAND $<TARGET_FILE:ces_tests>)
add_test(NAME save_data_dialog COMMAND $<TARGET_FILE:save_data_dialog_tests>)
add_test(NAME http_uri_parse COMMAND $<TARGET_FILE:http_uri_parse_tests>)
add_test(NAME shader_recompiler_compute COMMAND $<TARGET_FILE:shader_recompiler_compute_tests>)
add_test(NAME shader_recompiler_alignbyte
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --alignbyte-only)
add_test(NAME graphics_pipeline_rasterization
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --polygon-mode-only)
add_test(NAME graphics_draw_offsets
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --draw-offset-only)
add_test(NAME virtual_memory_allocation
COMMAND $<TARGET_FILE:virtual_memory_allocation_tests>)
add_test(NAME guest_red_zone_patcher
COMMAND $<TARGET_FILE:virtual_memory_allocation_tests> --red-zone-patcher-only)
add_test(NAME command_scheduler_timeline
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --scheduler-only)
add_test(NAME stream_buffer_ring
@@ -525,50 +675,105 @@ if(BUILD_TESTING)
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --context-state-only)
add_test(NAME gpu_tiler
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --gpu-tiler-only)
add_test(NAME image_transfer_layout
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --image-layout-only)
add_test(NAME texture_cache_layered_image
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --layered-image-only)
add_test(NAME host_image_allocation
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --host-image-allocation-only)
add_test(NAME texture_cache_image_views
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --image-view-cache-only)
add_test(NAME texture_cache_storage_sampled
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --storage-sampled-only)
add_test(NAME texture_cache_depth_readback
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --depth-readback-only)
add_test(NAME compute_meta_clear_classification
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --compute-meta-clear-only)
add_test(NAME buffer_cache_dirty_gc
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --buffer-cache-gc-only)
add_test(NAME color_render_target_1d
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --rt1d-only)
if(WIN32)
# These tests still depend on the Windows multisample-depth path.
add_test(NAME texture_cache_image_overlap
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --image-overlap-only)
add_test(NAME texture_cache_htile_clear
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --htile-clear-only)
add_test(NAME buffer_cache_ranges
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --buffer-cache-range-only)
endif()
add_test(NAME texture_cache_image_overlap
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --image-overlap-only)
add_test(NAME texture_cache_htile_clear
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --htile-clear-only)
add_test(NAME buffer_cache_ranges
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --buffer-cache-range-only)
add_custom_target(kyty_tests DEPENDS
ime_dialog_tests
shader_cfg_tests
scalar_provenance_tests
image_page_table_tests
memory_tracker_tests
page_manager_tests
archive_file_tests
trophy_system_tests
avplayer_file_tests
vdecsw_tests
bit_array_tests
lru_cache_tests
shader_vertex_metadata_tests
shader_stage_runtime_tests
resource_materialization_tests
resource_tracking_tests
resource_mutex_tests
event_queue_lifetime_tests
kernel_file_system_tests
sync_on_address_tests
shader_recompiler_compute_tests
virtual_memory_allocation_tests
audio_out2_port_tests
audio_out_timing_tests
ngs2_sampler_tests
pad_haptics_tests
controller_settings_tests
host_input_tests
save_data_memory_tests
png_enc_tests
ces_tests
save_data_dialog_tests
http_uri_parse_tests
)
endif()
# Test Darwin signal-context restoration for SSE4a instructions.
if(APPLE AND (CMAKE_OSX_ARCHITECTURES STREQUAL "x86_64" OR
(NOT CMAKE_OSX_ARCHITECTURES AND CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|AMD64)$")))
add_executable(macos_sse4a_tests EXCLUDE_FROM_ALL
"${KYTY_TESTS_DIR}/macosSse4aTests.cpp"
"${KYTY_SOURCE_DIR}/loader/x64InstructionEmulator.cpp"
"${KYTY_SOURCE_DIR}/loader/guestInstructionPatcher.cpp"
)
target_link_libraries(macos_sse4a_tests common fmt::fmt Zydis::Zydis xbyak::xbyak)
target_include_directories(macos_sse4a_tests PRIVATE ${inc_headers})
if(BUILD_TESTING)
add_test(NAME macos_sse4a COMMAND $<TARGET_FILE:macos_sse4a_tests>)
set_tests_properties(macos_sse4a PROPERTIES TIMEOUT 15)
add_dependencies(kyty_tests macos_sse4a_tests)
endif()
endif()
add_executable(kyty_emulator "${KYTY_SOURCE_DIR}/main.cpp" ${kyty_emulator_src})
configure_macos_guest_address_space(kyty_emulator)
set(KYTY_TROPHY_UNLOCK_SOUND "${CMAKE_CURRENT_SOURCE_DIR}/assets/sounds/trophy-unlock.wav")
add_custom_target(kyty_trophy_sound
COMMAND ${CMAKE_COMMAND} -E make_directory "$<TARGET_FILE_DIR:kyty_emulator>/assets/sounds"
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${KYTY_TROPHY_UNLOCK_SOUND}"
"$<TARGET_FILE_DIR:kyty_emulator>/assets/sounds/trophy-unlock.wav"
VERBATIM)
add_dependencies(kyty_emulator kyty_trophy_sound)
install(FILES "${KYTY_TROPHY_UNLOCK_SOUND}" DESTINATION assets/sounds)
add_custom_target(kyty_touch_cursors
COMMAND ${CMAKE_COMMAND} -E copy_directory
"${CMAKE_CURRENT_SOURCE_DIR}/assets/cursors"
"$<TARGET_FILE_DIR:kyty_emulator>/assets/cursors"
VERBATIM)
add_dependencies(kyty_emulator kyty_touch_cursors)
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/assets/cursors" DESTINATION assets)
target_link_libraries(kyty_emulator ${kyty_emulator_link_libraries})
if (WIN32)
target_link_libraries(kyty_emulator opengl32)
@@ -604,7 +809,16 @@ if(KYTY_CLANG_CL)
)
add_custom_command(TARGET kyty_emulator POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different "${KYTY_THIRD_PARTY_DIR}/winpthread/bin/libwinpthread-1.dll" $<TARGET_FILE_DIR:kyty_emulator>/libwinpthread-1.dll)
elseif(WIN32 OR LINUX)
set_target_properties(kyty_emulator PROPERTIES LINK_FLAGS "${KYTY_LD_OPTIONS} -Wl,-Map=${KYTY_EMULATOR_MAP_LINK_PATH}")
set_target_properties(kyty_emulator PROPERTIES LINK_FLAGS "${KYTY_LD_OPTIONS}")
# LINK_FLAGS is a space-delimited string: a -Map path containing spaces would
# be split into bogus arguments, so pass it as a discrete link option instead.
target_link_options(kyty_emulator PRIVATE "-Wl,-Map=${KYTY_EMULATOR_MAP_LINK_PATH}")
endif()
if(LINUX)
target_link_options(kyty_emulator PRIVATE
$<$<CONFIG:Release>:-Wl,--strip-all>
)
endif()
if(APPLE)
@@ -622,6 +836,10 @@ endif()
install(TARGETS kyty_emulator DESTINATION .)
if(KYTY_BUILD_LAUNCHER)
add_subdirectory("${KYTY_SOURCE_DIR}/launcher" "${CMAKE_CURRENT_BINARY_DIR}/launcher")
if(LINUX)
target_link_options(launcher PRIVATE $<$<CONFIG:Release>:-Wl,--strip-all>)
endif()
endif()
if(KYTY_CLANG_CL)
install(FILES "${KYTY_THIRD_PARTY_DIR}/winpthread/bin/libwinpthread-1.dll" DESTINATION .)
+181 -58
View File
@@ -1,16 +1,20 @@
# KytyPS5
[![Build KytyPS5 (Windows)](https://img.shields.io/github/actions/workflow/status/KytyPS5/KytyPS5/build.yml?branch=main&event=push&label=Build%20KytyPS5%20%28Windows%29)](https://github.com/KytyPS5/KytyPS5/actions/workflows/build.yml)
[![Build KytyPS5 (Linux)](https://img.shields.io/github/actions/workflow/status/KytyPS5/KytyPS5/build.yml?branch=main&event=push&label=Build%20KytyPS5%20%28Linux%29)](https://github.com/KytyPS5/KytyPS5/actions/workflows/build.yml)
[![Build KytyPS5 (macOS)](https://img.shields.io/github/actions/workflow/status/KytyPS5/KytyPS5/build.yml?branch=main&event=push&label=Build%20KytyPS5%20%28macOS%29)](https://github.com/KytyPS5/KytyPS5/actions/workflows/build.yml)
[![Build KytyPS5 (Windows)](https://img.shields.io/github/check-runs/KytyPS5/KytyPS5/main?nameFilter=Build%20KytyPS5%20%28Windows%29&label=Build%20KytyPS5%20%28Windows%29)](https://github.com/KytyPS5/KytyPS5/actions/workflows/build.yml)
[![Build KytyPS5 (Linux)](https://img.shields.io/github/check-runs/KytyPS5/KytyPS5/main?nameFilter=Build%20KytyPS5%20%28Linux%29&label=Build%20KytyPS5%20%28Linux%29)](https://github.com/KytyPS5/KytyPS5/actions/workflows/build.yml)
[![Build KytyPS5 (macOS)](https://img.shields.io/github/check-runs/KytyPS5/KytyPS5/main?nameFilter=Build%20KytyPS5%20%28macOS%29&label=Build%20KytyPS5%20%28macOS%29)](https://github.com/KytyPS5/KytyPS5/actions/workflows/build.yml)
[![Platform](https://img.shields.io/badge/platform-Windows%20x64%20%7C%20Linux%20x64%20%7C%20macOS%20x86__64-0078D4.svg)](#system-requirements)
[![Status](https://img.shields.io/badge/status-early%20development-orange.svg)](#current-status)
[![Status](https://img.shields.io/badge/status-active%20development-orange.svg)](#current-status)
[![License](https://img.shields.io/badge/license-GPL--2.0-blue.svg)](LICENSE)
KytyPS5 is a free and open-source PlayStation 5 emulator written in C++ for Windows and Linux,
with experimental macOS support. It is based on a heavily modified version of
[Kyty](https://github.com/InoriRus/Kyty). The project is in an early stage of development, so
compatibility is limited and behavior may change significantly between builds.
**[Weekly updates](https://github.com/KytyPS5/KytyPS5/discussions/862)** — game progress, recent fixes, and ongoing development.
**[Development on Discord](https://discord.gg/UNrkMqGaBg)** — KytyPS5 development.
KytyPS5 is a free and open-source PlayStation 5 translation layer written in C++ for Windows
and Linux, with experimental macOS support. It is based on a heavily modified version of
[Kyty](https://github.com/InoriRus/Kyty). The project is in active development, and behavior
can change significantly between builds.
> [!IMPORTANT]
> KytyPS5 is not affiliated with Sony Interactive Entertainment or PlayStation. The project does
@@ -19,40 +23,43 @@ compatibility is limited and behavior may change significantly between builds.
## Current Status
KytyPS5 can boot 2D games and a selection of 3D games, including titles built with Unreal Engine
4/5, Unity, and custom engines. No external low-level emulation modules are currently required.
KytyPS5 can boot 2D and 3D games, including titles built with Unreal Engine
4/5, Unity, and custom engines. External low-level emulation modules are neither required nor
planned.
Development is focused on compatibility and boot reliability.
Development is currently focused on expanding game compatibility and improving boot reliability.
Windows is the primary platform and receives the most testing. Linux builds and runs; see
[Building on Linux](#building-on-linux).
Windows and Linux are the primary target platforms and receive the most testing.
macOS support is experimental. The emulator is built for x86-64 and runs on Apple Silicon under
Rosetta 2, with Vulkan provided by MoltenVK. A small number of titles have been verified in-game
on Apple Silicon hardware; see [Building on macOS](#building-on-macos).
Community game test results are available in the
[KytyPS5 Compatibility List](https://kytyps5.github.io/).
## Bugs and Issues
The project is in an early stage, so please be mindful when opening new issues. Expect crashes,
graphical glitches, low compatibility, and poor performance.
Compatibility, stability, and performance can vary between versions. You may encounter crashes
or graphical glitches, so please include the version you tested when reporting an issue.
## Screenshots
<table align="center">
<tr>
<td align="center">
<strong>Disgaea 6</strong><br>
<img src="docs/screenshots/ps5-01.png" width="300" alt="Disgaea 6 running in KytyPS5">
<strong>Astro Bot</strong><br>
<img src="docs/screenshots/ps5-01.png" width="300" alt="Astro Bot running in KytyPS5">
</td>
<td align="center">
<strong>Dreaming Sarah</strong><br>
<img src="docs/screenshots/ps5-03.png" width="300" alt="Dreaming Sarah running in KytyPS5">
<strong>Saros</strong><br>
<img src="docs/screenshots/ps5-03.png" width="300" alt="Saros running in KytyPS5">
</td>
</tr>
<tr>
<td align="center">
<strong>Neptunia ReVerse</strong><br>
<img src="docs/screenshots/ps5-04.png" width="300" alt="Minecraft Legends running in KytyPS5">
<img src="docs/screenshots/ps5-04.png" width="300" alt="Neptunia ReVerse running in KytyPS5">
</td>
<td align="center">
<strong>SILENT HILL: The Short Message</strong><br>
@@ -61,12 +68,12 @@ graphical glitches, low compatibility, and poor performance.
</tr>
<tr>
<td align="center">
<strong>Hellboy</strong><br>
<img src="docs/screenshots/ps5-02.png" width="300" alt="Disgaea 6 running in KytyPS5">
<strong>Demon's Souls</strong><br>
<img src="docs/screenshots/ps5-02.png" width="300" alt="Demon's Souls running in KytyPS5">
</td>
<td align="center">
<strong>Paleo Pines</strong><br>
<img src="docs/screenshots/ps5-06.png" width="300" alt="Dreaming Sarah running in KytyPS5">
<strong>UFC 6</strong><br>
<img src="docs/screenshots/ps5-06.jpg" width="300" alt="UFC 6 running in KytyPS5">
</td>
</tr>
</table>
@@ -76,19 +83,31 @@ graphical glitches, low compatibility, and poor performance.
## Contributing
Testing games and submitting detailed bug reports are useful ways to contribute. Search existing
issues first, then use the **Game Emulation Bug Report** template and attach the complete log file.
issues first, then use the **Game Emulation Status Report** template and attach the complete log file.
Code contributions should be focused, build successfully on the platforms they touch, and include
relevant tests where practical. Windows is the primary target, so a change that alters shared code
should not regress it; changes confined to a platform's own code paths only need to build there. Because KytyPS5 is still evolving quickly, consider opening an issue before
starting a large change.
**Pull requests for general fixes, architectural changes, or refactoring that do not address a concrete bug or launch problem in a specific game will be automatically closed.**
**Large, unfocused commits or pull requests that bundle unrelated changes without a clear purpose or game-related benefit will also be automatically closed.**
Keep each PR focused. Name the affected game, describe the exact problem, and provide evidence showing what the change fixes.
Windows and Linux are the primary target platforms, so changes to shared code should not
introduce regressions on either platform. Changes confined to a platform's own code paths
only need to build on that platform. Because KytyPS5 is still evolving quickly, consider
opening an issue before starting a large change.
### Formatting
Set up the clang-format hook after cloning:
Set up the clang-format hook after cloning.
```powershell
python -m pip install pre-commit
Install `pre-commit` using the method appropriate for your platform:
- **Arch Linux / CachyOS:** `sudo pacman -S pre-commit`
- **Other Linux / macOS / Windows:** `python -m pip install pre-commit`
Then install the Git hook:
```bash
python -m pre_commit install --install-hooks
```
@@ -123,11 +142,13 @@ the Vulkan/SPIR-V validation rules.
### Build requirements (Windows)
- Git
- CMake 3.12 or newer
- CMake 3.22.1 or newer
- Ninja
- Visual Studio 2022 or Build Tools 2022 with the **Desktop development with C++** workload and
**C++ Clang tools for Windows** component
- Qt 6 for MSVC 2022 64-bit, including Concurrent, Network, and Widgets
- [glslang](https://github.com/KhronosGroup/glslang/releases) (`glslang` or `glslangValidator`) on `PATH`
- Python 3 on `PATH`; the bundled SPIRV-Tools runs it at configure time
The Microsoft C++ compiler (`cl.exe`) is not supported; use `clang-cl`.
@@ -156,20 +177,20 @@ The finished application and its runtime dependencies will be placed in
### Building on Linux
Install the toolchain and the libraries the bundled SDL2 needs. Without the audio, Wayland and
udev development packages SDL2 quietly configures itself without those backends, and the resulting
build has no working sound and no gamepad hotplug:
Install the toolchain and the libraries the bundled SDL3 needs. Without the audio, Wayland, and
udev development packages, SDL3 quietly configures itself without those backends, and the resulting
build has no working audio or gamepad hotplug support:
```bash
sudo apt-get install --no-install-recommends \
clang lld ninja-build cmake git glslang-tools \
clang lld ninja-build cmake git glslang-tools python3 pkg-config \
libgl1-mesa-dev libx11-dev libxcursor-dev libxext-dev libxfixes-dev \
libxi-dev libxrandr-dev libxss-dev libxkbcommon-dev \
libxi-dev libxrandr-dev libxss-dev libxtst-dev libxkbcommon-dev \
libasound2-dev libpulse-dev libudev-dev libdbus-1-dev libwayland-dev wayland-protocols
```
Qt 6 (Concurrent, Network, Widgets) is also required — either the distribution packages
(`qt6-base-dev`) or an official Qt installation.
Qt 6 (Concurrent, Network, and Widgets) is required for the launcher. Use your distribution's
packages (`qt6-base-dev`) or an official Qt installation.
```bash
git submodule update --init --recursive
@@ -183,13 +204,87 @@ cmake --install _Build/linux --prefix _Build/linux/install
```
The install step copies the Qt libraries and plugins next to the binaries, so
`_Build/linux/install` runs without a matching system Qt.
`_Build/linux/install` runs without a matching system Qt installation. FFmpeg is linked statically
from the pinned [KytyPS5 FFmpeg core](https://github.com/KytyPS5/ext-ffmpeg-core)
release, including VP9 and WebM support. System FFmpeg packages are not required.
To build `kyty_emulator` and the `kyty_tests` target without Qt, use a separate build directory:
```bash
git submodule update --init --recursive
cmake -S . -B _Build/linux-no-qt -G Ninja -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ \
-DKYTY_BUILD_LAUNCHER=OFF
cmake --build _Build/linux-no-qt --target kyty_emulator kyty_tests --parallel
```
As on Windows, the MSVC compiler is not used; Clang is required. `cl.exe` is rejected at configure
time.
The CMake source root is the repository root.
### Building on NixOS
A development shell provides Clang, CMake, Ninja, Qt 6, the Vulkan headers, and the SDL3 backend
libraries. Enter it and configure exactly as on other Linux distributions; the shell exports
`CMAKE_PREFIX_PATH` and `QT_PLUGIN_PATH`, so the `-DCMAKE_PREFIX_PATH="$Qt6_DIR"` argument is not
needed:
```bash
nix-shell # or: nix develop
git submodule update --init --recursive
cmake -S . -B _Build/linux -G Ninja -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
cmake --build _Build/linux --target launcher --parallel
cmake --install _Build/linux --prefix _Build/linux/install
```
The configure step downloads the FFmpeg prebuilts and the `xbyak`, `zydis`, `zstd`, and ZArchive
sources, so it needs network access; a fully sandboxed `nix build` would require vendoring those
inputs. A Vulkan 1.3 driver must be available at runtime (on NixOS,
`hardware.graphics.enable = true`).
### Building on Fedora and Fedora Atomic (Bazzite, Bluefin, Silverblue)
On regular Fedora, install dependencies on the host. On Fedora Atomic variants such as Bazzite,
Bluefin and Silverblue, use [Distrobox](https://distrobox.it/) and run the install and build steps
inside the container. Keep the checkout in your home directory so it is shared with the container.
Add `--nvidia` to the create command for hosts using the proprietary NVIDIA driver:
```bash
distrobox create --name kyty-build --image registry.fedoraproject.org/fedora:latest
distrobox enter kyty-build
```
Install the toolchain, Qt 6 and SDL3 dependencies:
```bash
sudo dnf install -y \
clang lld ninja-build cmake git glslang python3 pkgconf-pkg-config \
mesa-libGL-devel libX11-devel libXcursor-devel libXext-devel libXfixes-devel \
libXi-devel libXrandr-devel libXScrnSaver-devel libXtst-devel libxkbcommon-devel \
alsa-lib-devel pulseaudio-libs-devel systemd-devel dbus-devel \
wayland-devel wayland-protocols-devel qt6-qtbase-devel
```
From the repository root, follow the launcher configure, build and install steps in
[Building on Linux](#building-on-linux), omitting `-DCMAKE_PREFIX_PATH="$Qt6_DIR"`; CMake finds
Fedora's packaged Qt 6 automatically.
Run `./_Build/linux/install/kyty_launcher` on regular Fedora or inside the container. To launch a
container build from the host, leave the container with `exit`, then run from the repository root:
```bash
distrobox enter kyty-build -- ./_Build/linux/install/kyty_launcher
```
Qt libraries and plugins are bundled. You can also launch directly on a Fedora Atomic host
if its other system libraries are compatible with the container build.
### Building on macOS
macOS builds target x86-64 and run under Rosetta 2 on Apple Silicon, so the PS5's x86-64 game
@@ -200,8 +295,8 @@ Requirements:
- An Apple Silicon Mac with Rosetta 2 installed (`softwareupdate --install-rosetta`)
- Xcode (or the Command Line Tools)
- Homebrew packages: `brew install cmake ninja glslang`
- Qt 6 (Concurrent, Network, Widgets) with x86-64 support. The official Qt installation is
- Homebrew packages: `brew install cmake ninja glslang python`
- Qt 6 (Concurrent, Network, and Widgets) with x86-64 support. The official Qt installation is
universal and works; Homebrew's Qt is arm64-only and will not link
```bash
@@ -217,17 +312,23 @@ cmake --install _Build/macos --prefix _Build/macos/install
```
The build re-signs `kyty_emulator` with the JIT entitlements it needs to execute translated
guest code; no manual signing step is required.
guest code; no manual signing step is required. When the launcher is built, the installation
also produces `_Build/macos/install/KytyPS5.app` — double-click to launch the GUI.
A flat `kyty_emulator` is kept for CLI usage.
Vulkan comes from MoltenVK. Download `MoltenVK-macos.tar` from the
[MoltenVK releases](https://github.com/KhronosGroup/MoltenVK/releases), then copy
`MoltenVK/dynamic/dylib/macOS/libMoltenVK.dylib` next to `kyty_emulator` and ad-hoc sign it:
`MoltenVK/dynamic/dylib/macOS/libMoltenVK.dylib` next to the flat `kyty_emulator`
(and, for the bundle, into `KytyPS5.app/Contents/Frameworks/`) and sign it with an ad hoc signature:
```bash
codesign --force --sign - _Build/macos/install/libMoltenVK.dylib
# For the bundle (if present):
codesign --force --sign - _Build/macos/install/KytyPS5.app/Contents/Frameworks/libMoltenVK.dylib
codesign --force --sign - _Build/macos/install/KytyPS5.app
```
Release archives already include a signed `libMoltenVK.dylib`.
Release archives already include a signed `libMoltenVK.dylib` (both flat and inside the bundle).
### Regression tests
@@ -244,7 +345,7 @@ Use `_Build/linux` instead of `_Build/windows` for a Linux build.
A ready-made Visual Studio Code setup is included in [`.vscode`](.vscode). It configures CMake
Tools to build the project with Ninja and `clang-cl` and provides launch profiles for both
`launcher.exe` and `kyty_emulator.exe`. It is Windows-only: VS Code settings cannot select a
`kyty_launcher.exe` and `kyty_emulator.exe`. It is Windows-only: VS Code settings cannot select a
compiler per platform, so on Linux configure from the command line as shown above.
Before using it:
@@ -264,33 +365,54 @@ Update your graphics driver before reporting rendering problems.
To use the graphical launcher:
```powershell
.\_Build\windows\install\launcher.exe
.\_Build\windows\install\kyty_launcher.exe
```
```bash
./_Build/linux/install/launcher
./_Build/linux/install/kyty_launcher
```
```bash
open _Build/macos/install/KytyPS5.app # or double-click in Finder
```
On first launch, add one or more game folders in the global settings. The launcher searches those
folders recursively for game directories containing `eboot.bin`. Select a detected game and run it
from the game list.
folders recursively for game directories containing `eboot.bin` and ZArchive (`.zar`) game dumps
whose archive root contains `eboot.bin`. Select a detected game and run it from the game list.
ZArchive dumps are mounted read-only and streamed directly; they do not need to be extracted first.
The emulator can also be started directly with a legally obtained game directory or ELF file:
Official release builds include a built-in updater. Leave **Check for updates on startup** enabled,
or click **Check for updates**, then choose **Install Update**. The launcher downloads the package
for your platform from GitHub, checks its SHA-256 checksum, and restarts after installation. Close
any running games first. Settings, saves, patches, and other files outside the release package are
preserved; replacement failures restore the previous files. The installation folder must be writable.
If a package cannot be installed automatically, the updater offers the GitHub release page.
Source builds and builds from forks do not replace themselves with official releases.
The emulator can also be started directly with a legally obtained game directory, ELF file, or
ZArchive dump:
```powershell
.\_Build\windows\install\kyty_emulator.exe --game "D:\Games\ExampleGame"
.\_Build\windows\install\kyty_emulator.exe --game "D:\Games\ExampleGame.zar"
```
```bash
./_Build/linux/install/kyty_emulator --game "/games/ExampleGame"
./_Build/linux/install/kyty_emulator --game "/games/ExampleGame.zar"
```
On macOS, point SDL at the MoltenVK library explicitly; the hardened runtime prevents it from
being picked up from the executable's directory:
On macOS, the adjacent flat or app-bundled `libMoltenVK.dylib` is found automatically; no
environment variable is required:
```bash
cd _Build/macos/install
SDL_VULKAN_LIBRARY="$PWD/libMoltenVK.dylib" ./kyty_emulator --game "/games/ExampleGame"
./_Build/macos/install/kyty_emulator --game "/games/ExampleGame"
```
To override the Vulkan loader, set `SDL_VULKAN_LIBRARY`:
```bash
SDL_VULKAN_LIBRARY=/path/to/libMoltenVK.dylib ./kyty_emulator --game "/games/ExampleGame"
```
Run `kyty_emulator --help` to see the available graphics, logging, validation, profiling, and
@@ -321,5 +443,6 @@ licenses included with those components.
- [InoriRus/Kyty](https://github.com/InoriRus/Kyty) — KytyPS5 is based on a heavily modified version
of the original Kyty project.
- [shadps4-emu/shadPS4](https://github.com/shadps4-emu/shadPS4) — reference for memory-model
understanding and the AVPlayer implementation.
- [shadps4-emu/shadPS4](https://github.com/shadps4-emu/shadPS4) — reference for understanding PS4
memory behavior, GPU resource aliasing, cache coherency,
and the AVPlayer implementation.
Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

+4
View File
@@ -0,0 +1,4 @@
{
"trophy.toast.earned": "تم كسب الكأس!",
"user.guest": "ضيف"
}
+4
View File
@@ -0,0 +1,4 @@
{
"trophy.toast.earned": "Trofej získána!",
"user.guest": "Host"
}
+4
View File
@@ -0,0 +1,4 @@
{
"trophy.toast.earned": "Trofæ optjent!",
"user.guest": "Gæst"
}
+4
View File
@@ -0,0 +1,4 @@
{
"trophy.toast.earned": "Trophäe erhalten!",
"user.guest": "Gast"
}
+4
View File
@@ -0,0 +1,4 @@
{
"trophy.toast.earned": "Κερδίσατε ένα τρόπαιο!",
"user.guest": "Επισκ."
}
+4
View File
@@ -0,0 +1,4 @@
{
"trophy.toast.earned": "Trophy earned!",
"user.guest": "Guest"
}
+4
View File
@@ -0,0 +1,4 @@
{
"trophy.toast.earned": "Trophy earned!",
"user.guest": "Guest"
}
+4
View File
@@ -0,0 +1,4 @@
{
"trophy.toast.earned": "¡Ganaste un trofeo!",
"user.guest": "Invitado"
}
+4
View File
@@ -0,0 +1,4 @@
{
"trophy.toast.earned": "¡Ganaste un trofeo!",
"user.guest": "Invitado"
}
+4
View File
@@ -0,0 +1,4 @@
{
"trophy.toast.earned": "Pokaali ansaittu!",
"user.guest": "Vieras"
}
+4
View File
@@ -0,0 +1,4 @@
{
"trophy.toast.earned": "Trophée obtenu !",
"user.guest": "Invité"
}
+4
View File
@@ -0,0 +1,4 @@
{
"trophy.toast.earned": "Trophée obtenu !",
"user.guest": "Invité"
}
+4
View File
@@ -0,0 +1,4 @@
{
"trophy.toast.earned": "Trófea megszerezve!",
"user.guest": "Vendég"
}
+4
View File
@@ -0,0 +1,4 @@
{
"trophy.toast.earned": "Trofi diperoleh!",
"user.guest": "Tamu"
}
+4
View File
@@ -0,0 +1,4 @@
{
"trophy.toast.earned": "Trofeo ottenuto!",
"user.guest": "Ospite"
}
+4
View File
@@ -0,0 +1,4 @@
{
"trophy.toast.earned": "トロフィーを獲得しました!",
"user.guest": "ゲスト"
}
+4
View File
@@ -0,0 +1,4 @@
{
"trophy.toast.earned": "트로피를 획득했습니다!",
"user.guest": "게스트"
}
+4
View File
@@ -0,0 +1,4 @@
{
"trophy.toast.earned": "Trofee behaald!",
"user.guest": "Gast"
}
+4
View File
@@ -0,0 +1,4 @@
{
"trophy.toast.earned": "Trofé opptjent!",
"user.guest": "Gjest"
}
+4
View File
@@ -0,0 +1,4 @@
{
"trophy.toast.earned": "Zdobyto trofeum!",
"user.guest": "Gość"
}
+4
View File
@@ -0,0 +1,4 @@
{
"trophy.toast.earned": "Troféu conquistado!",
"user.guest": "Convidado"
}
+4
View File
@@ -0,0 +1,4 @@
{
"trophy.toast.earned": "Troféu conquistado!",
"user.guest": "Convidado"
}
+4
View File
@@ -0,0 +1,4 @@
{
"trophy.toast.earned": "Trofeu câștigat!",
"user.guest": "Invitat"
}
+4
View File
@@ -0,0 +1,4 @@
{
"trophy.toast.earned": "Трофей получен!",
"user.guest": "Гость"
}
+4
View File
@@ -0,0 +1,4 @@
{
"trophy.toast.earned": "Trofé intjänad!",
"user.guest": "Gäst"
}
+4
View File
@@ -0,0 +1,4 @@
{
"trophy.toast.earned": "ได้รับถ้วยรางวัลแล้ว!",
"user.guest": "แขก"
}
+4
View File
@@ -0,0 +1,4 @@
{
"trophy.toast.earned": "Kupa kazanıldı!",
"user.guest": "Misafir"
}
+4
View File
@@ -0,0 +1,4 @@
{
"trophy.toast.earned": "Đã nhận cúp!",
"user.guest": "Khách"
}
+4
View File
@@ -0,0 +1,4 @@
{
"trophy.toast.earned": "已获得奖杯!",
"user.guest": "访客"
}
+4
View File
@@ -0,0 +1,4 @@
{
"trophy.toast.earned": "已獲得獎盃!",
"user.guest": "訪客"
}
Binary file not shown.
+20
View File
@@ -0,0 +1,20 @@
# Notification localization
Trophy notification subtitles use the configured console language. Trophy names still come
from the game's metadata. The launcher trophy dialogs are unchanged.
Edit `assets/localization/<locale>.json`, using flat UTF-8 string values:
```json
{
"trophy.toast.earned": "Trophy earned!"
}
```
CMake converts the catalogs into C++ byte arrays in the build directory. The emulator parses
the embedded catalogs once and falls back to `en-US.json` for missing translations. No language
files or translation service are needed at runtime. Rebuild after editing a catalog.
For local testing, rebuild `kyty_emulator`, choose a game's Console Language in the launcher,
and unlock a trophy with notifications enabled. Installed system fonts provide non-Latin
glyphs; the selected language needs an appropriate font on the host.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 326 KiB

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 MiB

Generated
+27
View File
@@ -0,0 +1,27 @@
{
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1789426278,
"narHash": "sha256-GnotcvKtbTMnoVx6G4E7ZdUX6487Dky74dqq3pU7iRk=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "efe6f071ede9d21c37462d2d6682d5e670099684",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}
+20
View File
@@ -0,0 +1,20 @@
{
description = "KytyPS5 development shell";
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
outputs = { self, nixpkgs }:
let
systems = [ "x86_64-linux" ];
forAllSystems = nixpkgs.lib.genAttrs systems;
in
{
devShells = forAllSystems (system:
let
pkgs = import nixpkgs { inherit system; };
in
{
default = import ./nix/devshell.nix { inherit pkgs; };
});
};
}
+85
View File
@@ -0,0 +1,85 @@
{ pkgs }:
let
# Build-time dependencies for the bundled SDL3 audio, video and input backends.
buildDeps = with pkgs; [
qt6.qtbase # Concurrent, Network, Widgets (launcher)
vulkan-headers
vulkan-loader
vulkan-tools
vulkan-validation-layers
libglvnd
# X11 / input
libX11
libXcursor
libXext
libXfixes
libXi
libXrandr
libXScrnSaver
libXtst
libxkbcommon
# Wayland
wayland
wayland-protocols
libdecor
# audio + device/dbus
alsa-lib
libpulseaudio
systemd # libudev
dbus
];
# Libraries the built binaries need at runtime.
runtimeLibs = with pkgs; [
stdenv.cc.cc.lib # libstdc++ / libgcc_s
libgcc.lib
qt6.qtbase # libQt6Concurrent/Network/Widgets
vulkan-loader
libglvnd
alsa-lib
libpulseaudio
libX11
libXcursor
libXext
libXfixes
libXi
libXrandr
libXScrnSaver
libXtst
libxkbcommon
wayland
libdecor
systemd
dbus
];
in
pkgs.mkShell {
name = "kytyps5";
nativeBuildInputs = with pkgs; [
clang
lld
cmake
ninja
pkg-config
git
glslang # provides glslangValidator for the bundled shaders
];
buildInputs = buildDeps;
shellHook = ''
export CMAKE_PREFIX_PATH="${pkgs.qt6.qtbase}:''${CMAKE_PREFIX_PATH:-}"
export QT_PLUGIN_PATH="${pkgs.qt6.qtbase}/lib/qt-6/plugins:${pkgs.qt6.qtbase}/lib/qt6/plugins:''${QT_PLUGIN_PATH:-}"
export LD_LIBRARY_PATH="${pkgs.lib.makeLibraryPath runtimeLibs}:''${LD_LIBRARY_PATH:-}"
if [ -z "''${KYTY_SHELL_QUIET:-}" ]; then
echo "KytyPS5 dev shell"
echo " cmake -S . -B _Build/linux -G Ninja -DCMAKE_BUILD_TYPE=Release \\"
echo " -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++"
echo " cmake --build _Build/linux --target launcher --parallel"
echo " cmake --install _Build/linux --prefix _Build/linux/install"
fi
'';
}
+4
View File
@@ -0,0 +1,4 @@
let
pkgs = import <nixpkgs> { };
in
import ./nix/devshell.nix { inherit pkgs; }
+21
View File
@@ -12,9 +12,23 @@ endif()
add_library(common STATIC ${common_src} ${common_headers})
set(localization_dir "${PROJECT_SOURCE_DIR}/assets/localization")
file(GLOB localization_catalogs CONFIGURE_DEPENDS "${localization_dir}/*.json")
set(localization_data "${CMAKE_CURRENT_BINARY_DIR}/localizationData.h")
add_custom_command(
OUTPUT "${localization_data}"
COMMAND ${CMAKE_COMMAND} "-DINPUTS=${localization_catalogs}" "-DOUTPUT=${localization_data}"
-P "${KYTY_SOURCE_DIR}/embed_localization.cmake"
DEPENDS ${localization_catalogs} "${KYTY_SOURCE_DIR}/embed_localization.cmake"
COMMENT "Embed notification localization catalogs"
VERBATIM
)
target_sources(common PRIVATE "${localization_data}")
target_include_directories(common
PUBLIC ${KYTY_SOURCE_DIR}
PRIVATE
${CMAKE_CURRENT_BINARY_DIR}
${KYTY_THIRD_PARTY_DIR}/cpuinfo/include
)
@@ -24,8 +38,15 @@ target_link_libraries(common
Tracy::TracyClient
PRIVATE
cpuinfo
kyty_git_version
spdlog::spdlog
ZArchive::zarchive
nlohmann_json::nlohmann_json
)
if(APPLE)
# hostStats.cpp reads GPU utilization from the IOAccelerator registry entries.
target_link_libraries(common PRIVATE "-framework CoreFoundation" "-framework IOKit")
endif()
get_property(inc_headers TARGET common PROPERTY INCLUDE_DIRECTORIES)
set(check_headers ${CMAKE_CURRENT_SOURCE_DIR})
+112
View File
@@ -0,0 +1,112 @@
#include "common/additionalContent.h"
#include "common/stringUtils.h"
#include <algorithm>
#include <fstream>
#include <map>
#include <nlohmann/json.hpp>
#include <regex>
#include <system_error>
namespace Common {
namespace {
std::string GetString(const nlohmann::json& object, const std::string& key) {
const auto it = object.find(key);
return it != object.end() && it->is_string() ? it->get<std::string>() : std::string {};
}
std::string GetTitle(const nlohmann::json& param) {
const auto localized = param.find("localizedParameters");
if (localized != param.end() && localized->is_object()) {
const auto preferred = localized->find(GetString(*localized, "defaultLanguage"));
if (preferred != localized->end()) {
if (auto title = GetString(*preferred, "titleName"); !title.empty()) {
return title;
}
}
for (const auto& language: *localized) {
if (auto title = GetString(language, "titleName"); !title.empty()) {
return title;
}
}
}
return GetString(param, "titleName");
}
} // namespace
std::vector<AddContentEntry> FindAddContent(const std::filesystem::path& dir,
const std::string& title_id) {
if (dir.empty() || title_id.empty()) {
return {};
}
std::error_code ec;
const auto root = std::filesystem::absolute(dir, ec);
if (ec) {
return {};
}
// Scan directories separately so an unreadable child does not discard its siblings.
std::vector<std::filesystem::path> pending {root};
std::vector<std::filesystem::path> params;
while (!pending.empty()) {
const auto current = std::move(pending.back());
pending.pop_back();
std::filesystem::directory_iterator it(
current, std::filesystem::directory_options::skip_permission_denied, ec);
const std::filesystem::directory_iterator end;
for (; !ec && it != end; it.increment(ec)) {
std::error_code entry_ec;
if (it->is_directory(entry_ec) && !it->is_symlink(entry_ec) && !entry_ec) {
pending.push_back(it->path());
} else if (it->is_regular_file(entry_ec) && !entry_ec &&
EqualNoCase(PathToString(it->path().filename()), "param.json") &&
EqualNoCase(PathToString(it->path().parent_path().filename()), "sce_sys")) {
params.push_back(it->path());
}
}
}
std::sort(params.begin(), params.end());
static const std::regex content_id_pattern(
"^[A-Z]{2}[0-9]{4}-[A-Z]{4}[0-9]{5}_[0-9]{2}-[A-Z0-9]{16}$");
std::map<std::string, AddContentEntry> by_label;
for (const auto& file: params) {
const auto size = std::filesystem::file_size(file, ec);
if (ec || size > 1024 * 1024) {
continue;
}
std::ifstream stream(file, std::ios::binary);
if (!stream) {
continue;
}
const auto param = nlohmann::json::parse(stream, nullptr, false);
// applicationCategoryType is required for applications, not additional content.
if (!param.is_object() || param.contains("applicationCategoryType")) {
continue;
}
const auto content_id = GetString(param, "contentId");
if (!std::regex_match(content_id, content_id_pattern) ||
content_id.compare(7, 9, title_id) != 0) {
continue;
}
const auto mount_dir = file.parent_path().parent_path();
const auto label = content_id.substr(20);
by_label.try_emplace(label,
AddContentEntry {content_id, label, mount_dir, GetTitle(param)});
}
std::vector<AddContentEntry> entries;
entries.reserve(by_label.size());
for (auto& [label, entry]: by_label) {
entries.push_back(std::move(entry));
}
return entries;
}
} // namespace Common
+23
View File
@@ -0,0 +1,23 @@
#ifndef KYTY_COMMON_ADDITIONAL_CONTENT_H_
#define KYTY_COMMON_ADDITIONAL_CONTENT_H_
#include <filesystem>
#include <string>
#include <vector>
namespace Common {
struct AddContentEntry {
std::string content_id;
std::string entitlement_label;
std::filesystem::path mount_dir;
std::string title;
};
// Finds packages for this title, deduplicated by entitlement label.
std::vector<AddContentEntry> FindAddContent(const std::filesystem::path& dir,
const std::string& title_id);
} // namespace Common
#endif /* KYTY_COMMON_ADDITIONAL_CONTENT_H_ */
+25
View File
@@ -0,0 +1,25 @@
// SPDX-FileCopyrightText: 2014 Jannik Vogel <email@jannikvogel.de>
// SPDX-License-Identifier: CC0-1.0
#pragma once
#include <cstddef>
#include <type_traits>
namespace Common {
template <typename T>
[[nodiscard]] constexpr T AlignUp(T value, std::size_t size) {
static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
auto mod{static_cast<T>(value % size)};
value -= mod;
return static_cast<T>(mod == T{0} ? value : value + size);
}
template <typename T>
[[nodiscard]] constexpr T AlignDown(T value, std::size_t size) {
static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
return static_cast<T>(value - value % size);
}
} // namespace Common
+397
View File
@@ -0,0 +1,397 @@
#include "common/archive.h"
#include "common/stringUtils.h"
#include <algorithm>
#include <condition_variable>
#include <cstring>
#include <mutex>
#include <optional>
#include <string_view>
#include <thread>
#include <unordered_map>
#include <utility>
#include <zarchive/zarchivereader.h>
// POSIX hosts and MinGW's pthread-backed libstdc++ have cancellable condition waits.
// MSVC/ClangCL and MinGW's native Win32 threading backend do not use pthread waits.
#if !defined(_WIN32) || defined(_GLIBCXX_GCC_GTHR_POSIX_H)
#include <pthread.h>
#define KYTY_ARCHIVE_PTHREAD_CANCELLATION
#endif
namespace Common {
// Backends expose immutable metadata and offset-based reads. Cursor management, path routing,
// reader lifetime and the host-stack worker are shared by every archive format.
class ArchiveReader {
public:
struct Entry {
uint64_t id;
uint64_t size;
bool is_file;
};
virtual ~ArchiveReader() = default;
virtual std::optional<Entry> Find(std::string_view member) = 0;
virtual std::vector<File::DirEntry> List(std::string_view member) = 0;
virtual uint64_t Read(uint64_t id, uint64_t offset, uint32_t size, void* data) = 0;
};
namespace {
class ZArchiveReaderBackend final: public ArchiveReader {
public:
explicit ZArchiveReaderBackend(std::unique_ptr<ZArchiveReader> reader)
: m_reader(std::move(reader)) {}
std::optional<Entry> Find(std::string_view member) override {
const auto node = m_reader->LookUp(member);
if (node == ZARCHIVE_INVALID_NODE) {
return {};
}
return Entry {node, m_reader->GetFileSize(node), m_reader->IsFile(node)};
}
std::vector<File::DirEntry> List(std::string_view member) override {
const auto node = m_reader->LookUp(member);
if (!m_reader->IsDirectory(node)) {
return {};
}
const auto count = m_reader->GetDirEntryCount(node);
if (count > (1u << 20u)) {
return {};
}
std::vector<File::DirEntry> result;
result.reserve(count);
for (uint32_t index = 0; index < count; ++index) {
ZArchiveReader::DirEntry entry {};
if (m_reader->GetDirEntry(node, index, entry)) {
result.push_back({std::string(entry.name), entry.isFile});
}
}
return result;
}
uint64_t Read(uint64_t id, uint64_t offset, uint32_t size, void* data) override {
// ZArchiveReader already serializes access to its stream and decompression cache.
return m_reader->ReadFromFile(static_cast<ZArchiveNodeHandle>(id), offset, size, data);
}
private:
std::unique_ptr<ZArchiveReader> m_reader;
};
std::shared_ptr<ArchiveReader> OpenZArchive(const std::filesystem::path& path) {
auto reader = std::unique_ptr<ZArchiveReader>(ZArchiveReader::OpenFromFile(path));
return reader ? std::make_shared<ZArchiveReaderBackend>(std::move(reader)) : nullptr;
}
struct ArchiveFormat {
std::string_view extension;
std::shared_ptr<ArchiveReader> (*open)(const std::filesystem::path&);
};
constexpr ArchiveFormat Formats[] = {{".zar", OpenZArchive}};
using NativeView = std::basic_string_view<std::filesystem::path::value_type>;
const ArchiveFormat* FindFormat(NativeView path) {
for (const auto& format: Formats) {
if (path.size() < format.extension.size()) {
continue;
}
const auto extension = path.substr(path.size() - format.extension.size());
if (std::equal(
extension.begin(), extension.end(), format.extension.begin(),
[](auto a, char b) { return (a >= 'A' && a <= 'Z' ? a + ('a' - 'A') : a) == b; })) {
return &format;
}
}
return nullptr;
}
size_t FindMarker(NativeView path) {
// Native files use this check on every operation. The usual path has no marker and allocates
// nothing.
for (auto marker = path.find('!'); marker != NativeView::npos;
marker = path.find('!', marker + 1)) {
if ((marker + 1 == path.size() || path[marker + 1] == '/' || path[marker + 1] == '\\') &&
FindFormat(path.substr(0, marker)) != nullptr) {
return marker;
}
}
return NativeView::npos;
}
struct ParsedPath {
std::filesystem::path archive;
std::string member;
};
std::optional<ParsedPath> ParsePath(const std::filesystem::path& path) {
const auto& native = path.native();
const auto marker = FindMarker(native);
if (marker == NativeView::npos) {
return {};
}
ParsedPath parsed {.archive = std::filesystem::path(native.substr(0, marker))};
auto member = PathToGenericString(std::filesystem::path(native.substr(marker + 1)));
std::replace(member.begin(), member.end(), '\\', '/');
std::string_view remaining = member;
while (!remaining.empty()) {
const auto separator = remaining.find('/');
const auto component = remaining.substr(0, separator);
remaining.remove_prefix(separator == std::string_view::npos ? remaining.size() : separator + 1);
if (component.empty() || component == ".") {
continue;
}
if (component == "..") {
if (parsed.member.empty()) {
return {};
}
const auto separator = parsed.member.rfind('/');
parsed.member.resize(separator == std::string::npos ? 0 : separator);
} else {
if (!parsed.member.empty()) {
parsed.member += '/';
}
parsed.member += component;
}
}
return parsed;
}
std::mutex g_readers_mutex;
std::unordered_map<std::filesystem::path, std::weak_ptr<ArchiveReader>> g_readers;
// Guest stacks can be only 64 KiB. Decompress on an ordinary host stack, then copy into guest
// memory on the caller so GPU-tracked writes use its fault handler. A single worker bounds host
// threads and avoids duplicating the archive's own block cache. Requests live on waiting callers.
class ArchiveIoThread {
public:
static ArchiveIoThread& Instance() {
// Guest exit can run static destructors while other guest threads are still reading.
// Keep the worker alive until process termination, as with the guest threads themselves.
static auto* instance = new ArchiveIoThread;
return *instance;
}
uint64_t Read(ArchiveReader& reader, uint64_t id, uint64_t offset, uint32_t size, void* data) {
Request request {reader, id, offset, size, data};
std::unique_lock lock(m_mutex);
if (m_last != nullptr) {
m_last->next = &request;
} else {
m_first = &request;
}
m_last = &request;
m_wake.notify_one();
request.ready.wait(lock, [&] { return request.done; });
return request.result;
}
KYTY_CLASS_NO_COPY(ArchiveIoThread);
private:
struct Request {
ArchiveReader& reader;
uint64_t id;
uint64_t offset;
uint32_t size;
void* data;
Request* next = nullptr;
uint64_t result = 0;
bool done = false;
std::condition_variable ready {};
};
ArchiveIoThread() {
std::thread([this] { Loop(); }).detach();
}
void Loop() {
for (;;) {
Request* request;
{
std::unique_lock lock(m_mutex);
m_wake.wait(lock, [this] { return m_first != nullptr; });
request = m_first;
m_first = request->next;
if (m_first == nullptr) {
m_last = nullptr;
}
}
const auto result =
request->reader.Read(request->id, request->offset, request->size, request->data);
{
std::lock_guard lock(m_mutex);
request->result = result;
request->done = true;
// Notify before releasing the mutex: the waiting caller owns the condition
// variable.
request->ready.notify_one();
}
}
}
std::mutex m_mutex;
std::condition_variable m_wake;
Request* m_first = nullptr;
Request* m_last = nullptr;
};
} // namespace
struct ArchiveFile::Private {
std::shared_ptr<ArchiveReader> reader;
ArchiveReader::Entry entry;
uint64_t position = 0;
};
ArchiveFile::ArchiveFile(std::unique_ptr<Private> p): m_p(std::move(p)) {}
ArchiveFile::~ArchiveFile() = default;
uint64_t ArchiveFile::Size() const {
return m_p->entry.size;
}
uint64_t ArchiveFile::Tell() const {
return m_p->position;
}
bool ArchiveFile::Seek(uint64_t offset) {
m_p->position = offset;
return true;
}
void ArchiveFile::Read(void* data, uint32_t size, uint32_t* bytes_read) {
#if defined(KYTY_ARCHIVE_PTHREAD_CANCELLATION)
// A pending cancellation must not destroy the waiting request or its TLS buffer while the
// worker still uses them. Restore the caller's state only after the copy is complete.
int cancellation_state = PTHREAD_CANCEL_ENABLE;
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancellation_state);
#endif
constexpr uint32_t chunk_size = 1u << 20u;
thread_local std::vector<uint8_t> chunk;
uint32_t read = 0;
if (data != nullptr && size != 0 && m_p->position < Size()) {
const auto requested =
static_cast<uint32_t>(std::min<uint64_t>(size, Size() - m_p->position));
if (chunk.size() < std::min(chunk_size, requested)) {
chunk.resize(std::min(chunk_size, requested));
}
while (read < requested) {
const auto step = std::min(chunk_size, requested - read);
const auto got = ArchiveIoThread::Instance().Read(*m_p->reader, m_p->entry.id,
m_p->position, step, chunk.data());
if (got == 0 || got > step) {
break;
}
std::memcpy(static_cast<uint8_t*>(data) + read, chunk.data(), got);
read += static_cast<uint32_t>(got);
m_p->position += got;
if (got < step) {
break;
}
}
}
if (bytes_read != nullptr) {
*bytes_read = read;
}
#if defined(KYTY_ARCHIVE_PTHREAD_CANCELLATION)
pthread_setcancelstate(cancellation_state, nullptr);
#endif
}
std::filesystem::path MakeArchivePath(const std::filesystem::path& archive,
const std::filesystem::path& member) {
auto root = archive;
root += "!";
return member.empty() ? root : root / member.relative_path();
}
bool IsSupportedArchive(const std::filesystem::path& path) {
return FindFormat(path.native()) != nullptr;
}
bool IsArchivePath(const std::filesystem::path& path) {
return FindMarker(path.native()) != NativeView::npos;
}
std::filesystem::path GetArchiveHostPath(const std::filesystem::path& path) {
const auto marker = FindMarker(path.native());
return marker == NativeView::npos ? std::filesystem::path {}
: std::filesystem::path(path.native().substr(0, marker));
}
std::shared_ptr<ArchiveReader> OpenArchive(const std::filesystem::path& path) {
const auto archive = IsArchivePath(path) ? GetArchiveHostPath(path) : path;
const auto* format = FindFormat(archive.native());
if (format == nullptr) {
return {};
}
std::error_code error;
auto key = std::filesystem::absolute(archive, error);
if (error) {
return {};
}
{
std::lock_guard lock(g_readers_mutex);
if (auto it = g_readers.find(key); it != g_readers.end()) {
if (auto reader = it->second.lock()) {
return reader;
}
}
}
// Do not hold the cache mutex while opening an unrelated archive from disk.
auto reader = format->open(archive);
if (reader == nullptr) {
return {};
}
std::lock_guard lock(g_readers_mutex);
std::erase_if(g_readers, [](const auto& entry) { return entry.second.expired(); });
auto& cached = g_readers[key];
if (auto existing = cached.lock()) {
return existing;
}
cached = reader;
return reader;
}
std::optional<File::Info> GetArchiveInfo(const std::filesystem::path& path) {
const auto parsed = ParsePath(path);
if (parsed) {
if (auto reader = OpenArchive(parsed->archive)) {
if (auto entry = reader->Find(parsed->member)) {
return File::Info {entry->is_file, entry->size};
}
}
}
return {};
}
std::vector<File::DirEntry> GetArchiveDirEntries(const std::filesystem::path& path) {
const auto parsed = ParsePath(path);
if (parsed) {
if (auto reader = OpenArchive(parsed->archive)) {
return reader->List(parsed->member);
}
}
return {};
}
std::unique_ptr<ArchiveFile> OpenArchiveFile(const std::filesystem::path& path) {
auto parsed = ParsePath(path);
if (!parsed) {
return {};
}
auto reader = OpenArchive(parsed->archive);
const auto entry = reader ? reader->Find(parsed->member) : std::nullopt;
if (!entry || !entry->is_file) {
return {};
}
auto p = std::make_unique<ArchiveFile::Private>();
p->reader = std::move(reader);
p->entry = *entry;
return std::unique_ptr<ArchiveFile>(new ArchiveFile(std::move(p)));
}
} // namespace Common
+50
View File
@@ -0,0 +1,50 @@
#ifndef KYTY_COMMON_ARCHIVE_H_
#define KYTY_COMMON_ARCHIVE_H_
#include "common/file.h"
#include <cstdint>
#include <filesystem>
#include <memory>
#include <vector>
namespace Common {
class ArchiveReader;
class ArchiveFile {
public:
~ArchiveFile();
[[nodiscard]] uint64_t Size() const;
[[nodiscard]] uint64_t Tell() const;
bool Seek(uint64_t offset);
void Read(void* data, uint32_t size, uint32_t* bytes_read);
KYTY_CLASS_NO_COPY(ArchiveFile);
private:
struct Private;
explicit ArchiveFile(std::unique_ptr<Private> p);
std::unique_ptr<Private> m_p;
friend std::unique_ptr<ArchiveFile> OpenArchiveFile(const std::filesystem::path& path);
};
// Virtual paths use "archive.ext!/member" and retain native host-path encoding.
[[nodiscard]] std::filesystem::path MakeArchivePath(const std::filesystem::path& archive,
const std::filesystem::path& member = {});
[[nodiscard]] bool IsSupportedArchive(const std::filesystem::path& path);
[[nodiscard]] bool IsArchivePath(const std::filesystem::path& path);
[[nodiscard]] std::optional<File::Info> GetArchiveInfo(const std::filesystem::path& path);
[[nodiscard]] std::vector<File::DirEntry> GetArchiveDirEntries(const std::filesystem::path& path);
[[nodiscard]] std::filesystem::path GetArchiveHostPath(const std::filesystem::path& path);
[[nodiscard]] std::unique_ptr<ArchiveFile> OpenArchiveFile(const std::filesystem::path& path);
// Retain this handle while a mount or metadata scan is active to reuse the index and block cache.
// Accepts either a host archive filename or a virtual path inside the archive.
[[nodiscard]] std::shared_ptr<ArchiveReader> OpenArchive(const std::filesystem::path& path);
} // namespace Common
#endif /* KYTY_COMMON_ARCHIVE_H_ */
+5 -19
View File
@@ -1,8 +1,8 @@
#include "common/assert.h"
#include "common/debug.h"
#include "common/logging/log.h"
#include "common/subsystems.h"
#include "kytyGitVersion.h"
#include <cstdio>
#include <cstdlib>
@@ -11,30 +11,15 @@
namespace Common {
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS && KYTY_BUILD == KYTY_BUILD_DEBUG && \
KYTY_COMPILER == KYTY_COMPILER_CLANG
constexpr int PRINT_STACK_FROM = 4;
#else
constexpr int PRINT_STACK_FROM = 2;
#endif
static std::string BuildFatalReport(const char* title, std::string_view text, const char* file,
int line) {
DebugStack stack;
DebugStack::Trace(&stack);
std::string report = "--- Stack Trace ---\n";
for (int i = PRINT_STACK_FROM; i < stack.depth; i++) {
report += fmt::format("[{}] {:016x}\n", i - PRINT_STACK_FROM,
static_cast<uint64_t>(stack.GetAddr(i)));
}
report += fmt::format("{}\n{} in {}:{}\n", title, text, file, line);
return report;
return fmt::format("--- Build ---\n{}\n{}\n{} in {}:{}\n", KYTY_BUILD_LABEL, title, text, file,
line);
}
static int DbgReport(const char* title, std::string_view text, const char* file, int line) {
Log::WriteFatal(BuildFatalReport(title, text, file, line));
SubsystemsListSingleton::Instance()->ShutdownAll();
Subsystems::EmergencyShutdownActive();
return 1;
}
@@ -58,6 +43,7 @@ int DbgExitHandler(const char* file, int line, fmt::text_style style, std::strin
}
void DbgExit(int status) {
Subsystems::EmergencyShutdownActive();
std::fflush(nullptr);
std::_Exit(status);
}
-4
View File
@@ -29,11 +29,7 @@ void DbgExit(int status);
} // namespace Common
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS || KYTY_PLATFORM == KYTY_PLATFORM_LINUX
#define EXIT_HALT() (Common::DbgExit(321), 1)
#else
#define EXIT_HALT() (std::_Exit(321), 1)
#endif
#ifndef KYTY_FINAL
#define EXIT_IF(x) \
-166
View File
@@ -1,166 +0,0 @@
#ifndef KYTY_COMMON_BYTEBUFFER_H_
#define KYTY_COMMON_BYTEBUFFER_H_
#include "common/assert.h"
#include "common/common.h"
#include <algorithm>
#include <cstddef> // IWYU pragma: export
#include <cstring>
#include <utility>
#include <vector>
namespace Common {
using Byte = std::byte;
class ByteBuffer {
public:
using DataType = std::vector<Byte>;
static constexpr uint32_t INVALID_INDEX = static_cast<uint32_t>(-1);
using iterator = DataType::iterator;
using const_iterator = DataType::const_iterator;
ByteBuffer() = default;
ByteBuffer(const ByteBuffer&) = default;
ByteBuffer(ByteBuffer&&) = default;
ByteBuffer& operator=(const ByteBuffer&) = default;
ByteBuffer& operator=(ByteBuffer&&) = default;
explicit ByteBuffer(uint32_t size): m_data(size) {}
ByteBuffer(std::initializer_list<uint8_t> list) {
for (const uint8_t& e: list) {
m_data.emplace_back(static_cast<Byte>(e));
}
}
explicit ByteBuffer(const void* buf, uint32_t size)
: ByteBuffer(size) // @suppress("Ambiguous problem")
{
EXIT_IF(buf == nullptr && size != 0);
if (size != 0) {
std::memcpy(m_data.data(), buf, size);
}
}
[[nodiscard]] uint32_t Size() const { return static_cast<uint32_t>(m_data.size()); }
[[nodiscard]] bool IsEmpty() const { return m_data.empty(); }
void Clear() { m_data.clear(); }
void Add(const Byte& val) { m_data.push_back(val); }
void Add(Byte&& val) { m_data.push_back(std::move(val)); }
void Add(const Byte* val, uint32_t num) {
EXIT_IF(val == nullptr && num != 0);
m_data.insert(m_data.end(), val, val + num);
}
void Add(const ByteBuffer& v) {
if (this == &v) {
const ByteBuffer copy(v);
Add(copy.GetDataConst(), copy.Size());
return;
}
Add(v.GetDataConst(), v.Size());
}
void InsertAt(uint32_t index, const Byte& val) {
EXIT_IF(index > Size());
m_data.insert(m_data.begin() + index, val);
}
void InsertAt(uint32_t index, Byte&& val) {
EXIT_IF(index > Size());
m_data.insert(m_data.begin() + index, std::move(val));
}
[[nodiscard]] uint32_t Find(const Byte& t) const {
const auto it = std::find(m_data.begin(), m_data.end(), t);
return (it == m_data.end() ? INVALID_INDEX
: static_cast<uint32_t>(std::distance(m_data.begin(), it)));
}
[[nodiscard]] bool Contains(const Byte& t) const { return Find(t) != INVALID_INDEX; }
bool Remove(const Byte& t) {
const auto it = std::find(m_data.begin(), m_data.end(), t);
if (it == m_data.end()) {
return false;
}
m_data.erase(it);
return true;
}
bool RemoveAt(uint32_t index, uint32_t count = 1) {
if (index >= Size() || count == 0) {
return false;
}
const uint32_t erase_count = std::min(count, Size() - index);
m_data.erase(m_data.begin() + index, m_data.begin() + index + erase_count);
return true;
}
[[nodiscard]] bool IndexValid(uint32_t index) const { return index < Size(); }
Byte& operator[](uint32_t index) {
EXIT_IF(index >= Size());
return m_data[index];
}
const Byte& operator[](uint32_t index) const {
EXIT_IF(index >= Size());
return m_data[index];
}
[[nodiscard]] const Byte& At(uint32_t index) const {
EXIT_IF(index >= Size());
return m_data[index];
}
Byte* GetData() { return m_data.data(); }
[[nodiscard]] const Byte* GetData() const { return m_data.data(); }
[[nodiscard]] const Byte* GetDataConst() const { return m_data.data(); }
void Sort() {
std::sort(m_data.begin(), m_data.end(), [](Byte a, Byte b) {
return std::to_integer<uint8_t>(a) < std::to_integer<uint8_t>(b);
});
}
template <typename OP>
void Sort(OP&& comp_func) {
std::sort(m_data.begin(), m_data.end(), std::forward<OP>(comp_func));
}
bool operator==(const ByteBuffer& s) const { return m_data == s.m_data; }
bool operator!=(const ByteBuffer& s) const { return !(*this == s); }
iterator begin() { return m_data.begin(); } // NOLINT(readability-identifier-naming)
iterator end() { return m_data.end(); } // NOLINT(readability-identifier-naming)
[[nodiscard]] const_iterator begin() const {
return m_data.begin();
} // NOLINT(readability-identifier-naming)
[[nodiscard]] const_iterator end() const {
return m_data.end();
} // NOLINT(readability-identifier-naming)
[[nodiscard]] const_iterator cbegin() const {
return m_data.cbegin();
} // NOLINT(readability-identifier-naming)
[[nodiscard]] const_iterator cend() const {
return m_data.cend();
} // NOLINT(readability-identifier-naming)
private:
DataType m_data;
};
} // namespace Common
#endif /* KYTY_COMMON_BYTEBUFFER_H_ */
-21
View File
@@ -1,21 +0,0 @@
#include "common/commonSubsystem.h"
#include "common/byteBuffer.h" // IWYU pragma: associated
#include "common/common.h" // IWYU pragma: associated
#include "common/debug.h" // IWYU pragma: associated
#include "common/hash.h" // IWYU pragma: associated
#include "common/magicEnum.h" // IWYU pragma: associated
#include "common/singleton.h" // IWYU pragma: associated
#include "common/virtualMemory.h"
namespace Common {
KYTY_SUBSYSTEM_INIT(Common) {
VirtualMemory::Init();
}
KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(Common) {}
KYTY_SUBSYSTEM_DESTROY(Common) {}
} // namespace Common
-12
View File
@@ -1,12 +0,0 @@
#ifndef KYTY_COMMON_COMMON_SUBSYSTEM_H_
#define KYTY_COMMON_COMMON_SUBSYSTEM_H_
#include "common/subsystems.h"
namespace Common {
KYTY_SUBSYSTEM_DEFINE(Common);
} // namespace Common
#endif /* KYTY_COMMON_COMMON_SUBSYSTEM_H_ */
-17
View File
@@ -1,20 +1,7 @@
#include "common/debug.h"
#include "common/platform/sysDbg.h"
namespace Common {
void DebugStack::Print(int from, [[maybe_unused]] bool with_name) const {
for (int i = from; i < depth; i++) {
printf("[%d] %016" PRIx64 "\n", i - from, static_cast<uint64_t>(GetAddr(i)));
}
}
void DebugStack::Trace(DebugStack* stack) {
stack->depth = DEBUG_MAX_STACK_DEPTH;
SysStackWalk(stack->stack.data(), &stack->depth);
}
std::string Debug::GetCompiler() {
#if KYTY_COMPILER == KYTY_COMPILER_CLANG
return "clang";
@@ -37,8 +24,4 @@ std::string Debug::GetLinker() {
#endif
}
std::string Debug::GetBitness() {
return "64";
}
} // namespace Common
+1 -27
View File
@@ -2,42 +2,16 @@
#define KYTY_COMMON_DEBUG_H_
#include "common/common.h"
#include "common/stringUtils.h"
#include <array>
#include <cstring>
#include <string>
namespace Common {
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS && KYTY_BUILD == KYTY_BUILD_DEBUG && \
KYTY_COMPILER == KYTY_COMPILER_CLANG
constexpr int DEBUG_MAX_STACK_DEPTH = 20;
#else
constexpr int DEBUG_MAX_STACK_DEPTH = 15;
#endif
namespace Debug {
std::string GetCompiler();
std::string GetLinker();
std::string GetBitness();
} // namespace Debug
struct DebugStack {
int depth {0};
std::array<void*, DEBUG_MAX_STACK_DEPTH> stack {};
[[nodiscard]] uintptr_t GetAddr(int i) const { return reinterpret_cast<uintptr_t>(stack[i]); }
void Print(int from, bool with_name = true) const;
void CopyTo(DebugStack* s) const {
std::memcpy(s->stack.data(), stack.data(), sizeof(void*) * depth);
s->depth = depth;
}
static void Trace(DebugStack* stack);
};
} // namespace Common
#endif /* KYTY_COMMON_DEBUG_H_ */
+117
View File
@@ -0,0 +1,117 @@
#ifndef KYTY_COMMON_DEBUG_COUNTERS_H_
#define KYTY_COMMON_DEBUG_COUNTERS_H_
#include <atomic>
#include <chrono>
#include <cstdint>
namespace Common::DebugCounters {
static_assert(std::atomic<uint64_t>::is_always_lock_free && std::atomic<bool>::is_always_lock_free);
// Collect events only while the panel is visible. Relaxed, lock-free atomics keep updates
// cheap and safe in signal handlers. Rates come from comparing two snapshots.
enum class Counter {
// GPU work.
Draws,
DrawInstances,
IndirectDraws,
Dispatches,
QueueSubmits,
GpuWaits, // CPU blocked on a GPU timeline semaphore.
GpuWaitNs,
GpuFaults, // Guest writes to GPU-tracked memory.
ShadersCompiled,
ShaderCompileNs,
PipelinesCreated,
PipelineCreateNs,
// Caches.
TextureUploadBytes,
TextureDownloadBytes,
TextureEvictions,
BufferUploadBytes,
BufferDownloadBytes,
BufferEvictions,
// Presentation.
FlipsRequested,
FlipsRejected, // Guest flip queue was full.
LateVblanks, // The present thread fell behind the vblank rate.
SwapchainRecreations,
DroppedPresents,
// Emulator.
EmulatedInstructions, // Host CPU lacked an instruction the guest used.
UnresolvedImportCalls,
GuestFileReadBytes,
GuestFileWriteBytes,
AudioUnderruns,
Count
};
enum class Peak { ShaderCompileNs, PipelineCreateNs, Count };
namespace Detail {
inline std::atomic<bool> g_enabled {false};
inline std::atomic<uint64_t> g_counters[static_cast<int>(Counter::Count)] {};
inline std::atomic<uint64_t> g_peaks[static_cast<int>(Peak::Count)] {};
} // namespace Detail
[[nodiscard]] inline bool Enabled() noexcept {
return Detail::g_enabled.load(std::memory_order_relaxed);
}
inline void SetEnabled(bool enabled) noexcept {
Detail::g_enabled.store(enabled, std::memory_order_relaxed);
}
inline void Add(Counter counter, uint64_t value = 1) noexcept {
if (!Enabled()) {
return;
}
Detail::g_counters[static_cast<int>(counter)].fetch_add(value, std::memory_order_relaxed);
}
class ScopedTimer final {
public:
ScopedTimer(Counter count, Counter duration, Peak peak = Peak::Count)
: m_count(count), m_duration(duration), m_peak(peak),
m_start(Enabled() ? std::chrono::steady_clock::now()
: std::chrono::steady_clock::time_point {}) {}
~ScopedTimer() {
if (m_start == std::chrono::steady_clock::time_point {} || !Enabled()) {
return;
}
const auto elapsed =
static_cast<uint64_t>(std::chrono::duration_cast<std::chrono::nanoseconds>(
std::chrono::steady_clock::now() - m_start)
.count());
Add(m_count);
Add(m_duration, elapsed);
if (m_peak != Peak::Count) {
auto& peak = Detail::g_peaks[static_cast<int>(m_peak)];
auto previous = peak.load(std::memory_order_relaxed);
while (previous < elapsed &&
!peak.compare_exchange_weak(previous, elapsed, std::memory_order_relaxed)) {
}
}
}
ScopedTimer(const ScopedTimer&) = delete;
ScopedTimer& operator=(const ScopedTimer&) = delete;
private:
Counter m_count;
Counter m_duration;
Peak m_peak;
std::chrono::steady_clock::time_point m_start;
};
[[nodiscard]] inline uint64_t Get(Counter counter) noexcept {
return Detail::g_counters[static_cast<int>(counter)].load(std::memory_order_relaxed);
}
[[nodiscard]] inline uint64_t Get(Peak peak) noexcept {
return Detail::g_peaks[static_cast<int>(peak)].load(std::memory_order_relaxed);
}
} // namespace Common::DebugCounters
#endif /* KYTY_COMMON_DEBUG_COUNTERS_H_ */
+130 -8
View File
@@ -1,6 +1,7 @@
#include "common/emulatorConfig.h"
#include "common/assert.h"
#include "common/debugCounters.h"
#include <algorithm>
#include <memory>
@@ -9,20 +10,26 @@ namespace Config {
static std::unique_ptr<ConfigOptions> g_config;
KYTY_SUBSYSTEM_INIT(Config) {
void Initialize() {
EXIT_IF(g_config != nullptr);
g_config = std::make_unique<ConfigOptions>();
}
KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(Config) {}
KYTY_SUBSYSTEM_DESTROY(Config) {}
void Shutdown() {
Common::DebugCounters::SetEnabled(false);
g_config.reset();
}
void Load(const ConfigOptions& cfg) {
EXIT_IF(g_config == nullptr);
EXIT_IF(cfg.user_name.empty() || cfg.user_name.size() > MAX_USER_NAME_LENGTH);
EXIT_IF(!IsConfiguredUserIdValid(cfg.user_id));
EXIT_IF(cfg.controller_speaker_volume > 100 || cfg.controller_vibration_intensity > 100);
EXIT_IF(cfg.keyboard_player > static_cast<uint32_t>(MAX_PLAYERS));
*g_config = cfg;
Common::DebugCounters::SetEnabled(cfg.perf_overlay_enabled);
}
uint32_t GetScreenWidth() {
@@ -33,10 +40,79 @@ uint32_t GetScreenHeight() {
return g_config->screen_height;
}
const std::string& GetUserName() {
return g_config->user_name;
}
int32_t GetUserId() {
return g_config->user_id;
}
const std::string& GetAudioInputDevice() {
return g_config->audio_input_device;
}
const std::optional<ControllerColor>& GetControllerColor() {
return g_config->controller_color;
}
uint32_t GetControllerSpeakerVolume() {
return g_config->controller_speaker_volume;
}
uint32_t GetControllerVibrationIntensity() {
return g_config->controller_vibration_intensity;
}
uint32_t GetKeyboardPlayer() {
return g_config->keyboard_player;
}
int32_t GetPlayerUserId(int player) {
return g_config->user_id + player * PLAYER_USER_ID_STEP;
}
int GetPlayerFromUserId(int32_t user_id) {
for (int player = 0; player < MAX_PLAYERS; player++) {
if (user_id == GetPlayerUserId(player)) {
return player;
}
}
return -1;
}
bool IsGuestUserId(int32_t user_id) {
return GetPlayerFromUserId(user_id) > 0;
}
PresentMode GetPresentMode() {
return g_config->present_mode;
}
int32_t GetGpuIndex() {
return g_config->gpu_index;
}
bool FullscreenEnabled() {
return g_config->fullscreen_enabled;
}
bool HdrEnabled() {
return g_config->hdr_enabled;
}
bool HideCursorEnabled() {
return g_config->hide_cursor_enabled;
}
bool VrEnabled() {
return g_config->vr_enabled;
}
bool AmdCpuEnabled() {
return g_config->amd_cpu_enabled;
}
uint32_t GetVblankFrequency() {
return std::clamp(g_config->vblank_frequency, 30u, 360u);
}
@@ -49,6 +125,10 @@ bool VulkanValidationEnabled() {
return g_config->vulkan_validation_enabled;
}
bool IsNetworkConnected() {
return g_config->network_connected;
}
bool ShaderValidationEnabled() {
return g_config->shader_validation_enabled;
}
@@ -57,7 +137,7 @@ ShaderOptimizationType GetShaderOptimizationType() {
return g_config->shader_optimization_type;
}
ShaderLogDirection GetShaderLogDirection() {
LogDirection GetShaderLogDirection() {
return g_config->shader_log_direction;
}
@@ -77,7 +157,7 @@ bool GraphicsDebugDumpEnabled() {
return g_config->graphics_debug_dump_enabled;
}
OutputDirection GetPrintfDirection() {
LogDirection GetPrintfDirection() {
return g_config->printf_direction;
}
@@ -85,14 +165,18 @@ std::filesystem::path GetPrintfOutputFile() {
return g_config->printf_output_file;
}
ProfilerDirection GetProfilerDirection() {
return g_config->profiler_direction;
bool ProfilerEnabled() {
return g_config->profiler_enabled;
}
bool SpirvDebugPrintfEnabled() {
return g_config->spirv_debug_printf_enabled;
}
bool GpuAssistedValidationEnabled() {
return g_config->gpu_assisted_validation_enabled && g_config->vulkan_validation_enabled;
}
bool RenderDocEnabled() {
return g_config->renderdoc_enabled;
}
@@ -101,8 +185,46 @@ bool ReadbackLinearImagesEnabled() {
return g_config->readback_linear_images;
}
bool SyncRawImageBuffersEnabled() {
return g_config->sync_raw_image_buffers;
}
bool SupportZmaskEnabled() {
return g_config->support_zmask;
}
bool TessellationEnabled() {
return g_config->tessellation_enabled;
}
bool TrophyEnabled() {
return g_config->trophy_enabled;
}
uint32_t GetTrophyDurationSeconds() {
return std::clamp(g_config->trophy_duration_seconds, 5u, 10u);
}
bool PlayGoHackEnabled() {
return g_config->playgo_hack_enabled;
}
bool SkipNoticeScreen() {
return g_config->skip_notice_screen;
}
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
bool RedZoneProtectionEnabled() {
return g_config->red_zone_protection_enabled;
}
#endif
const Keymap& GetKeymap() {
return g_config->keymap;
}
const std::vector<std::string>& GetGuestArguments() {
return g_config->guest_arguments;
}
} // namespace Config
+99 -13
View File
@@ -2,64 +2,137 @@
#define KYTY_COMMON_EMULATOR_CONFIG_H_
#include "common/common.h"
#include "common/subsystems.h"
#include <cstddef>
#include <array>
#include <filesystem>
#include <limits>
#include <optional>
#include <string>
#include <vector>
namespace Config {
KYTY_SUBSYSTEM_DEFINE(Config);
void Initialize();
void Shutdown();
struct Lifecycle {
static constexpr const char* name = "Config";
static constexpr auto initialize = Config::Initialize;
static constexpr auto shutdown = Config::Shutdown;
};
enum class ShaderOptimizationType { None, Size, Performance };
enum class ShaderLogDirection { Silent, Console, File };
enum class LogDirection { Silent, Console, File };
enum class ProfilerDirection { None, Network };
enum class OutputDirection { Silent, Console, File };
enum class PresentMode { Fifo, Mailbox, Immediate };
using Keymap = std::vector<std::string>;
using ControllerColor = std::array<uint8_t, 3>;
constexpr uint32_t DEFAULT_CONSOLE_LANGUAGE = 1;
constexpr uint32_t MAX_CONSOLE_LANGUAGE = 29;
constexpr std::size_t MAX_USER_NAME_LENGTH = 16;
constexpr int32_t DEFAULT_USER_ID = 1000;
constexpr int MAX_PLAYERS = 4;
constexpr int32_t PLAYER_USER_ID_STEP = 0x100;
constexpr int32_t MAX_USER_ID =
std::numeric_limits<int32_t>::max() - (MAX_PLAYERS - 1) * PLAYER_USER_ID_STEP;
constexpr bool IsConfiguredUserIdValid(int32_t user_id) {
constexpr int32_t USER_ID_EVERYONE = 0xfe;
constexpr int32_t USER_ID_SYSTEM = 0xff;
return user_id >= 0 && user_id <= MAX_USER_ID && user_id != USER_ID_EVERYONE &&
user_id != USER_ID_SYSTEM;
}
struct ConfigOptions {
uint32_t screen_width = 1280;
uint32_t screen_height = 720;
std::string user_name = "Kyty";
int32_t user_id = DEFAULT_USER_ID;
std::string audio_input_device;
std::optional<ControllerColor> controller_color;
uint32_t controller_speaker_volume = 50;
uint32_t controller_vibration_intensity = 100;
// 0 shares player 1 with the first gamepad; 1..MAX_PLAYERS dedicates that player to the keyboard.
uint32_t keyboard_player = 0;
PresentMode present_mode = PresentMode::Mailbox;
int32_t gpu_index = -1;
bool fullscreen_enabled = false;
bool hdr_enabled = false;
bool hide_cursor_enabled = false;
bool splash_enabled = true;
bool vr_enabled = false;
bool amd_cpu_enabled = false;
bool network_connected = false;
uint32_t vblank_frequency = 60;
uint32_t console_language = DEFAULT_CONSOLE_LANGUAGE;
bool vulkan_validation_enabled = false;
bool shader_validation_enabled = false;
ShaderOptimizationType shader_optimization_type = ShaderOptimizationType::None;
ShaderLogDirection shader_log_direction = ShaderLogDirection::Silent;
LogDirection shader_log_direction = LogDirection::Silent;
std::filesystem::path shader_log_folder = "_Shaders";
bool command_buffer_dump_enabled = false;
std::filesystem::path command_buffer_dump_folder = "_Buffers";
bool graphics_debug_dump_enabled = false;
OutputDirection printf_direction = OutputDirection::Console;
LogDirection printf_direction = LogDirection::Silent;
std::filesystem::path printf_output_file = "_kyty.txt";
ProfilerDirection profiler_direction = ProfilerDirection::None;
bool profiler_enabled = false;
bool spirv_debug_printf_enabled = false;
bool gpu_assisted_validation_enabled = false;
bool renderdoc_enabled = false;
bool readback_linear_images = false;
Keymap keymap;
bool sync_raw_image_buffers = false;
bool support_zmask = false;
bool tessellation_enabled = false;
bool trophy_enabled = true;
uint32_t trophy_duration_seconds = 6;
bool perf_overlay_enabled = false;
bool playgo_hack_enabled = false;
bool skip_notice_screen = false;
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
bool red_zone_protection_enabled = false;
#endif
Keymap keymap;
// Ordinary boots need a non-null argv[0]; --guest-exec supplies the caller's arguments.
std::vector<std::string> guest_arguments {""};
};
void Load(const ConfigOptions& cfg);
uint32_t GetScreenWidth();
uint32_t GetScreenHeight();
const std::string& GetUserName();
int32_t GetUserId();
const std::string& GetAudioInputDevice();
const std::optional<ControllerColor>& GetControllerColor();
uint32_t GetControllerSpeakerVolume();
uint32_t GetControllerVibrationIntensity();
uint32_t GetKeyboardPlayer();
// Player 0 is the configured user; later players derive their IDs from it.
int32_t GetPlayerUserId(int player);
// Returns -1 when the user ID does not belong to any player.
int GetPlayerFromUserId(int32_t user_id);
// Players after the first are guests: they have no profile, trophies or NP account.
bool IsGuestUserId(int32_t user_id);
PresentMode GetPresentMode();
int32_t GetGpuIndex();
bool FullscreenEnabled();
bool HdrEnabled();
bool HideCursorEnabled();
bool VrEnabled();
bool AmdCpuEnabled();
bool IsNetworkConnected();
uint32_t GetVblankFrequency();
uint32_t GetConsoleLanguage();
bool VulkanValidationEnabled();
bool ShaderValidationEnabled();
ShaderOptimizationType GetShaderOptimizationType();
ShaderLogDirection GetShaderLogDirection();
LogDirection GetShaderLogDirection();
std::filesystem::path GetShaderLogFolder();
bool CommandBufferDumpEnabled();
@@ -67,17 +140,30 @@ std::filesystem::path GetCommandBufferDumpFolder();
bool GraphicsDebugDumpEnabled();
OutputDirection GetPrintfDirection();
LogDirection GetPrintfDirection();
std::filesystem::path GetPrintfOutputFile();
ProfilerDirection GetProfilerDirection();
bool ProfilerEnabled();
bool SpirvDebugPrintfEnabled();
bool GpuAssistedValidationEnabled();
bool RenderDocEnabled();
bool ReadbackLinearImagesEnabled();
bool SyncRawImageBuffersEnabled();
bool SupportZmaskEnabled();
bool TessellationEnabled();
bool TrophyEnabled();
uint32_t GetTrophyDurationSeconds();
bool PlayGoHackEnabled();
bool SkipNoticeScreen();
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
bool RedZoneProtectionEnabled();
#endif
const Keymap& GetKeymap();
const std::vector<std::string>& GetGuestArguments();
} // namespace Config
+200 -155
View File
@@ -1,5 +1,6 @@
#include "common/file.h"
#include "common/archive.h"
#include "common/assert.h"
#include "common/common.h"
#include "common/platform/sysFileIO.h"
@@ -25,9 +26,6 @@
#ifdef CopyFile
#undef CopyFile
#endif
#ifdef MoveFile
#undef MoveFile
#endif
#endif
namespace Common {
@@ -64,7 +62,8 @@ SysFileTimeStruct DateTimeToFileTimeUtc(const DateTime& date_time) {
} // namespace
struct File::FilePrivate {
sys_file_t* f;
sys_file_t* f;
std::unique_ptr<ArchiveFile> archive;
};
File::File(): m_p(std::make_unique<FilePrivate>()) {
@@ -72,7 +71,7 @@ File::File(): m_p(std::make_unique<FilePrivate>()) {
}
File::~File() {
EXIT_IF(m_p->f != nullptr);
Close();
}
File::File(const std::filesystem::path& name): m_p(std::make_unique<FilePrivate>()) {
@@ -88,11 +87,15 @@ File::File(const std::filesystem::path& name, Mode mode): m_p(std::make_unique<F
}
bool File::IsInvalid() const {
return m_p->f == nullptr;
return m_p->f == nullptr && m_p->archive == nullptr;
}
bool File::Create(const std::filesystem::path& name) {
EXIT_IF(m_p->f != nullptr);
EXIT_IF(!IsInvalid());
if (IsArchivePath(name)) {
return false;
}
m_file_name = name;
@@ -107,9 +110,16 @@ bool File::Create(const std::filesystem::path& name) {
}
bool File::Open(const std::filesystem::path& name, Mode mode) {
EXIT_IF(m_p->f != nullptr);
EXIT_IF(!IsInvalid());
m_file_name = name;
if (IsArchivePath(name)) {
if (mode != Mode::Read) {
return false;
}
m_p->archive = OpenArchiveFile(name);
return m_p->archive != nullptr;
}
switch (mode) {
case Mode::Read: m_p->f = SysFileOpenR(name); break;
@@ -127,7 +137,7 @@ bool File::Open(const std::filesystem::path& name, Mode mode) {
}
bool File::OpenInMem(void* buf, uint32_t buf_size) {
EXIT_IF(m_p->f != nullptr);
EXIT_IF(!IsInvalid());
m_p->f = SysFileOpen(static_cast<uint8_t*>(buf), buf_size);
@@ -139,12 +149,8 @@ bool File::OpenInMem(void* buf, uint32_t buf_size) {
return true;
}
bool File::OpenInMem(ByteBuffer& buf) {
return OpenInMem(buf.GetData(), buf.Size());
}
bool File::CreateInMem() {
EXIT_IF(m_p->f != nullptr);
EXIT_IF(!IsInvalid());
m_p->f = SysFileCreate();
@@ -157,6 +163,7 @@ bool File::CreateInMem() {
}
void File::Close() {
m_p->archive.reset();
if (m_p->f != nullptr) {
SysFileClose(m_p->f);
m_p->f = nullptr;
@@ -164,7 +171,11 @@ void File::Close() {
}
uint64_t File::Size() const {
EXIT_IF(m_p->f == nullptr);
EXIT_IF(IsInvalid());
if (m_p->archive != nullptr) {
return m_p->archive->Size();
}
if (m_p->f == nullptr) {
return 0;
@@ -174,41 +185,76 @@ uint64_t File::Size() const {
}
uint64_t File::Remaining() const {
EXIT_IF(m_p->f == nullptr);
EXIT_IF(IsInvalid());
return Size() - Tell();
const auto size = Size();
const auto position = Tell();
return position < size ? size - position : 0;
}
uint64_t File::Size(const std::filesystem::path& name) {
if (IsArchivePath(name)) {
const auto info = GetArchiveInfo(name);
return info ? info->size : 0;
}
return SysFileSize(name);
}
std::optional<File::Info> File::GetInfo(const std::filesystem::path& name) {
if (IsArchivePath(name)) {
return GetArchiveInfo(name);
}
Info info {};
return SysFileGetInfo(name, &info.is_file, &info.size) ? std::optional(info) : std::nullopt;
}
bool File::Seek(uint64_t offset) {
EXIT_IF(m_p->f == nullptr);
EXIT_IF(IsInvalid());
if (m_p->archive != nullptr) {
return m_p->archive->Seek(offset);
}
return SysFileSeek(*m_p->f, offset);
}
bool File::Truncate(uint64_t size) {
EXIT_IF(m_p->f == nullptr);
EXIT_IF(IsInvalid());
if (m_p->archive != nullptr) {
return false;
}
return SysFileTruncate(*m_p->f, size);
}
bool File::Unlink() {
EXIT_IF(m_p->f == nullptr);
EXIT_IF(IsInvalid());
if (m_p->archive != nullptr) {
return false;
}
return SysFileUnlink(*m_p->f, m_file_name);
}
uint64_t File::Tell() const {
EXIT_IF(m_p->f == nullptr);
EXIT_IF(IsInvalid());
if (m_p->archive != nullptr) {
return m_p->archive->Tell();
}
return SysFileTell(*m_p->f);
}
void File::Read(void* data, uint32_t size, uint32_t* bytes_read) {
EXIT_IF(m_p->f == nullptr);
EXIT_IF(IsInvalid());
if (m_p->archive != nullptr) {
m_p->archive->Read(data, size, bytes_read);
return;
}
if (m_p->f != nullptr) {
SysFileRead(data, size, *m_p->f, bytes_read);
@@ -216,7 +262,14 @@ void File::Read(void* data, uint32_t size, uint32_t* bytes_read) {
}
void File::Write(const void* data, uint32_t size, uint32_t* bytes_written) {
EXIT_IF(m_p->f == nullptr);
EXIT_IF(IsInvalid());
if (m_p->archive != nullptr) {
if (bytes_written != nullptr) {
*bytes_written = 0;
}
return;
}
SysFileWrite(data, size, *m_p->f, bytes_written);
}
@@ -252,103 +305,120 @@ void File::Printf(const char* format, ...) {
Write(s.data(), static_cast<uint32_t>(s.size()));
}
static std::filesystem::path WithoutTrailingSeparator(
const std::filesystem::path& path) {
if (!path.empty() && !path.has_filename() &&
path != path.root_path()) {
return path.parent_path();
}
return path;
}
bool File::IsDirectoryExisting(const std::filesystem::path& path) {
auto path_str = PathToGenericString(path);
return SysFileIsDirectoryExisting(
Common::EndsWith(path_str, "/") ? Common::RemoveLast(path_str, 1) : path_str);
if (IsArchivePath(path)) {
const auto info = GetArchiveInfo(path);
return info && !info->is_file;
}
return SysFileIsDirectoryExisting(WithoutTrailingSeparator(path));
}
bool File::IsFileExisting(const std::filesystem::path& name) {
if (IsArchivePath(name)) {
const auto info = GetArchiveInfo(name);
return info && info->is_file;
}
return SysFileIsFileExisting(name);
}
bool File::CreateDirectory(
const std::filesystem::path& path) // @suppress("Member declaration not found")
{
auto path_str = PathToGenericString(path);
return SysFileCreateDirectory(Common::EndsWith(path_str, "/") ? Common::RemoveLast(path_str, 1)
: path_str);
bool File::CreateDirectory(const std::filesystem::path& path) {
if (IsArchivePath(path)) {
return false;
}
return SysFileCreateDirectory(
WithoutTrailingSeparator(path));
}
bool File::DeleteDirectory(const std::filesystem::path& path) {
auto path_str = PathToGenericString(path);
return SysFileDeleteDirectory(Common::EndsWith(path_str, "/") ? Common::RemoveLast(path_str, 1)
: path_str);
if (IsArchivePath(path)) {
return false;
}
return SysFileDeleteDirectory(
WithoutTrailingSeparator(path));
}
bool File::CreateDirectories(const std::filesystem::path& path) {
std::string real_path = Common::ReplaceChar(PathToGenericString(path), '\\', '/');
std::vector<std::string> list = Common::Split(real_path, "/");
std::string p;
for (uint32_t si = 0; si < list.size(); si++) {
const std::string& s = list[si];
if (si != 0 || Common::StartsWith(real_path, "/")) {
p += "/";
}
p += s;
if (IsDirectoryExisting(p)) {
continue;
}
if (!CreateDirectory(p)) // @suppress("Invalid arguments")
{
return false;
}
if (IsArchivePath(path)) {
return false;
}
const auto normalized_path =
WithoutTrailingSeparator(path);
return true;
auto current_path = normalized_path.root_path();
for (const auto& component:
normalized_path.relative_path()) {
current_path /= component;
if (IsDirectoryExisting(current_path)) {
continue;
}
if (!CreateDirectory(current_path)) {
return false;
}
}
return true;
}
bool File::DeleteDirectories(const std::filesystem::path& path) {
std::string real_path = Common::ReplaceChar(PathToGenericString(path), '\\', '/');
std::vector<std::string> list = Common::Split(real_path, "/");
std::string p;
std::vector<std::string> list2;
for (uint32_t si = 0; si < list.size(); si++) {
const std::string& s = list[si];
if (si != 0 || Common::StartsWith(real_path, "/")) {
p += "/";
}
p += s;
list2.push_back(p);
if (IsArchivePath(path)) {
return false;
}
const auto normalized_path =
WithoutTrailingSeparator(path);
uint32_t num = list2.size();
std::vector<std::filesystem::path> directories;
auto current_path = normalized_path.root_path();
for (uint32_t si = num - 1; si < num; si--) {
if (!DeleteDirectory(list2[si])) {
return false;
}
}
for (const auto& component:
normalized_path.relative_path()) {
current_path /= component;
directories.push_back(current_path);
}
return true;
for (auto it = directories.rbegin();
it != directories.rend(); ++it) {
if (!DeleteDirectory(*it)) {
return false;
}
}
return true;
}
bool File::DeleteFile(
const std::filesystem::path& name) // @suppress("Member declaration not found")
{
if (IsArchivePath(name)) {
return false;
}
return SysFileDeleteFile(name);
}
bool File::Flush() {
EXIT_IF(m_p->f == nullptr);
EXIT_IF(IsInvalid());
if (m_p->archive != nullptr) {
return true;
}
return SysFileFlush(*m_p->f);
}
ByteBuffer File::ReadWholeBuffer() {
std::vector<std::byte> File::ReadWholeBuffer() {
EXIT_IF(IsInvalid());
EXIT_IF(Tell() != 0);
@@ -356,26 +426,18 @@ ByteBuffer File::ReadWholeBuffer() {
EXIT_IF((s >> 32u) != 0);
ByteBuffer buf(s);
const auto read_size = static_cast<uint32_t>(s);
std::vector<std::byte> buf(read_size);
Read(buf.GetData(), s);
Read(buf.data(), read_size);
return buf;
}
ByteBuffer File::Read(uint32_t size) {
ByteBuffer buf(size);
uint32_t b = 0;
Read(buf.GetData(), size, &b);
buf.RemoveAt(b, size - b);
return buf;
}
void File::Write(const ByteBuffer& buf, uint32_t* bytes_written) {
Write(buf.GetDataConst(), buf.Size(), bytes_written);
}
DateTime File::GetLastAccessTimeUTC(const std::filesystem::path& name) {
if (IsArchivePath(name)) {
return GetLastAccessTimeUTC(GetArchiveHostPath(name));
}
SysTimeStruct t {};
SysFileToSystemTimeUtc(SysFileGetLastAccessTimeUtc(name), t);
@@ -387,6 +449,9 @@ DateTime File::GetLastAccessTimeUTC(const std::filesystem::path& name) {
}
DateTime File::GetLastWriteTimeUTC(const std::filesystem::path& name) {
if (IsArchivePath(name)) {
return GetLastWriteTimeUTC(GetArchiveHostPath(name));
}
SysTimeStruct t {};
SysFileToSystemTimeUtc(SysFileGetLastWriteTimeUtc(name), t);
@@ -401,6 +466,10 @@ void File::GetLastAccessAndWriteTimeUTC(const std::filesystem::path& name, DateT
DateTime* write) {
EXIT_IF(access == nullptr);
EXIT_IF(write == nullptr);
if (IsArchivePath(name)) {
GetLastAccessAndWriteTimeUTC(GetArchiveHostPath(name), access, write);
return;
}
SysTimeStruct at {};
SysTimeStruct wt {};
@@ -427,7 +496,12 @@ void File::GetLastAccessAndWriteTimeUTC(DateTime* access, DateTime* write) {
EXIT_IF(access == nullptr);
EXIT_IF(write == nullptr);
EXIT_IF(m_p->f == nullptr);
EXIT_IF(IsInvalid());
if (m_p->archive != nullptr) {
GetLastAccessAndWriteTimeUTC(m_file_name, access, write);
return;
}
if (m_p->f == nullptr) {
*access = DateTime();
@@ -457,68 +531,35 @@ void File::GetLastAccessAndWriteTimeUTC(DateTime* access, DateTime* write) {
}
bool File::SetLastAccessTimeUTC(const std::filesystem::path& name, const DateTime& dt) {
if (IsArchivePath(name)) {
return false;
}
auto f = DateTimeToFileTimeUtc(dt);
return SysFileSetLastAccessTimeUtc(name, f);
}
bool File::SetLastWriteTimeUTC(const std::filesystem::path& name, const DateTime& dt) {
if (IsArchivePath(name)) {
return false;
}
auto f = DateTimeToFileTimeUtc(dt);
return SysFileSetLastWriteTimeUtc(name, f);
}
bool File::SetLastAccessAndWriteTimeUTC(const std::filesystem::path& name, const DateTime& access,
const DateTime& write) {
if (IsArchivePath(name)) {
return false;
}
auto af = DateTimeToFileTimeUtc(access);
auto wf = DateTimeToFileTimeUtc(write);
return SysFileSetLastAccessAndWriteTimeUtc(name, af, wf);
}
std::vector<File::FindInfo> File::FindFiles(const std::filesystem::path& path) {
std::vector<sys_file_find_t> files;
SysFileFindFiles(path, files);
auto path_str = PathToGenericString(path);
uint32_t len = static_cast<uint32_t>(path_str.size());
if (!Common::EndsWith(path_str, "/") && !Common::EndsWith(path_str, "\\")) {
len++;
}
std::vector<File::FindInfo> ret;
ret.reserve(files.size());
for (const auto& f: files) {
File::FindInfo r {};
r.path_with_name = f.path_with_name;
r.rel_path_with_name = Common::Mid(PathToGenericString(f.path_with_name), len);
r.size = f.size;
SysTimeStruct at {};
SysTimeStruct wt {};
SysFileToSystemTimeUtc(f.last_access_time, at);
SysFileToSystemTimeUtc(f.last_write_time, wt);
if (!at.is_invalid && !wt.is_invalid) {
r.last_access_time = DateTime(Date(at.Year, at.Month, at.Day),
Time(at.Hour, at.Minute, at.Second, at.Milliseconds));
r.last_write_time = DateTime(Date(wt.Year, wt.Month, wt.Day),
Time(wt.Hour, wt.Minute, wt.Second, wt.Milliseconds));
}
// printf("%s, %s, %" PRIu64", %s, %s\n", r.path_with_name.c_str(),
// r.rel_path_with_name.c_str(), r.size, r.last_access_time.ToString().c_str(),
// r.last_write_time.ToString().c_str());
ret.push_back(std::move(r));
}
return ret;
}
std::vector<File::DirEntry> File::GetDirEntries(const std::filesystem::path& path) {
if (IsArchivePath(path)) {
return GetArchiveDirEntries(path);
}
std::vector<sys_dir_entry_t> files;
SysFileGetDents(path, files);
@@ -526,13 +567,8 @@ std::vector<File::DirEntry> File::GetDirEntries(const std::filesystem::path& pat
std::vector<File::DirEntry> ret;
ret.reserve(files.size());
for (const auto& f: files) {
File::DirEntry r {};
r.name = f.name;
r.is_file = f.is_file;
ret.push_back(std::move(r));
for (auto& f: files) {
ret.emplace_back(std::move(f.name), f.is_file);
}
return ret;
@@ -541,20 +577,29 @@ std::vector<File::DirEntry> File::GetDirEntries(const std::filesystem::path& pat
bool File::CopyFile(const std::filesystem::path& src,
const std::filesystem::path& dst) // @suppress("Member declaration not found")
{
if (IsArchivePath(src) || IsArchivePath(dst)) {
return false;
}
return SysFileCopyFile(src, dst);
}
bool File::MoveFile(const std::filesystem::path& src,
const std::filesystem::path& dst) // @suppress("Member declaration not found")
bool File::RenameFile(const std::filesystem::path& src,
const std::filesystem::path& dst) // @suppress("Member declaration not found")
{
if (IsArchivePath(src) || IsArchivePath(dst)) {
return false;
}
if (IsFileExisting(dst)) {
DeleteFile(dst); // @suppress("Invalid arguments")
}
return SysFileMoveFile(src, dst);
return SysFileRenameFile(src, dst);
}
void File::RemoveReadonly(const std::filesystem::path& name) {
if (IsArchivePath(name)) {
return;
}
SysFileRemoveReadonly(name);
}
+11 -20
View File
@@ -1,12 +1,13 @@
#ifndef KYTY_COMMON_FILE_H_
#define KYTY_COMMON_FILE_H_
#include "common/byteBuffer.h"
#include "common/common.h"
#include "common/dateTime.h"
#include <cstddef>
#include <filesystem>
#include <memory>
#include <optional>
#include <string>
#include <vector>
@@ -20,9 +21,6 @@
#ifdef CopyFile
#undef CopyFile
#endif
#ifdef MoveFile
#undef MoveFile
#endif
#endif
namespace Common {
@@ -33,18 +31,14 @@ class File {
public:
enum class Mode { Read, Write, ReadWrite, WriteRead };
struct FindInfo {
std::filesystem::path path_with_name;
std::filesystem::path rel_path_with_name;
DateTime last_access_time;
DateTime last_write_time;
uint64_t size;
};
struct DirEntry {
std::string name;
bool is_file;
};
struct Info {
bool is_file;
uint64_t size;
};
File();
explicit File(const std::filesystem::path& name);
@@ -54,7 +48,6 @@ public:
bool Create(const std::filesystem::path& name);
bool Open(const std::filesystem::path& name, Mode mode);
bool OpenInMem(void* buf, uint32_t buf_size);
bool OpenInMem(ByteBuffer& buf); // NOLINT(google-runtime-references)
bool CreateInMem();
void Close();
@@ -76,16 +69,15 @@ public:
void GetLastAccessAndWriteTimeUTC(DateTime* access, DateTime* write);
void Read(void* data, uint32_t size, uint32_t* bytes_read = nullptr);
ByteBuffer Read(uint32_t size);
void Write(const void* data, uint32_t size, uint32_t* bytes_written = nullptr);
void Write(const ByteBuffer& buf, uint32_t* bytes_written = nullptr);
void Read(void* data, uint32_t size, uint32_t* bytes_read = nullptr);
void Write(const void* data, uint32_t size, uint32_t* bytes_written = nullptr);
void Printf(const char* format, ...) KYTY_FORMAT_PRINTF(2, 3);
ByteBuffer ReadWholeBuffer();
std::vector<std::byte> ReadWholeBuffer();
static uint64_t Size(const std::filesystem::path& name);
static std::optional<Info> GetInfo(const std::filesystem::path& name);
static bool IsDirectoryExisting(const std::filesystem::path& path);
static bool IsFileExisting(const std::filesystem::path& name);
@@ -104,10 +96,9 @@ public:
static bool SetLastAccessAndWriteTimeUTC(const std::filesystem::path& name,
const DateTime& access, const DateTime& write);
static std::vector<FindInfo> FindFiles(const std::filesystem::path& path);
static std::vector<DirEntry> GetDirEntries(const std::filesystem::path& path);
static bool CopyFile(const std::filesystem::path& src, const std::filesystem::path& dst);
static bool MoveFile(const std::filesystem::path& src, const std::filesystem::path& dst);
static bool RenameFile(const std::filesystem::path& src, const std::filesystem::path& dst);
static void RemoveReadonly(const std::filesystem::path& name);
KYTY_CLASS_NO_COPY(File);
-97
View File
@@ -54,103 +54,6 @@ inline uint32_t hash(const void* key, uint32_t key_len) {
return hash;
}
inline uint32_t hash8(uint8_t key) {
uint32_t hash = 0;
uint8_t* ptr = &key;
hash += ptr[0];
hash += (hash << 10u);
hash ^= (hash >> 6u);
hash += (hash << 3u);
hash ^= (hash >> 11u);
hash += (hash << 15u);
return hash;
}
inline uint32_t hash16(uint16_t key) {
uint32_t hash = 0;
auto* ptr = reinterpret_cast<uint8_t*>(&key);
hash += ptr[0];
hash += (hash << 10u);
hash ^= (hash >> 6u);
hash += ptr[1];
hash += (hash << 10u);
hash ^= (hash >> 6u);
hash += (hash << 3u);
hash ^= (hash >> 11u);
hash += (hash << 15u);
return hash;
}
inline uint32_t hash32(uint32_t key) {
uint32_t hash = 0;
auto* ptr = reinterpret_cast<uint8_t*>(&key);
hash += ptr[0];
hash += (hash << 10u);
hash ^= (hash >> 6u);
hash += ptr[1];
hash += (hash << 10u);
hash ^= (hash >> 6u);
hash += ptr[2];
hash += (hash << 10u);
hash ^= (hash >> 6u);
hash += ptr[3];
hash += (hash << 10u);
hash ^= (hash >> 6u);
hash += (hash << 3u);
hash ^= (hash >> 11u);
hash += (hash << 15u);
return hash;
}
inline uint32_t hash64(uint64_t key) {
uint32_t hash = 0;
auto* ptr = reinterpret_cast<uint8_t*>(&key);
hash += ptr[0];
hash += (hash << 10u);
hash ^= (hash >> 6u);
hash += ptr[1];
hash += (hash << 10u);
hash ^= (hash >> 6u);
hash += ptr[2];
hash += (hash << 10u);
hash ^= (hash >> 6u);
hash += ptr[3];
hash += (hash << 10u);
hash ^= (hash >> 6u);
hash += ptr[4];
hash += (hash << 10u);
hash ^= (hash >> 6u);
hash += ptr[5];
hash += (hash << 10u);
hash ^= (hash >> 6u);
hash += ptr[6];
hash += (hash << 10u);
hash ^= (hash >> 6u);
hash += ptr[7];
hash += (hash << 10u);
hash ^= (hash >> 6u);
hash += (hash << 3u);
hash ^= (hash >> 11u);
hash += (hash << 15u);
return hash;
}
} // namespace Common
#endif /* KYTY_COMMON_HASH_H_ */
+54 -76
View File
@@ -2,18 +2,20 @@
#include <atomic>
#include <cstdio>
#include <cstdlib>
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
#include <windows.h> // IWYU pragma: keep
#elif defined(__APPLE__)
#else
#include <algorithm>
#include <csignal>
#include <cstdlib>
#include <initializer_list>
#include <unistd.h>
#if defined(__APPLE__)
#include <sys/ucontext.h>
#else
#include <csignal>
#include <initializer_list>
#include <ucontext.h> // IWYU pragma: keep
#include <unistd.h>
#endif
#endif
// IWYU pragma: no_include <errhandlingapi.h>
@@ -28,54 +30,59 @@ namespace Common::HostException {
static std::atomic<Handler> g_handler {nullptr};
static std::atomic_uint32_t g_install_state {0};
static thread_local bool g_in_exception_filter = false;
static_assert(decltype(g_handler)::is_always_lock_free);
static_assert(decltype(g_install_state)::is_always_lock_free);
[[noreturn]] static void FailFast(const char* reason) noexcept {
std::fputs("HostException fail-fast: ", stderr);
std::fputs(reason != nullptr ? reason : "unspecified", stderr);
std::fputc('\n', stderr);
std::fflush(stderr);
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
TerminateProcess(GetCurrentProcess(), static_cast<UINT>(EXCEPTION_NONCONTINUABLE_EXCEPTION));
#endif
std::_Exit(321);
}
class FilterScope final {
#if KYTY_PLATFORM == KYTY_PLATFORM_LINUX
// macOS uses the same POSIX platform setting and needs a signal stack too.
class ThreadSignalStack {
public:
FilterScope() noexcept {
if (g_in_exception_filter) {
FailFast("nested exception while resolving a host fault");
ThreadSignalStack() {
const auto page_size = static_cast<size_t>(::getpagesize());
const auto stack_size =
(std::max<size_t>(64 * 1024, MINSIGSTKSZ) + page_size - 1) & ~(page_size - 1);
if (::posix_memalign(&m_memory, page_size, stack_size) != 0) {
return;
}
stack_t stack {};
stack.ss_sp = m_memory;
stack.ss_size = stack_size;
if (::sigaltstack(&stack, &m_previous) != 0) {
std::free(m_memory);
m_memory = nullptr;
}
g_in_exception_filter = true;
}
~FilterScope() { g_in_exception_filter = false; }
~ThreadSignalStack() {
if (m_memory != nullptr && ::sigaltstack(&m_previous, nullptr) == 0) {
std::free(m_memory);
}
}
KYTY_CLASS_NO_COPY(FilterScope);
[[nodiscard]] bool IsInitialized() const { return m_memory != nullptr; }
KYTY_CLASS_NO_COPY(ThreadSignalStack)
private:
void* m_memory = nullptr;
stack_t m_previous {};
};
static Handler LoadInstalledHandler() noexcept {
if (g_install_state.load(std::memory_order_acquire) == 0) {
FailFast("host exception handler is not installed");
}
const auto handler = g_handler.load(std::memory_order_acquire);
if (handler == nullptr) {
FailFast("host exception callback is null");
}
return handler;
bool InitializeThreadSignalStack() {
// Keep fault handling off guest stacks, which GPU tracking can make read-only.
thread_local ThreadSignalStack signal_stack;
return signal_stack.IsInitialized();
}
#endif
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
static LONG WINAPI ExceptionFilter(PEXCEPTION_POINTERS exception) {
FilterScope filter_scope;
static LONG WINAPI ExceptionFilter(PEXCEPTION_POINTERS exception) noexcept {
auto* exception_record = exception->ExceptionRecord;
if (exception_record->ExceptionCode == DBG_PRINTEXCEPTION_C ||
@@ -105,12 +112,6 @@ static LONG WINAPI ExceptionFilter(PEXCEPTION_POINTERS exception) {
} else if (exception_record->ExceptionCode == EXCEPTION_ILLEGAL_INSTRUCTION) {
info.type = ExceptionType::IllegalInstruction;
} else {
printf("Unhandled win exception: code=0x%08" PRIx32 ", addr=0x%016" PRIx64
", rip=0x%016" PRIx64 ", rsp=0x%016" PRIx64 ", rbp=0x%016" PRIx64 "\n",
static_cast<uint32_t>(exception_record->ExceptionCode),
reinterpret_cast<uint64_t>(exception_record->ExceptionAddress),
exception->ContextRecord->Rip, exception->ContextRecord->Rsp,
exception->ContextRecord->Rbp);
return EXCEPTION_CONTINUE_SEARCH;
}
@@ -131,28 +132,21 @@ static LONG WINAPI ExceptionFilter(PEXCEPTION_POINTERS exception) {
info.r14 = exception->ContextRecord->R14;
info.r15 = exception->ContextRecord->R15;
const auto handler = LoadInstalledHandler();
return handler(info) ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_CONTINUE_SEARCH;
const auto handler = g_handler.load(std::memory_order_acquire);
if (handler != nullptr && handler(info)) {
return EXCEPTION_CONTINUE_EXECUTION;
}
return EXCEPTION_CONTINUE_SEARCH;
}
#elif defined(__APPLE__)
static std::atomic<Handler> g_handler {nullptr};
static std::atomic_uint32_t g_install_state {0};
static thread_local bool g_in_exception_filter = false;
static_assert(decltype(g_handler)::is_always_lock_free);
static_assert(decltype(g_install_state)::is_always_lock_free);
[[noreturn]] static void FailFast(const char* reason) noexcept {
std::fputs("HostException fail-fast: ", stderr);
std::fputs(reason != nullptr ? reason : "unspecified", stderr);
std::fputc('\n', stderr);
std::fflush(stderr);
std::_Exit(321);
}
// Translate the x86-64 page-fault error code (mcontext __es.__err) into an access type.
// bit 1 (0x2) = write, bit 4 (0x10) = instruction fetch, otherwise a read.
static AccessViolationType DecodeAccess(uint64_t err) {
@@ -170,11 +164,6 @@ static AccessViolationType DecodeAccess(uint64_t err) {
// re-executing the faulting instruction against the now-fixed protection. An unresolved
// fault restores the default disposition so the retry terminates the process.
static void SignalHandler(int sig, siginfo_t* si, void* uctx) {
if (g_in_exception_filter) {
FailFast("nested exception while resolving a host fault");
}
g_in_exception_filter = true;
auto* uc = static_cast<ucontext_t*>(uctx);
const auto* mc = uc->uc_mcontext;
const auto& ss = mc->__ss;
@@ -210,14 +199,7 @@ static void SignalHandler(int sig, siginfo_t* si, void* uctx) {
info.r15 = ss.__r15;
const auto handler = g_handler.load(std::memory_order_acquire);
if (handler == nullptr) {
FailFast("host exception callback is null");
}
const bool resolved = handler(info);
g_in_exception_filter = false;
if (resolved) {
if (handler != nullptr && handler(info)) {
return; // retry the faulting instruction against the fixed mapping
}
@@ -244,8 +226,6 @@ static void ChainToDefault(int signal_number) noexcept {
}
static void SignalHandler(int signal_number, siginfo_t* signal_info, void* native_context) {
FilterScope filter_scope;
auto* context = static_cast<ucontext_t*>(native_context);
auto* gregs = context->uc_mcontext.gregs;
@@ -289,9 +269,8 @@ static void SignalHandler(int signal_number, siginfo_t* signal_info, void* nativ
info.r14 = static_cast<uint64_t>(gregs[REG_R14]);
info.r15 = static_cast<uint64_t>(gregs[REG_R15]);
const auto handler = LoadInstalledHandler();
if (handler(info)) {
const auto handler = g_handler.load(std::memory_order_acquire);
if (handler != nullptr && handler(info)) {
return;
}
@@ -313,7 +292,7 @@ bool InstallHandler(Handler handler) {
g_handler.store(handler, std::memory_order_release);
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
if (AddVectoredExceptionHandler(1, ExceptionFilter) == nullptr) {
if (AddVectoredExceptionHandler(0, ExceptionFilter) == nullptr) {
g_handler.store(nullptr, std::memory_order_release);
g_install_state.store(0, std::memory_order_release);
printf("AddVectoredExceptionHandler() failed\n");
@@ -322,7 +301,7 @@ bool InstallHandler(Handler handler) {
#elif defined(__APPLE__)
struct sigaction sa {};
sa.sa_sigaction = SignalHandler;
sa.sa_flags = SA_SIGINFO;
sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
sigemptyset(&sa.sa_mask);
// The guest signal-dispatch path (KernelRaiseException) interrupts threads with
// SIGUSR1; block it while a fault is being resolved so a stop-the-world request
@@ -343,8 +322,7 @@ bool InstallHandler(Handler handler) {
struct sigaction action {};
action.sa_sigaction = SignalHandler;
sigemptyset(&action.sa_mask);
// Fault resolution needs the normal thread stack.
action.sa_flags = SA_SIGINFO | SA_RESTART;
action.sa_flags = SA_SIGINFO | SA_RESTART | SA_ONSTACK;
for (const int signal_number: {SIGSEGV, SIGBUS, SIGILL}) {
if (::sigaction(signal_number, &action, nullptr) != 0) {
+4
View File
@@ -39,6 +39,10 @@ using Handler = bool (*)(const ExceptionInfo&);
bool InstallHandler(Handler handler);
#if KYTY_PLATFORM == KYTY_PLATFORM_LINUX
bool InitializeThreadSignalStack();
#endif
} // namespace Common::HostException
#endif /* KYTY_COMMON_HOST_EXCEPTION_H_ */
+580
View File
@@ -0,0 +1,580 @@
#include "common/hostStats.h"
#include "common/config.h"
#include <algorithm>
#include <chrono>
#include <thread>
#include <unordered_map>
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h> // IWYU pragma: keep
// clang-format off
#include <psapi.h>
// clang-format on
#elif defined(__APPLE__)
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOKitLib.h>
#include <cstring>
#include <libproc.h>
#include <mach/mach.h>
#include <notify.h>
#include <sys/resource.h>
#include <sys/sysctl.h>
#include <unistd.h>
#else
#include <filesystem>
#include <fstream>
#include <sstream>
#include <sys/resource.h>
#include <unistd.h>
#endif
namespace Common {
namespace {
// Cumulative counters; rates come from the difference between two samples.
struct Counters {
struct Thread {
uint64_t cpu_ns;
std::string name;
};
std::optional<uint64_t> process_cpu_ns;
std::optional<uint64_t> system_busy;
std::optional<uint64_t> system_total;
std::optional<uint64_t> context_switches;
std::optional<uint64_t> page_faults;
std::optional<uint64_t> page_ins;
std::optional<uint64_t> disk_read;
std::optional<uint64_t> disk_write;
std::unordered_map<uint64_t, Thread> threads;
uint64_t wall_ns = 0;
};
uint64_t WallNanoseconds() {
return static_cast<uint64_t>(std::chrono::duration_cast<std::chrono::nanoseconds>(
std::chrono::steady_clock::now().time_since_epoch())
.count());
}
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
uint64_t FileTimeTo100Ns(const FILETIME& time) {
return (static_cast<uint64_t>(time.dwHighDateTime) << 32u) | time.dwLowDateTime;
}
struct PlatformState {};
void SamplePlatform(PlatformState& /*state*/, HostStats& stats, Counters& now) {
const auto process = GetCurrentProcess();
FILETIME creation {};
FILETIME exit {};
FILETIME kernel {};
FILETIME user {};
if (GetProcessTimes(process, &creation, &exit, &kernel, &user) != 0) {
now.process_cpu_ns = (FileTimeTo100Ns(kernel) + FileTimeTo100Ns(user)) * 100u;
}
FILETIME idle {};
if (GetSystemTimes(&idle, &kernel, &user) != 0) {
// Kernel time includes idle time.
now.system_total = FileTimeTo100Ns(kernel) + FileTimeTo100Ns(user);
now.system_busy = *now.system_total - FileTimeTo100Ns(idle);
}
PROCESS_MEMORY_COUNTERS memory {};
if (K32GetProcessMemoryInfo(process, &memory, sizeof(memory)) != 0) {
stats.process_memory = memory.WorkingSetSize;
stats.process_resident = memory.WorkingSetSize;
now.page_faults = memory.PageFaultCount;
}
IO_COUNTERS io {};
if (GetProcessIoCounters(process, &io) != 0) {
now.disk_read = io.ReadTransferCount;
now.disk_write = io.WriteTransferCount;
}
MEMORYSTATUSEX system {};
system.dwLength = sizeof(system);
if (GlobalMemoryStatusEx(&system) != 0) {
stats.system_memory_total = system.ullTotalPhys;
stats.system_memory_used = system.ullTotalPhys - system.ullAvailPhys;
stats.system_free = system.ullAvailPhys;
stats.memory_pressure = system.dwMemoryLoad >= 90 ? MemoryPressure::Critical
: system.dwMemoryLoad >= 80 ? MemoryPressure::Warning
: MemoryPressure::Normal;
}
}
#else
void SampleRusage(Counters& now) {
rusage usage {};
if (getrusage(RUSAGE_SELF, &usage) != 0) {
return;
}
const auto to_ns = [](const timeval& time) {
return static_cast<uint64_t>(time.tv_sec) * 1000000000u +
static_cast<uint64_t>(time.tv_usec) * 1000u;
};
now.process_cpu_ns = to_ns(usage.ru_utime) + to_ns(usage.ru_stime);
now.context_switches = static_cast<uint64_t>(usage.ru_nvcsw + usage.ru_nivcsw);
now.page_faults = static_cast<uint64_t>(usage.ru_minflt + usage.ru_majflt);
now.page_ins = static_cast<uint64_t>(usage.ru_majflt);
}
#if defined(__APPLE__)
template <typename T>
std::optional<T> SysctlValue(const char* name) {
T value {};
size_t size = sizeof(value);
if (sysctlbyname(name, &value, &size, nullptr, 0) != 0 || size != sizeof(value)) {
return std::nullopt;
}
return value;
}
struct PlatformState {
mach_port_t host = mach_host_self();
int thermal_token = -1;
bool thermal_ready = false;
std::string gpu_model;
std::optional<uint32_t> gpu_cores;
~PlatformState() {
if (thermal_ready) {
notify_cancel(thermal_token);
}
mach_port_deallocate(mach_task_self(), host);
}
};
std::optional<int64_t> DictionaryNumber(CFDictionaryRef dictionary, CFStringRef key) {
const auto* value = CFDictionaryGetValue(dictionary, key);
int64_t number = 0;
if (value == nullptr || CFGetTypeID(value) != CFNumberGetTypeID() ||
!CFNumberGetValue(static_cast<CFNumberRef>(value), kCFNumberSInt64Type, &number) ||
number < 0) {
return std::nullopt;
}
return number;
}
std::string RegistryString(io_object_t service, CFStringRef key) {
std::string result;
auto* value = IORegistryEntryCreateCFProperty(service, key, kCFAllocatorDefault, 0);
if (value == nullptr) {
return result;
}
if (CFGetTypeID(value) == CFStringGetTypeID()) {
char buffer[128] {};
if (CFStringGetCString(static_cast<CFStringRef>(value), buffer, sizeof(buffer),
kCFStringEncodingUTF8)) {
result = buffer;
}
} else if (CFGetTypeID(value) == CFDataGetTypeID()) {
// Intel Macs store the model as NUL-terminated data.
const auto* data = static_cast<CFDataRef>(value);
const auto* bytes = reinterpret_cast<const char*>(CFDataGetBytePtr(data));
const auto length = static_cast<size_t>(CFDataGetLength(data));
result.assign(bytes, strnlen(bytes, length));
}
CFRelease(value);
return result;
}
// IOAccelerator exposes whole-device statistics; there is no per-process figure.
void SampleGpu(PlatformState& state, HostStats& stats) {
io_iterator_t iterator = 0;
if (IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching("IOAccelerator"),
&iterator) != KERN_SUCCESS) {
return;
}
const auto take_max = [](std::optional<double>& target, std::optional<int64_t> value) {
if (value) {
target = std::max(target.value_or(0.0), std::min(100.0, static_cast<double>(*value)));
}
};
const auto add = [](std::optional<uint64_t>& target, std::optional<int64_t> value) {
if (value) {
target = target.value_or(0) + static_cast<uint64_t>(*value);
}
};
for (io_object_t service = IOIteratorNext(iterator); service != 0;
service = IOIteratorNext(iterator)) {
if (state.gpu_model.empty()) {
state.gpu_model = RegistryString(service, CFSTR("model"));
auto* cores = IORegistryEntryCreateCFProperty(service, CFSTR("gpu-core-count"),
kCFAllocatorDefault, 0);
int64_t count = 0;
if (cores != nullptr) {
if (CFGetTypeID(cores) == CFNumberGetTypeID() &&
CFNumberGetValue(static_cast<CFNumberRef>(cores), kCFNumberSInt64Type,
&count) &&
count > 0) {
state.gpu_cores = static_cast<uint32_t>(count);
}
CFRelease(cores);
}
}
auto* statistics = IORegistryEntryCreateCFProperty(service, CFSTR("PerformanceStatistics"),
kCFAllocatorDefault, 0);
if (statistics != nullptr) {
if (CFGetTypeID(statistics) == CFDictionaryGetTypeID()) {
const auto* values = static_cast<CFDictionaryRef>(statistics);
take_max(stats.gpu_percent,
DictionaryNumber(values, CFSTR("Device Utilization %")));
take_max(stats.gpu_renderer_percent,
DictionaryNumber(values, CFSTR("Renderer Utilization %")));
take_max(stats.gpu_tiler_percent,
DictionaryNumber(values, CFSTR("Tiler Utilization %")));
add(stats.gpu_memory_in_use,
DictionaryNumber(values, CFSTR("In use system memory")));
add(stats.gpu_memory_allocated,
DictionaryNumber(values, CFSTR("Alloc system memory")));
add(stats.gpu_recoveries, DictionaryNumber(values, CFSTR("recoveryCount")));
}
CFRelease(statistics);
}
IOObjectRelease(service);
}
IOObjectRelease(iterator);
stats.gpu_model = state.gpu_model;
stats.gpu_cores = state.gpu_cores;
}
void SampleThreads(HostStats& stats, Counters& now) {
thread_act_array_t threads = nullptr;
mach_msg_type_number_t count = 0;
const auto task = mach_task_self();
if (task_threads(task, &threads, &count) != KERN_SUCCESS) {
return;
}
stats.thread_count = count;
for (mach_msg_type_number_t i = 0; i < count; i++) {
thread_identifier_info_data_t identifier {};
mach_msg_type_number_t size = THREAD_IDENTIFIER_INFO_COUNT;
thread_basic_info_data_t basic {};
mach_msg_type_number_t basic_size = THREAD_BASIC_INFO_COUNT;
if (thread_info(threads[i], THREAD_IDENTIFIER_INFO,
reinterpret_cast<thread_info_t>(&identifier), &size) == KERN_SUCCESS &&
thread_info(threads[i], THREAD_BASIC_INFO, reinterpret_cast<thread_info_t>(&basic),
&basic_size) == KERN_SUCCESS) {
const auto to_ns = [](const time_value_t& time) {
return static_cast<uint64_t>(time.seconds) * 1000000000u +
static_cast<uint64_t>(time.microseconds) * 1000u;
};
auto& thread = now.threads[identifier.thread_id];
thread.cpu_ns = to_ns(basic.user_time) + to_ns(basic.system_time);
thread_extended_info_data_t extended {};
mach_msg_type_number_t extended_size = THREAD_EXTENDED_INFO_COUNT;
if (thread_info(threads[i], THREAD_EXTENDED_INFO,
reinterpret_cast<thread_info_t>(&extended),
&extended_size) == KERN_SUCCESS) {
thread.name = std::string(extended.pth_name,
strnlen(extended.pth_name, sizeof(extended.pth_name)));
}
}
mach_port_deallocate(task, threads[i]);
}
vm_deallocate(task, reinterpret_cast<vm_address_t>(threads), count * sizeof(thread_act_t));
}
void SamplePlatform(PlatformState& state, HostStats& stats, Counters& now) {
SampleRusage(now);
host_cpu_load_info_data_t load {};
mach_msg_type_number_t load_count = HOST_CPU_LOAD_INFO_COUNT;
if (host_statistics(state.host, HOST_CPU_LOAD_INFO, reinterpret_cast<host_info_t>(&load),
&load_count) == KERN_SUCCESS) {
const uint64_t busy = static_cast<uint64_t>(load.cpu_ticks[CPU_STATE_USER]) +
load.cpu_ticks[CPU_STATE_SYSTEM] + load.cpu_ticks[CPU_STATE_NICE];
now.system_busy = busy;
now.system_total = busy + load.cpu_ticks[CPU_STATE_IDLE];
}
// Physical footprint is what Activity Monitor shows in its Memory column.
task_vm_info_data_t vm_info {};
mach_msg_type_number_t vm_info_count = TASK_VM_INFO_COUNT;
if (task_info(mach_task_self(), TASK_VM_INFO, reinterpret_cast<task_info_t>(&vm_info),
&vm_info_count) == KERN_SUCCESS) {
stats.process_memory = vm_info.phys_footprint;
stats.process_resident = vm_info.resident_size;
stats.process_compressed = vm_info.compressed;
stats.process_file_backed = vm_info.external;
stats.process_virtual = vm_info.virtual_size;
}
rusage_info_v2 usage {};
if (proc_pid_rusage(getpid(), RUSAGE_INFO_V2, reinterpret_cast<rusage_info_t*>(&usage)) == 0) {
now.disk_read = usage.ri_diskio_bytesread;
now.disk_write = usage.ri_diskio_byteswritten;
}
stats.system_memory_total = SysctlValue<uint64_t>("hw.memsize");
vm_size_t page = 0;
vm_statistics64_data_t vm {};
mach_msg_type_number_t count = HOST_VM_INFO64_COUNT;
if (host_page_size(state.host, &page) == KERN_SUCCESS &&
host_statistics64(state.host, HOST_VM_INFO64, reinterpret_cast<host_info64_t>(&vm),
&count) == KERN_SUCCESS) {
// Activity Monitor's "Memory Used": app memory + wired + compressed.
const uint64_t app = vm.internal_page_count > vm.purgeable_count
? vm.internal_page_count - vm.purgeable_count
: 0;
stats.system_memory_used = (app + vm.wire_count + vm.compressor_page_count) * page;
stats.system_wired = static_cast<uint64_t>(vm.wire_count) * page;
stats.system_compressed = static_cast<uint64_t>(vm.compressor_page_count) * page;
stats.system_cached =
(static_cast<uint64_t>(vm.external_page_count) + vm.purgeable_count) * page;
stats.system_free = static_cast<uint64_t>(vm.free_count) * page;
}
if (const auto swap = SysctlValue<xsw_usage>("vm.swapusage")) {
stats.swap_used = swap->xsu_used;
stats.swap_total = swap->xsu_total;
}
// 1 = normal, 2 = warning, 4 = critical, as reported to dispatch memory-pressure sources.
if (const auto level = SysctlValue<int>("kern.memorystatus_vm_pressure_level")) {
stats.memory_pressure = *level >= 4 ? MemoryPressure::Critical
: *level >= 2 ? MemoryPressure::Warning
: MemoryPressure::Normal;
}
// 0 nominal, 1 moderate, 2 heavy, 3 trapping, 4 sleeping.
if (!state.thermal_ready) {
state.thermal_ready = notify_register_check("com.apple.system.thermalpressurelevel",
&state.thermal_token) == NOTIFY_STATUS_OK;
}
uint64_t thermal = 0;
if (state.thermal_ready &&
notify_get_state(state.thermal_token, &thermal) == NOTIFY_STATUS_OK) {
stats.thermal_pressure = thermal >= 3 ? ThermalPressure::Critical
: thermal == 2 ? ThermalPressure::Heavy
: thermal == 1 ? ThermalPressure::Moderate
: ThermalPressure::Nominal;
}
SampleThreads(stats, now);
SampleGpu(state, stats);
}
#else
using ProcValues = std::unordered_map<std::string, uint64_t>;
// Reads "<key>: <number> [kB]" lines; kB values are returned in bytes.
ProcValues ReadProcValues(const char* path) {
ProcValues values;
std::ifstream file(path);
std::string line;
while (std::getline(file, line)) {
const auto colon = line.find(':');
if (colon == std::string::npos) {
continue;
}
std::istringstream stream(line.substr(colon + 1));
uint64_t number = 0;
std::string unit;
if (stream >> number) {
stream >> unit;
values[line.substr(0, colon)] = unit == "kB" ? number * 1024u : number;
}
}
return values;
}
std::optional<uint64_t> Find(const ProcValues& values, const char* key) {
const auto it = values.find(key);
return it != values.end() ? std::optional(it->second) : std::nullopt;
}
struct PlatformState {};
void SampleThreads(HostStats& stats, Counters& now) {
static const double ns_per_tick = 1e9 / static_cast<double>(std::max(sysconf(_SC_CLK_TCK), 1L));
std::error_code error;
uint32_t count = 0;
for (std::filesystem::directory_iterator it("/proc/self/task", error), end; !error && it != end;
it.increment(error)) {
count++;
std::ifstream stat_file(it->path() / "stat");
std::string stat;
uint64_t id = 0;
if (!(stat_file >> id)) {
continue; // The thread may have exited during enumeration.
}
std::getline(stat_file, stat);
const auto close = stat.rfind(')');
if (close == std::string::npos) {
continue;
}
// Fields after the command name start at field 3 (state); utime and stime are 14 and 15.
std::istringstream fields(stat.substr(close + 2));
std::string field;
for (int index = 3; index < 14 && fields >> field; index++) {
}
uint64_t user = 0;
uint64_t system = 0;
if (!(fields >> user >> system)) {
continue;
}
auto& thread = now.threads[id];
thread.cpu_ns = static_cast<uint64_t>(static_cast<double>(user + system) * ns_per_tick);
std::ifstream name_file(it->path() / "comm");
std::getline(name_file, thread.name);
}
if (!error) {
stats.thread_count = count;
}
}
void SamplePlatform(PlatformState& /*state*/, HostStats& stats, Counters& now) {
SampleRusage(now);
std::ifstream cpu_file("/proc/stat");
std::string label;
if (cpu_file >> label && label == "cpu") {
uint64_t total = 0;
uint64_t idle = 0;
uint64_t value = 0;
for (int index = 0; index < 8 && cpu_file >> value; index++) {
total += value;
if (index == 3 || index == 4) { // idle, iowait
idle += value;
}
}
now.system_total = total;
now.system_busy = total - idle;
}
const auto status = ReadProcValues("/proc/self/status");
stats.process_memory = Find(status, "VmRSS");
stats.process_resident = Find(status, "VmRSS");
stats.process_file_backed = Find(status, "RssFile");
stats.process_compressed = Find(status, "VmSwap");
stats.process_virtual = Find(status, "VmSize");
const auto io = ReadProcValues("/proc/self/io");
now.disk_read = Find(io, "read_bytes");
now.disk_write = Find(io, "write_bytes");
const auto memory = ReadProcValues("/proc/meminfo");
const auto total = Find(memory, "MemTotal");
const auto available = Find(memory, "MemAvailable");
if (total && available && *available <= *total) {
stats.system_memory_total = total;
stats.system_memory_used = *total - *available;
}
stats.system_free = Find(memory, "MemFree");
if (const auto cached = Find(memory, "Cached")) {
stats.system_cached = *cached + Find(memory, "Buffers").value_or(0);
}
const auto swap_total = Find(memory, "SwapTotal");
const auto swap_free = Find(memory, "SwapFree");
if (swap_total && swap_free && *swap_free <= *swap_total) {
stats.swap_total = swap_total;
stats.swap_used = *swap_total - *swap_free;
}
// Pressure stall information: share of the last 10 s some task waited on memory.
std::ifstream pressure("/proc/pressure/memory");
std::string kind;
std::string average;
double stalled = 0.0;
if (pressure >> kind >> average && kind == "some" && average.rfind("avg10=", 0) == 0 &&
std::istringstream(average.substr(6)) >> stalled) {
stats.memory_pressure = stalled >= 20.0 ? MemoryPressure::Critical
: stalled >= 5.0 ? MemoryPressure::Warning
: MemoryPressure::Normal;
} else if (total && available && *total != 0) {
const double free_share = static_cast<double>(*available) / static_cast<double>(*total);
stats.memory_pressure = free_share < 0.10 ? MemoryPressure::Critical
: free_share < 0.25 ? MemoryPressure::Warning
: MemoryPressure::Normal;
}
SampleThreads(stats, now);
}
#endif
#endif
constexpr size_t BUSIEST_THREADS = 6;
} // namespace
struct HostStatsSampler::Impl {
PlatformState state;
Counters last;
uint32_t logical_cores = std::max(std::thread::hardware_concurrency(), 1u);
bool has_last = false;
};
HostStatsSampler::HostStatsSampler(): m_impl(std::make_unique<Impl>()) {}
HostStatsSampler::~HostStatsSampler() = default;
HostStats HostStatsSampler::Sample() {
HostStats stats;
stats.logical_cores = m_impl->logical_cores;
Counters now;
now.wall_ns = WallNanoseconds();
SamplePlatform(m_impl->state, stats, now);
const auto& last = m_impl->last;
const auto elapsed = static_cast<double>(now.wall_ns - last.wall_ns) / 1e9;
if (m_impl->has_last && elapsed > 0.0) {
const auto rate = [&](std::optional<uint64_t> current,
std::optional<uint64_t> previous) -> std::optional<double> {
if (!current || !previous || *current < *previous) {
return std::nullopt;
}
return static_cast<double>(*current - *previous) / elapsed;
};
if (const auto cpu = rate(now.process_cpu_ns, last.process_cpu_ns)) {
stats.process_cpu_percent =
std::clamp(*cpu / 1e9 * 100.0 / stats.logical_cores, 0.0, 100.0);
}
if (now.system_total && last.system_total && now.system_busy && last.system_busy &&
*now.system_total > *last.system_total && *now.system_busy >= *last.system_busy) {
stats.system_cpu_percent =
std::clamp(static_cast<double>(*now.system_busy - *last.system_busy) /
static_cast<double>(*now.system_total - *last.system_total) * 100.0,
0.0, 100.0);
}
stats.context_switches_per_s = rate(now.context_switches, last.context_switches);
stats.page_faults_per_s = rate(now.page_faults, last.page_faults);
stats.page_ins_per_s = rate(now.page_ins, last.page_ins);
stats.disk_read_per_s = rate(now.disk_read, last.disk_read);
stats.disk_write_per_s = rate(now.disk_write, last.disk_write);
for (const auto& [id, thread]: now.threads) {
// A thread missing from the last sample started during this interval.
const auto previous = last.threads.find(id);
const uint64_t before = previous != last.threads.end() ? previous->second.cpu_ns : 0;
if (thread.cpu_ns < before) {
continue;
}
const double percent =
static_cast<double>(thread.cpu_ns - before) / 1e9 / elapsed * 100.0;
stats.busiest_threads.push_back(
{thread.name.empty() ? "thread " + std::to_string(id) : thread.name, percent});
}
std::sort(stats.busiest_threads.begin(), stats.busiest_threads.end(),
[](const auto& a, const auto& b) { return a.cpu_percent > b.cpu_percent; });
if (stats.busiest_threads.size() > BUSIEST_THREADS) {
stats.busiest_threads.resize(BUSIEST_THREADS);
}
}
m_impl->last = std::move(now);
m_impl->has_last = true;
return stats;
}
} // namespace Common
+86
View File
@@ -0,0 +1,86 @@
#ifndef KYTY_COMMON_HOST_STATS_H_
#define KYTY_COMMON_HOST_STATS_H_
#include <cstdint>
#include <memory>
#include <optional>
#include <string>
#include <vector>
namespace Common {
enum class MemoryPressure { Unknown, Normal, Warning, Critical };
enum class ThermalPressure { Unknown, Nominal, Moderate, Heavy, Critical };
struct ThreadUsage {
std::string name;
double cpu_percent = 0.0; // Of one core.
};
// Host-wide and process-wide resource usage. Missing values are std::nullopt; rates are per
// second since the previous sample.
struct HostStats {
uint32_t logical_cores = 0;
// Processing.
std::optional<double> process_cpu_percent; // Share of all logical cores, 0-100.
std::optional<double> system_cpu_percent; // Whole machine, 0-100.
std::optional<uint32_t> thread_count;
std::vector<ThreadUsage> busiest_threads; // Busiest first.
std::optional<double> context_switches_per_s;
std::optional<double> page_faults_per_s;
std::optional<double> page_ins_per_s; // Faults that read from disk.
ThermalPressure thermal_pressure = ThermalPressure::Unknown;
// Emulator process memory.
std::optional<uint64_t> process_memory; // Physical footprint / resident set.
std::optional<uint64_t> process_resident;
std::optional<uint64_t> process_compressed; // Compressed or swapped out.
std::optional<uint64_t> process_file_backed;
std::optional<uint64_t> process_virtual; // Reserved address space.
// System memory.
std::optional<uint64_t> system_memory_used;
std::optional<uint64_t> system_memory_total;
std::optional<uint64_t> system_wired;
std::optional<uint64_t> system_compressed;
std::optional<uint64_t> system_cached; // File cache, reclaimable.
std::optional<uint64_t> system_free;
std::optional<uint64_t> swap_used;
std::optional<uint64_t> swap_total;
MemoryPressure memory_pressure = MemoryPressure::Unknown;
// Disk I/O of the emulator process.
std::optional<double> disk_read_per_s;
std::optional<double> disk_write_per_s;
// GPU, whole device (macOS IOAccelerator).
std::string gpu_model;
std::optional<uint32_t> gpu_cores;
std::optional<double> gpu_percent;
std::optional<double> gpu_renderer_percent;
std::optional<double> gpu_tiler_percent;
std::optional<uint64_t> gpu_memory_in_use; // System memory the GPU driver has in use.
std::optional<uint64_t> gpu_memory_allocated;
std::optional<uint64_t> gpu_recoveries; // GPU resets since boot.
};
// May block for a few milliseconds (thread enumeration, OS registry reads), so call it off the
// render thread. The first sample has no rates.
class HostStatsSampler final {
public:
HostStatsSampler();
~HostStatsSampler();
HostStatsSampler(const HostStatsSampler&) = delete;
HostStatsSampler& operator=(const HostStatsSampler&) = delete;
[[nodiscard]] HostStats Sample();
private:
struct Impl;
std::unique_ptr<Impl> m_impl;
};
} // namespace Common
#endif /* KYTY_COMMON_HOST_STATS_H_ */
+53
View File
@@ -0,0 +1,53 @@
#include "common/localization.h"
#include <array>
#include <cstddef>
#include <nlohmann/json.hpp>
#include <string>
#include "localizationData.h"
namespace Common::Localization {
namespace {
constexpr std::array<std::string_view, 30> Locales = {
"ja-JP", "en-US", "fr-FR", "es-ES", "de-DE", "it-IT", "nl-NL", "pt-PT",
"ru-RU", "ko-KR", "zh-Hant", "zh-Hans", "fi-FI", "sv-SE", "da-DK", "no-NO",
"pl-PL", "pt-BR", "en-GB", "tr-TR", "es-419", "ar-AE", "fr-CA", "cs-CZ",
"hu-HU", "el-GR", "ro-RO", "th-TH", "vi-VN", "id-ID"};
size_t LanguageIndex(int console_language) {
return console_language >= 0 && console_language < static_cast<int>(Locales.size())
? static_cast<size_t>(console_language)
: 1;
}
} // namespace
std::string_view LocaleName(int console_language) {
return Locales[LanguageIndex(console_language)];
}
std::string_view Get(int console_language, std::string_view key) {
static const auto catalogs = [] {
std::array<nlohmann::json, Locales.size()> result;
for (size_t i = 0; i < Locales.size(); ++i) {
const auto bytes = EmbeddedCatalog(Locales[i]);
result[i] = nlohmann::json::parse(bytes.begin(), bytes.end(), nullptr, false);
}
return result;
}();
for (const auto index: std::array {LanguageIndex(console_language), size_t {1}}) {
const auto& catalog = catalogs[index];
const auto found = catalog.find(key);
if (found != catalog.end() && found->is_string()) {
const auto& text = found->get_ref<const std::string&>();
if (!text.empty()) {
return text;
}
}
}
return key;
}
} // namespace Common::Localization
+13
View File
@@ -0,0 +1,13 @@
#pragma once
#include <string_view>
namespace Common::Localization {
// Console language indices follow the system configuration; invalid indices use English.
[[nodiscard]] std::string_view LocaleName(int console_language);
// Translations have static lifetime. Missing translations use English, then the supplied key.
[[nodiscard]] std::string_view Get(int console_language, std::string_view key);
} // namespace Common::Localization
+16 -14
View File
@@ -3,9 +3,9 @@
#include "common/assert.h"
#include "common/emulatorConfig.h"
#include "common/stringUtils.h"
#include <cstdio>
#include <cstdlib>
#include <filesystem>
#include <fmt/format.h>
#include <memory>
@@ -46,8 +46,8 @@ std::shared_ptr<spdlog::logger> MakeFileLogger(std::string name
std::filesystem::create_directories(parent);
}
auto sink =
std::make_shared<spdlog::sinks::basic_file_sink_mt>(Common::PathToString(path), true);
const bool truncate = std::getenv(Log::RelaunchedVariable) == nullptr;
auto sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(path.native(), truncate);
return MakeLogger(std::move(name), std::move(sink));
}
@@ -129,6 +129,14 @@ static void WriteImpl(std::string_view text, fmt::text_style style = {}) {
}
}
void WriteToConsoleAndLog(std::string_view text) {
WriteImpl(text);
if (g_initialized && g_direction != Direction::Console) {
WriteStdout(text);
}
Flush();
}
void WriteFatal(std::string_view text) {
if (g_direction == Direction::Silent || !g_initialized) {
WriteStdout(text);
@@ -149,25 +157,19 @@ void WriteFatal(fmt::text_style style, std::string_view text) {
Flush();
}
KYTY_SUBSYSTEM_INIT(Log) {
void Initialize() {
g_initialized = true;
switch (Config::GetPrintfDirection()) {
case Config::OutputDirection::Silent: g_direction = Direction::Silent; break;
case Config::OutputDirection::Console: g_direction = Direction::Console; break;
case Config::OutputDirection::File: g_direction = Direction::File; break;
case Config::LogDirection::Silent: g_direction = Direction::Silent; break;
case Config::LogDirection::Console: g_direction = Direction::Console; break;
case Config::LogDirection::File: g_direction = Direction::File; break;
}
g_output_file =
(g_direction == Direction::File ? Config::GetPrintfOutputFile() : std::filesystem::path {});
SetupLogger();
}
KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(Log) {
Flush();
std::lock_guard lock(g_logger_mutex);
g_logger.reset();
}
KYTY_SUBSYSTEM_DESTROY(Log) {
void Shutdown() {
Flush();
std::lock_guard lock(g_logger_mutex);
g_logger.reset();
+14 -2
View File
@@ -2,7 +2,6 @@
#define KYTY_COMMON_LOGGING_LOG_H_
#include "common/common.h"
#include "common/subsystems.h"
#include <fmt/color.h>
#include <fmt/printf.h>
@@ -10,14 +9,27 @@
namespace Log {
KYTY_SUBSYSTEM_DEFINE(Log);
void Initialize();
void Shutdown();
struct Lifecycle {
static constexpr const char* name = "Log";
static constexpr auto initialize = Log::Initialize;
static constexpr auto shutdown = Log::Shutdown;
static constexpr auto emergency_shutdown = Log::Shutdown;
};
enum class Direction { Silent, Console, File };
// Set by LoadExec for the program it starts, which continues the log file of the one it replaces
// instead of starting it over.
inline constexpr const char* RelaunchedVariable = "KYTY_RELAUNCHED";
Direction GetDirection();
bool IsSilent();
void Write(std::string_view text);
void Write(fmt::text_style style, std::string_view text);
void WriteToConsoleAndLog(std::string_view text);
void WriteFatal(std::string_view text);
void WriteFatal(fmt::text_style style, std::string_view text);
void Flush();
-42
View File
@@ -1,42 +0,0 @@
#ifndef KYTY_COMMON_MAGICENUM_H_
#define KYTY_COMMON_MAGICENUM_H_
#include "common/common.h"
#include "common/stringUtils.h"
#include "magic_enum.hpp" // IWYU pragma: export
namespace Common {
template <typename E>
inline std::string EnumName(E v) {
auto str = magic_enum::enum_name(v);
return std::string(str.data(), str.length());
}
template <typename E>
inline std::string EnumName8(E v) {
auto str = magic_enum::enum_name(v);
return std::string(str.data(), str.length());
}
template <typename E>
inline E EnumValue(const std::string& str, E default_value) {
auto v = magic_enum::enum_cast<E>(str.c_str());
if (v.has_value()) {
return v.value();
}
return default_value;
}
#define KYTY_ENUM_RANGE(e, mx, mn) \
namespace magic_enum::customize { \
template <> \
struct enum_range<e> { \
static constexpr int min = (mx); \
static constexpr int max = (mn); \
}; \
}
} // namespace Common
#endif /* KYTY_COMMON_MAGICENUM_H_ */
+1 -3
View File
@@ -30,8 +30,6 @@ struct sys_dbg_stack_info_t {
#endif
};
void SysStackWalk(void** stack, int* depth);
void SysStackUsage(sys_dbg_stack_info_t& s); // NOLINT(google-runtime-references)
void SysStackUsagePrint(sys_dbg_stack_info_t& stack); // NOLINT(google-runtime-references)
void SysStackUsage(sys_dbg_stack_info_t& s); // NOLINT(google-runtime-references)
#endif /* KYTY_COMMON_PLATFORM_SYSDBG_H_ */
+2 -12
View File
@@ -18,14 +18,6 @@ enum sys_file_cache_type_t {
SYS_FILE_CACHE_SEQUENTIAL_SCAN = 2 // NOLINT(readability-identifier-naming)
};
// NOLINTNEXTLINE(readability-identifier-naming)
struct sys_file_find_t {
std::filesystem::path path_with_name;
SysFileTimeStruct last_access_time;
SysFileTimeStruct last_write_time;
uint64_t size;
};
// NOLINTNEXTLINE(readability-identifier-naming)
struct sys_dir_entry_t {
std::string name;
@@ -52,8 +44,8 @@ uint64_t SysFileTell(sys_file_t& f); // NOLINT(google-runt
bool SysFileTruncate(sys_file_t& f, uint64_t size); // NOLINT(google-runtime-references)
bool SysFileUnlink(sys_file_t& f,
const std::filesystem::path& name); // NOLINT(google-runtime-references)
void SysFileWrite(uint32_t n, sys_file_t& f); // NOLINT(google-runtime-references)
uint64_t SysFileSize(const std::filesystem::path& file_name);
bool SysFileGetInfo(const std::filesystem::path& name, bool* is_file, uint64_t* size);
bool SysFileIsError(sys_file_t& f); // NOLINT(google-runtime-references)
bool SysFileIsDirectoryExisting(const std::filesystem::path& path);
bool SysFileIsFileExisting(const std::filesystem::path& name);
@@ -76,11 +68,9 @@ bool SysFileSetLastWriteTimeUtc(const std::filesystem::path& name, SysFileTimeSt
bool SysFileSetLastAccessAndWriteTimeUtc(const std::filesystem::path& name,
SysFileTimeStruct& access, SysFileTimeStruct& write);
// NOLINTNEXTLINE(google-runtime-references)
void SysFileFindFiles(const std::filesystem::path& path, std::vector<sys_file_find_t>& out);
// NOLINTNEXTLINE(google-runtime-references)
void SysFileGetDents(const std::filesystem::path& path, std::vector<sys_dir_entry_t>& out);
bool SysFileCopyFile(const std::filesystem::path& src, const std::filesystem::path& dst);
bool SysFileMoveFile(const std::filesystem::path& src, const std::filesystem::path& dst);
bool SysFileRenameFile(const std::filesystem::path& src, const std::filesystem::path& dst);
void SysFileRemoveReadonly(const std::filesystem::path& name);
#endif /* KYTY_COMMON_PLATFORM_SYSFILEIO_H_ */
-51
View File
@@ -8,7 +8,6 @@
#include <cstdlib>
#include <cstring>
#include <execinfo.h>
#include <pthread.h>
#include <sys/param.h>
#include <sys/types.h>
@@ -17,56 +16,6 @@
#include <libgen.h> // POSIX basename() lives here on macOS, not in <cstring>
#endif
// Avoid unwinding a guest-owned stack.
static bool OnOwnStack() {
const char* probe = reinterpret_cast<const char*>(&probe);
pthread_attr_t attr {};
#if defined(__APPLE__)
const auto* top = static_cast<const char*>(pthread_get_stackaddr_np(pthread_self()));
const auto size = pthread_get_stacksize_np(pthread_self());
(void)attr;
return top != nullptr && size != 0 && probe < top && probe >= top - size;
#else
if (pthread_getattr_np(pthread_self(), &attr) != 0) {
return false;
}
void* base = nullptr;
size_t size = 0;
const bool ok = pthread_attr_getstack(&attr, &base, &size) == 0 && base != nullptr && size != 0;
pthread_attr_destroy(&attr);
if (!ok) {
return false;
}
const auto* low = static_cast<const char*>(base);
return probe >= low && probe < low + size;
#endif
}
void SysStackWalk(void** stack, int* depth) {
if (stack == nullptr || depth == nullptr || *depth <= 0) {
if (depth != nullptr) {
*depth = 0;
}
return;
}
if (!OnOwnStack()) {
*depth = 0;
return;
}
const int n = ::backtrace(stack, *depth);
*depth = (n < 0 ? 0 : n);
}
void SysStackUsagePrint(sys_dbg_stack_info_t& stack) {
printf("stack: (0x%" PRIx64 ", %" PRIu64 ")\n", static_cast<uint64_t>(stack.commited_addr),
static_cast<uint64_t>(stack.commited_size));
printf("code: (0x%" PRIx64 ", %" PRIu64 ")\n", static_cast<uint64_t>(stack.code_addr),
static_cast<uint64_t>(stack.code_size));
}
void SysStackUsage(sys_dbg_stack_info_t& s) {
pid_t pid = getpid();
+39 -137
View File
@@ -11,6 +11,7 @@
#include <cerrno>
#include <cstdlib>
#include <cstring>
#include <dirent.h>
#include <fcntl.h>
#include <filesystem>
@@ -53,7 +54,7 @@ struct sys_file_t {
#endif
static std::filesystem::path get_internal_name(const std::filesystem::path& name) {
return name.is_absolute() ? name : (std::filesystem::path(".") / name);
return name.empty() || name.is_absolute() ? name : (std::filesystem::path(".") / name);
}
// Pass access-pattern hints to the host.
@@ -151,46 +152,29 @@ void SysFileWrite(const void* data, uint32_t size, sys_file_t& f, uint32_t* byte
}
}
void SysFileWrite(uint32_t n, sys_file_t& f) {
SysFileWrite(&n, 4, f);
static sys_file_t* OpenHostFile(const std::filesystem::path& file_name, const char* mode,
sys_file_cache_type_t cache_type) {
auto* ret = new sys_file_t;
ret->f = fopen(get_internal_name(file_name).c_str(), mode);
ret->type = ret->f == nullptr ? SYS_FILE_ERROR : SYS_FILE_FILE;
if (ret->f != nullptr) {
// Independent handles must observe writes and truncation immediately.
setvbuf(ret->f, nullptr, _IONBF, 0);
apply_cache_hint(ret->f, cache_type);
}
return ret;
}
sys_file_t* SysFileCreate(const std::filesystem::path& file_name) {
auto* ret = new sys_file_t;
auto real_name = get_internal_name(file_name);
auto real_name_str = real_name.string();
ret->f = fopen(real_name_str.c_str(), "w+");
auto* ret = OpenHostFile(file_name, "w+", SYS_FILE_CACHE_AUTO);
if (ret->f == nullptr) {
printf("can't create file: %s\n", real_name_str.c_str());
printf("can't create file: %s\n", file_name.c_str());
}
ret->type = SYS_FILE_FILE;
return ret;
}
sys_file_t* SysFileOpenR(const std::filesystem::path& file_name, sys_file_cache_type_t cache_type) {
auto* ret = new sys_file_t;
ret->type = SYS_FILE_FILE;
auto internal_name = get_internal_name(file_name);
auto internal_name_str = internal_name.string();
FILE* f = fopen(internal_name_str.c_str(), "r");
if (f == nullptr) {
ret->type = SYS_FILE_ERROR;
}
apply_cache_hint(f, cache_type);
ret->f = f;
return ret;
return OpenHostFile(file_name, "r", cache_type);
}
sys_file_t* SysFileOpen(uint8_t* buf, uint32_t buf_size) {
@@ -218,46 +202,12 @@ sys_file_t* SysFileCreate() {
}
sys_file_t* SysFileOpenW(const std::filesystem::path& file_name, sys_file_cache_type_t cache_type) {
auto* ret = new sys_file_t;
auto real_name = get_internal_name(file_name);
auto real_name_str = real_name.string();
FILE* f = fopen(real_name_str.c_str(), "r+");
if (f == nullptr) {
ret->type = SYS_FILE_ERROR;
} else {
ret->type = SYS_FILE_FILE;
}
apply_cache_hint(f, cache_type);
ret->f = f;
return ret;
return OpenHostFile(file_name, "r+", cache_type);
}
sys_file_t* SysFileOpenRw(const std::filesystem::path& file_name,
sys_file_cache_type_t cache_type) {
auto* ret = new sys_file_t;
auto real_name = get_internal_name(file_name);
auto real_name_str = real_name.string();
FILE* f = fopen(real_name_str.c_str(), "r+");
if (f == nullptr) {
ret->type = SYS_FILE_ERROR;
} else {
ret->type = SYS_FILE_FILE;
}
apply_cache_hint(f, cache_type);
ret->f = f;
return ret;
return OpenHostFile(file_name, "r+", cache_type);
}
void SysFileClose(sys_file_t* f) {
@@ -300,10 +250,21 @@ uint64_t SysFileSize(sys_file_t& f) {
return 0;
}
bool SysFileGetInfo(const std::filesystem::path& name, bool* is_file, uint64_t* size) {
const auto path = get_internal_name(name);
struct stat info {};
if (stat(path.c_str(), &info) != 0) {
return false;
}
*is_file = !S_ISDIR(info.st_mode);
*size = *is_file ? static_cast<uint64_t>(info.st_size) : 0;
return true;
}
uint64_t SysFileSize(const std::filesystem::path& file_name) {
sys_file_t* f = SysFileOpenR(file_name);
uint64_t size = SysFileSize(*f);
SysFileClose(f);
bool is_file;
uint64_t size = 0;
SysFileGetInfo(file_name, &is_file, &size);
return size;
}
@@ -356,29 +317,15 @@ bool SysFileIsError(sys_file_t& f) {
}
bool SysFileIsDirectoryExisting(const std::filesystem::path& path) {
auto real_name = get_internal_name(path);
auto real_name_str = real_name.string();
struct stat s {};
if (0 != stat(real_name_str.c_str(), &s)) {
return false;
}
return S_ISDIR(s.st_mode); // NOLINT
bool is_file;
uint64_t size;
return SysFileGetInfo(path, &is_file, &size) && !is_file;
}
bool SysFileIsFileExisting(const std::filesystem::path& name) {
auto real_name = get_internal_name(name);
auto real_name_str = real_name.string();
struct stat s {};
if (0 != stat(real_name_str.c_str(), &s)) {
return false;
}
return !S_ISDIR(s.st_mode); // NOLINT
bool is_file;
uint64_t size;
return SysFileGetInfo(name, &is_file, &size) && is_file;
}
bool SysFileCreateDirectory(const std::filesystem::path& path) {
@@ -613,51 +560,6 @@ bool SysFileSetLastAccessAndWriteTimeUtc(const std::filesystem::path& name,
// }
}
// Recursively collect regular files.
void SysFileFindFiles(const std::filesystem::path& path, std::vector<sys_file_find_t>& out) {
auto real_path = get_internal_name(path);
DIR* dir = opendir(real_path.string().c_str());
if (dir == nullptr) {
return;
}
for (const dirent* entry = readdir(dir); entry != nullptr; entry = readdir(dir)) {
const std::string file_name(entry->d_name);
if (file_name == "." || file_name == "..") {
continue;
}
auto child = real_path / file_name;
struct stat s {};
// lstat, so a symlink is never followed into a cycle during the recursive walk.
if (0 != lstat(child.string().c_str(), &s)) {
continue;
}
if (S_ISDIR(s.st_mode)) {
SysFileFindFiles(child, out);
} else if (S_ISREG(s.st_mode)) {
sys_file_find_t r {};
r.path_with_name = child;
r.size = static_cast<uint64_t>(s.st_size);
r.last_access_time.is_invalid = false;
r.last_access_time.time = s.st_atime;
r.last_access_time.nanos = KYTY_STAT_ATIME_NS(s);
r.last_write_time.is_invalid = false;
r.last_write_time.time = s.st_mtime;
r.last_write_time.nanos = KYTY_STAT_MTIME_NS(s);
out.push_back(r);
}
}
closedir(dir);
}
// Keep "." and ".." to match FindFirstFileW.
void SysFileGetDents(const std::filesystem::path& path, std::vector<sys_dir_entry_t>& out) {
auto real_path = get_internal_name(path);
@@ -693,7 +595,7 @@ bool SysFileCopyFile(const std::filesystem::path& src, const std::filesystem::pa
!error;
}
bool SysFileMoveFile(const std::filesystem::path& src, const std::filesystem::path& dst) {
bool SysFileRenameFile(const std::filesystem::path& src, const std::filesystem::path& dst) {
auto real_src = get_internal_name(src);
auto real_dst = get_internal_name(dst);
+37 -106
View File
@@ -5,7 +5,6 @@
#else
#include "common/assert.h"
#include "common/platform/sysVirtual.h"
#include "common/virtualMemory.h"
#include <atomic>
@@ -28,13 +27,12 @@
#define KYTY_FIXED_NOREPLACE
#endif
namespace Common {
namespace Common::VirtualMemory {
static pthread_mutex_t g_virtual_mutex {};
static std::map<uintptr_t, size_t>* g_allocs = nullptr;
static std::map<uintptr_t, int>* g_protects = nullptr;
static std::map<uintptr_t, size_t>* g_allocs = nullptr;
void SysVirtualInit() {
void Init() {
pthread_mutexattr_t attr {};
pthread_mutexattr_init(&attr);
@@ -46,43 +44,27 @@ void SysVirtualInit() {
pthread_mutex_init(&g_virtual_mutex, &attr);
pthread_mutexattr_destroy(&attr);
g_allocs = new std::map<uintptr_t, size_t>;
g_protects = new std::map<uintptr_t, int>;
g_allocs = new std::map<uintptr_t, size_t>;
}
static int get_protection_flag(VirtualMemory::Mode mode) {
static int get_protection_flag(Mode mode) {
int protect = PROT_NONE;
switch (mode) {
case VirtualMemory::Mode::Read: protect = PROT_READ; break;
case VirtualMemory::Mode::Write:
case VirtualMemory::Mode::ReadWrite: protect = PROT_READ | PROT_WRITE; break; // NOLINT
case VirtualMemory::Mode::Execute: protect = PROT_EXEC; break;
case VirtualMemory::Mode::ExecuteRead: protect = PROT_EXEC | PROT_READ; break; // NOLINT
case VirtualMemory::Mode::ExecuteWrite:
case VirtualMemory::Mode::ExecuteReadWrite:
case Mode::Read: protect = PROT_READ; break;
case Mode::Write:
case Mode::ReadWrite: protect = PROT_READ | PROT_WRITE; break; // NOLINT
case Mode::Execute: protect = PROT_EXEC; break;
case Mode::ExecuteRead: protect = PROT_EXEC | PROT_READ; break; // NOLINT
case Mode::ExecuteWrite:
case Mode::ExecuteReadWrite:
protect = PROT_EXEC | PROT_WRITE | PROT_READ;
break; // NOLINT
case VirtualMemory::Mode::NoAccess:
case Mode::NoAccess:
default: protect = PROT_NONE; break;
}
return protect;
}
static VirtualMemory::Mode get_protection_flag(int mode) {
switch (mode) {
case PROT_NONE: return VirtualMemory::Mode::NoAccess;
case PROT_READ: return VirtualMemory::Mode::Read;
case PROT_WRITE: return VirtualMemory::Mode::Write;
case PROT_READ | PROT_WRITE: return VirtualMemory::Mode::ReadWrite; // NOLINT
case PROT_EXEC: return VirtualMemory::Mode::Execute;
case PROT_EXEC | PROT_WRITE: return VirtualMemory::Mode::ExecuteWrite; // NOLINT
case PROT_EXEC | PROT_READ: return VirtualMemory::Mode::ExecuteRead; // NOLINT
case PROT_EXEC | PROT_WRITE | PROT_READ:
return VirtualMemory::Mode::ExecuteReadWrite; // NOLINT
default: return VirtualMemory::Mode::NoAccess;
}
}
// Keep automatic mappings inside the guest and GPU-addressable low window.
#ifdef KYTY_FIXED_NOREPLACE
static constexpr uintptr_t LOW_ARENA_LIMIT = 0x000000FC00000000ULL; // libc mspace window ceiling
@@ -147,7 +129,7 @@ static void* map_anonymous(uintptr_t addr, size_t size, int protect, int flags)
return mmap(nullptr, size, protect, flags, -1, 0); // NOLINT
}
uint64_t SysVirtualAlloc(uint64_t address, uint64_t size, VirtualMemory::Mode mode) {
uint64_t Alloc(uint64_t address, uint64_t size, Mode mode) {
EXIT_IF(g_allocs == nullptr);
auto addr = static_cast<uintptr_t>(address);
@@ -161,11 +143,6 @@ uint64_t SysVirtualAlloc(uint64_t address, uint64_t size, VirtualMemory::Mode mo
if (ptr != MAP_FAILED) {
pthread_mutex_lock(&g_virtual_mutex);
record_alloc(ret_addr, size);
uintptr_t page_start = ret_addr >> 12u;
uintptr_t page_end = (ret_addr + size - 1) >> 12u;
for (uintptr_t page = page_start; page <= page_end; page++) {
(*g_protects)[page] = protect;
}
pthread_mutex_unlock(&g_virtual_mutex);
}
@@ -176,8 +153,7 @@ static uintptr_t align_up(uintptr_t addr, uint64_t alignment) {
return (addr + alignment - 1) & ~(alignment - 1);
}
uint64_t SysVirtualAllocAligned(uint64_t address, uint64_t size, VirtualMemory::Mode mode,
uint64_t alignment) {
uint64_t AllocAligned(uint64_t address, uint64_t size, Mode mode, uint64_t alignment) {
if (alignment == 0) {
return 0;
}
@@ -246,16 +222,11 @@ uint64_t SysVirtualAllocAligned(uint64_t address, uint64_t size, VirtualMemory::
}
if (ptr == MAP_FAILED) {
return SysVirtualAllocAligned(address, size, mode, alignment << 1u);
return AllocAligned(address, size, mode, alignment << 1u);
}
pthread_mutex_lock(&g_virtual_mutex);
record_alloc(ret_addr, size);
uintptr_t page_start = ret_addr >> 12u;
uintptr_t page_end = (ret_addr + size - 1) >> 12u;
for (uintptr_t page = page_start; page <= page_end; page++) {
(*g_protects)[page] = protect;
}
pthread_mutex_unlock(&g_virtual_mutex);
return ret_addr;
@@ -308,7 +279,7 @@ static bool is_mapped(void* ptr, size_t length) {
}
#endif
bool SysVirtualAllocFixed(uint64_t address, uint64_t size, VirtualMemory::Mode mode) {
bool AllocFixed(uint64_t address, uint64_t size, Mode mode) {
EXIT_IF(g_allocs == nullptr);
auto addr = static_cast<uintptr_t>(address);
@@ -337,11 +308,6 @@ bool SysVirtualAllocFixed(uint64_t address, uint64_t size, VirtualMemory::Mode m
if (ptr != MAP_FAILED) {
pthread_mutex_lock(&g_virtual_mutex);
record_alloc(ret_addr, size);
uintptr_t page_start = ret_addr >> 12u;
uintptr_t page_end = (ret_addr + size - 1) >> 12u;
for (uintptr_t page = page_start; page <= page_end; page++) {
(*g_protects)[page] = protect;
}
pthread_mutex_unlock(&g_virtual_mutex);
return true;
@@ -350,15 +316,15 @@ bool SysVirtualAllocFixed(uint64_t address, uint64_t size, VirtualMemory::Mode m
return false;
}
bool SysVirtualCommit(uint64_t address, uint64_t size, VirtualMemory::Mode mode) {
return SysVirtualProtect(address, size, mode);
bool Commit(uint64_t address, uint64_t size, Mode mode) {
return Protect(address, size, mode);
}
uint64_t SysVirtualReserve(uint64_t address, uint64_t size) {
return SysVirtualReserveAligned(address, size, 1);
uint64_t Reserve(uint64_t address, uint64_t size) {
return ReserveAligned(address, size, 1);
}
uint64_t SysVirtualReserveAligned(uint64_t address, uint64_t size, uint64_t alignment) {
uint64_t ReserveAligned(uint64_t address, uint64_t size, uint64_t alignment) {
if (alignment == 0) {
return 0;
}
@@ -427,7 +393,7 @@ uint64_t SysVirtualReserveAligned(uint64_t address, uint64_t size, uint64_t alig
}
if (ptr == MAP_FAILED) {
return SysVirtualReserveAligned(address, size, alignment << 1u);
return ReserveAligned(address, size, alignment << 1u);
}
pthread_mutex_lock(&g_virtual_mutex);
@@ -437,7 +403,7 @@ uint64_t SysVirtualReserveAligned(uint64_t address, uint64_t size, uint64_t alig
return ret_addr;
}
bool SysVirtualReserveFixed(uint64_t address, uint64_t size) {
bool ReserveFixed(uint64_t address, uint64_t size) {
EXIT_IF(g_allocs == nullptr);
auto addr = static_cast<uintptr_t>(address);
@@ -473,9 +439,9 @@ bool SysVirtualReserveFixed(uint64_t address, uint64_t size) {
return false;
}
bool SysVirtualDecommit(uint64_t address, uint64_t size) {
bool Decommit(uint64_t address, uint64_t size) {
// Drop physical pages while preserving the reservation.
if (!SysVirtualProtect(address, size, VirtualMemory::Mode::NoAccess)) {
if (!Protect(address, size, Mode::NoAccess)) {
return false;
}
@@ -499,7 +465,7 @@ bool SysVirtualDecommit(uint64_t address, uint64_t size) {
return true;
}
bool SysVirtualFree(uint64_t address) {
bool Free(uint64_t address) {
EXIT_IF(g_allocs == nullptr);
size_t size = 0;
@@ -516,21 +482,10 @@ bool SysVirtualFree(uint64_t address) {
return false;
}
if (munmap(reinterpret_cast<void*>(addr), size) == 0) {
uintptr_t page_start = addr >> 12u;
uintptr_t page_end = (addr + size - 1) >> 12u;
pthread_mutex_lock(&g_virtual_mutex);
for (uintptr_t page = page_start; page <= page_end; page++) {
g_protects->erase(page);
}
pthread_mutex_unlock(&g_virtual_mutex);
return true;
}
return false;
return munmap(reinterpret_cast<void*>(addr), size) == 0;
}
bool SysVirtualFreeRange(uint64_t address, uint64_t size) {
bool FreeRange(uint64_t address, uint64_t size) {
EXIT_IF(g_allocs == nullptr);
if (size == 0 || (address & 0xfffu) != 0 || (size & 0xfffu) != 0) {
return false;
@@ -582,46 +537,22 @@ bool SysVirtualFreeRange(uint64_t address, uint64_t size) {
if (end < alloc_end) {
(*g_allocs)[end] = alloc_end - end;
}
for (uintptr_t page = addr >> 12u; page <= (end - 1u) >> 12u; page++) {
g_protects->erase(page);
}
pthread_mutex_unlock(&g_virtual_mutex);
return true;
}
bool SysVirtualProtect(uint64_t address, uint64_t size, VirtualMemory::Mode mode,
VirtualMemory::Mode* old_mode) {
auto addr = static_cast<uintptr_t>(address);
pthread_mutex_lock(&g_virtual_mutex);
if (old_mode != nullptr) {
if (auto s = g_protects->find(addr >> 12u); s != g_protects->end()) {
*old_mode = get_protection_flag(s->second);
} else {
*old_mode = VirtualMemory::Mode::NoAccess;
}
}
pthread_mutex_unlock(&g_virtual_mutex);
uintptr_t page_start = addr >> 12u;
uintptr_t page_end = (addr + size - 1) >> 12u;
if (mprotect(reinterpret_cast<void*>(page_start << 12u), (page_end - page_start + 1) << 12u,
get_protection_flag(mode)) == 0) {
pthread_mutex_lock(&g_virtual_mutex);
for (uintptr_t page = page_start; page <= page_end; page++) {
(*g_protects)[page] = get_protection_flag(mode);
}
pthread_mutex_unlock(&g_virtual_mutex);
return true;
}
return false;
bool Protect(uint64_t address, uint64_t size, Mode mode) {
const auto addr = static_cast<uintptr_t>(address);
const auto page_start = addr >> 12u;
const auto page_end = (addr + size - 1) >> 12u;
return mprotect(reinterpret_cast<void*>(page_start << 12u), (page_end - page_start + 1) << 12u,
get_protection_flag(mode)) == 0;
}
bool SysVirtualFlushInstructionCache(uint64_t /*address*/, uint64_t /*size*/) {
bool FlushInstructionCache(uint64_t /*address*/, uint64_t /*size*/) {
return true;
}
} // namespace Common
} // namespace Common::VirtualMemory
#endif
-53
View File
@@ -1,53 +0,0 @@
#ifndef KYTY_COMMON_PLATFORM_SYSSWAPBYTEORDER_H_
#define KYTY_COMMON_PLATFORM_SYSSWAPBYTEORDER_H_
#include "common/common.h"
#include <type_traits>
inline uint16_t SwapByteOrder16(uint16_t value) {
uint16_t hi = value << 8u;
uint16_t lo = value >> 8u;
return hi | lo;
}
inline uint32_t SwapByteOrder32(uint32_t value) {
return __builtin_bswap32(value);
}
inline uint64_t SwapByteOrder64(uint64_t value) {
return __builtin_bswap64(value);
}
template <typename T>
inline void SwapByteOrder(T& x) {
if (sizeof(x) == 2) {
if (std::is_signed_v<T>) {
x = static_cast<std::make_signed_t<T>>(
SwapByteOrder16(static_cast<std::make_unsigned_t<uint16_t>>(x)));
} else {
x = SwapByteOrder16(x);
}
}
if (sizeof(x) == 4) {
if (std::is_signed_v<T>) {
x = static_cast<std::make_signed_t<T>>(
SwapByteOrder32(static_cast<std::make_unsigned_t<uint32_t>>(x)));
} else {
x = SwapByteOrder32(x);
}
}
if (sizeof(x) == 8) {
if (std::is_signed_v<T>) {
x = static_cast<std::make_signed_t<T>>(
SwapByteOrder64(static_cast<std::make_unsigned_t<uint64_t>>(x)));
} else {
x = SwapByteOrder64(x);
}
}
}
template <typename T>
inline void NoSwapByteOrder(T& x) {}
#endif /* KYTY_COMMON_PLATFORM_SYSSWAPBYTEORDER_H_ */
+1 -5
View File
@@ -151,10 +151,6 @@ inline void SysTimeTToSystem(time_t t, SysTimeStruct& s) {
SysFileToSystemTimeUtc(ft, s);
}
inline time_t SysTimegm(struct tm* tm) {
return timegm(tm);
}
inline void SysSystemToFileTimeUtc(const SysTimeStruct& f, SysFileTimeStruct& t) {
struct tm i {};
@@ -165,7 +161,7 @@ inline void SysSystemToFileTimeUtc(const SysTimeStruct& f, SysFileTimeStruct& t)
i.tm_min = f.Minute;
i.tm_sec = f.Second;
t.is_invalid = (f.is_invalid || (t.time = SysTimegm(&i)) == static_cast<time_t>(-1));
t.is_invalid = (f.is_invalid || (t.time = ::timegm(&i)) == static_cast<time_t>(-1));
}
// Retrieves the current local date and time.
-28
View File
@@ -1,28 +0,0 @@
#ifndef KYTY_COMMON_PLATFORM_SYSVIRTUAL_H_
#define KYTY_COMMON_PLATFORM_SYSVIRTUAL_H_
#include "common/common.h"
#include "common/virtualMemory.h"
namespace Common {
void SysVirtualInit();
uint64_t SysVirtualAlloc(uint64_t address, uint64_t size, VirtualMemory::Mode mode);
uint64_t SysVirtualAllocAligned(uint64_t address, uint64_t size, VirtualMemory::Mode mode,
uint64_t alignment);
bool SysVirtualAllocFixed(uint64_t address, uint64_t size, VirtualMemory::Mode mode);
bool SysVirtualCommit(uint64_t address, uint64_t size, VirtualMemory::Mode mode);
uint64_t SysVirtualReserve(uint64_t address, uint64_t size);
uint64_t SysVirtualReserveAligned(uint64_t address, uint64_t size, uint64_t alignment);
bool SysVirtualReserveFixed(uint64_t address, uint64_t size);
bool SysVirtualDecommit(uint64_t address, uint64_t size);
bool SysVirtualFree(uint64_t address);
bool SysVirtualFreeRange(uint64_t address, uint64_t size);
bool SysVirtualProtect(uint64_t address, uint64_t size, VirtualMemory::Mode mode,
VirtualMemory::Mode* old_mode = nullptr);
bool SysVirtualFlushInstructionCache(uint64_t address, uint64_t size);
} // namespace Common
#endif /* KYTY_COMMON_PLATFORM_SYSVIRTUAL_H_ */

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