Compare commits

...

72 commits

Author SHA1 Message Date
Megamouse ee01d1186f overlays: play SND0.AT3 during initialization
Some checks are pending
Generate Translation Template / Generate Translation Template (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux-aarch64.sh, gcc, rpcs3/rpcs3-ci-jammy-aarch64:1.9, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux.sh, gcc, rpcs3/rpcs3-ci-jammy:1.9, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (a1d35836e8d45bfc6f63c26f0a3e5d46ef622fe1, rpcs3/rpcs3-binaries-linux-arm64, /rpcs3/.ci/build-linux-aarch64.sh, clang, rpcs3/rpcs3-ci-jammy-aarch64:1.9, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (d812f1254a1157c80fd402f94446310560f54e5f, rpcs3/rpcs3-binaries-linux, /rpcs3/.ci/build-linux.sh, clang, rpcs3/rpcs3-ci-jammy:1.9, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (0, 51ae32f468089a8169aaf1567de355ff4a3e0842, rpcs3/rpcs3-binaries-mac, Intel) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (1, 8e21bdbc40711a3fccd18fbf17b742348b0f4281, rpcs3/rpcs3-binaries-mac-arm64, Apple Silicon) (push) Waiting to run
Build RPCS3 / RPCS3 Windows (push) Waiting to run
Build RPCS3 / RPCS3 Windows Clang ${{ matrix.arch }} (aarch64, clang, clangarm64, ARM64, windows-11-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Windows Clang ${{ matrix.arch }} (x86_64, clang, clang64, X64, windows-2025) (push) Waiting to run
Build RPCS3 / RPCS3 FreeBSD (push) Waiting to run
2026-03-11 06:45:22 +01:00
Megamouse 2934641237 overlays: support playing audio with video_view 2026-03-11 06:45:22 +01:00
Elad fecb53f86c Fix SaveStates cellDumxPamf regression
Some checks are pending
Generate Translation Template / Generate Translation Template (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux-aarch64.sh, gcc, rpcs3/rpcs3-ci-jammy-aarch64:1.9, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux.sh, gcc, rpcs3/rpcs3-ci-jammy:1.9, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (a1d35836e8d45bfc6f63c26f0a3e5d46ef622fe1, rpcs3/rpcs3-binaries-linux-arm64, /rpcs3/.ci/build-linux-aarch64.sh, clang, rpcs3/rpcs3-ci-jammy-aarch64:1.9, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (d812f1254a1157c80fd402f94446310560f54e5f, rpcs3/rpcs3-binaries-linux, /rpcs3/.ci/build-linux.sh, clang, rpcs3/rpcs3-ci-jammy:1.9, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (0, 51ae32f468089a8169aaf1567de355ff4a3e0842, rpcs3/rpcs3-binaries-mac, Intel) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (1, 8e21bdbc40711a3fccd18fbf17b742348b0f4281, rpcs3/rpcs3-binaries-mac-arm64, Apple Silicon) (push) Waiting to run
Build RPCS3 / RPCS3 Windows (push) Waiting to run
Build RPCS3 / RPCS3 Windows Clang ${{ matrix.arch }} (aarch64, clang, clangarm64, ARM64, windows-11-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Windows Clang ${{ matrix.arch }} (x86_64, clang, clang64, X64, windows-2025) (push) Waiting to run
Build RPCS3 / RPCS3 FreeBSD (push) Waiting to run
2026-03-10 20:13:29 +02:00
Elad 9811e1cc3b Debugger: Add HW PPU threads view 2026-03-10 20:13:29 +02:00
Elad 234f2b4648 Silence sys_memory_get_user_memory_size 2026-03-10 20:13:29 +02:00
Megamouse 9e573a9ff2 rpcn: set default version to 2 2026-03-10 17:41:48 +01:00
Megamouse 3803c864f7 rpcn: Fix file access error when loading rpcn.yml with version 1
The file was still in use when saving.
2026-03-10 17:41:48 +01:00
Megamouse 8afa40eaa7 rpcn: Fix segfault in rpcn_settings_dialog destructor
This will happen if m_rpcn failed to connect in the constructor.
2026-03-10 17:41:48 +01:00
kd-11 c7a576edce gl: Implement proper, sectioned DMA transfers
Some checks are pending
Generate Translation Template / Generate Translation Template (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux-aarch64.sh, gcc, rpcs3/rpcs3-ci-jammy-aarch64:1.9, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux.sh, gcc, rpcs3/rpcs3-ci-jammy:1.9, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (a1d35836e8d45bfc6f63c26f0a3e5d46ef622fe1, rpcs3/rpcs3-binaries-linux-arm64, /rpcs3/.ci/build-linux-aarch64.sh, clang, rpcs3/rpcs3-ci-jammy-aarch64:1.9, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (d812f1254a1157c80fd402f94446310560f54e5f, rpcs3/rpcs3-binaries-linux, /rpcs3/.ci/build-linux.sh, clang, rpcs3/rpcs3-ci-jammy:1.9, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (0, 51ae32f468089a8169aaf1567de355ff4a3e0842, rpcs3/rpcs3-binaries-mac, Intel) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (1, 8e21bdbc40711a3fccd18fbf17b742348b0f4281, rpcs3/rpcs3-binaries-mac-arm64, Apple Silicon) (push) Waiting to run
Build RPCS3 / RPCS3 Windows (push) Waiting to run
Build RPCS3 / RPCS3 Windows Clang ${{ matrix.arch }} (aarch64, clang, clangarm64, ARM64, windows-11-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Windows Clang ${{ matrix.arch }} (x86_64, clang, clang64, X64, windows-2025) (push) Waiting to run
Build RPCS3 / RPCS3 FreeBSD (push) Waiting to run
- Allows to transfer partial contents when needed
2026-03-10 16:25:32 +03:00
kd-11 c72d54bd6a gl: Add guards to catch invalid configuration in image transfer functions 2026-03-10 16:25:32 +03:00
kd-11 040a79ddd1 gl: Improve object annotation for renderdoc debugging 2026-03-10 16:25:32 +03:00
kd-11 aa094ca948 gl: Trace memory readback operations to debug tracking when renderdoc compat is enabled
- Renderdoc does not show these calls so we need to insert the debug message
2026-03-10 16:25:32 +03:00
kd-11 7917520633 gl: Support packing/unpacking images with padding 2026-03-10 16:25:32 +03:00
kd-11 8651875e59 gl: Add optional row length to GPU image routines 2026-03-10 16:25:32 +03:00
kd-11 ef70a6e825 gl: Move ownership of the global blitter object from texture cache to global 2026-03-10 16:25:32 +03:00
kd-11 0869ef421d gl: Silence compiler warning 2026-03-10 16:25:32 +03:00
kd-11 5f86315ae0 gl: Fix shader interpreter compilation 2026-03-10 16:25:32 +03:00
kd-11 ab72ce418e gl: Minor enhancements to blitter
- Move some functions to cpp. Makes it easier to debug failing image operations
- Add fbo validation before blit operations
2026-03-10 16:25:32 +03:00
kd-11 36cdaac327 overlays: Fix image size estimation 2026-03-10 16:25:32 +03:00
kd-11 6d52415d50 gl: Ignore range offset when doing readback operations
- OGL desperately needs a functioning DMA layer
2026-03-10 16:25:32 +03:00
Megamouse 0603d24a91 Qt: play SND0.AT3 in game lists when a movie would play 2026-03-10 12:42:56 +01:00
Megamouse 71f0d5c602 cellGem: fix RAW8 to RGBA_320x240
Some checks are pending
Generate Translation Template / Generate Translation Template (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux-aarch64.sh, gcc, rpcs3/rpcs3-ci-jammy-aarch64:1.9, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux.sh, gcc, rpcs3/rpcs3-ci-jammy:1.9, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (a1d35836e8d45bfc6f63c26f0a3e5d46ef622fe1, rpcs3/rpcs3-binaries-linux-arm64, /rpcs3/.ci/build-linux-aarch64.sh, clang, rpcs3/rpcs3-ci-jammy-aarch64:1.9, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (d812f1254a1157c80fd402f94446310560f54e5f, rpcs3/rpcs3-binaries-linux, /rpcs3/.ci/build-linux.sh, clang, rpcs3/rpcs3-ci-jammy:1.9, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (0, 51ae32f468089a8169aaf1567de355ff4a3e0842, rpcs3/rpcs3-binaries-mac, Intel) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (1, 8e21bdbc40711a3fccd18fbf17b742348b0f4281, rpcs3/rpcs3-binaries-mac-arm64, Apple Silicon) (push) Waiting to run
Build RPCS3 / RPCS3 Windows (push) Waiting to run
Build RPCS3 / RPCS3 Windows Clang ${{ matrix.arch }} (aarch64, clang, clangarm64, ARM64, windows-11-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Windows Clang ${{ matrix.arch }} (x86_64, clang, clang64, X64, windows-2025) (push) Waiting to run
Build RPCS3 / RPCS3 FreeBSD (push) Waiting to run
We were basically writing two rows into dst for each other src line.
This means we were writing 480 lines in total instead of 240,
overwriting one of the lines written in the previous iteration.
This led to writing one line out of bounds last iteration.
Let's just use a simple debayer technique which perfectly matches here.
This also applies the previously missing gain factors.

I also tried to first demosaic and then drop every other pixel.
The result was comparatively blurred and the performance worse.
2026-03-10 07:01:55 +01:00
Megamouse 763001ee91 cellGem: fix gain channels 2026-03-10 07:01:55 +01:00
Megamouse 0f92ea2578 cellGem: fix memcpy in cellGemReadExternalPortDeviceInfo
It was copying from dst to src, and the wrong size at that
2026-03-10 07:01:55 +01:00
Megamouse e0a0d736c4 cellGem: remove redundant check 2026-03-10 07:01:55 +01:00
Ani 65320446f0 vk: Add 0x13C0 NAVI2 device ID (Raphael Mendocino)
Some checks are pending
Generate Translation Template / Generate Translation Template (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux-aarch64.sh, gcc, rpcs3/rpcs3-ci-jammy-aarch64:1.9, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux.sh, gcc, rpcs3/rpcs3-ci-jammy:1.9, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (a1d35836e8d45bfc6f63c26f0a3e5d46ef622fe1, rpcs3/rpcs3-binaries-linux-arm64, /rpcs3/.ci/build-linux-aarch64.sh, clang, rpcs3/rpcs3-ci-jammy-aarch64:1.9, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (d812f1254a1157c80fd402f94446310560f54e5f, rpcs3/rpcs3-binaries-linux, /rpcs3/.ci/build-linux.sh, clang, rpcs3/rpcs3-ci-jammy:1.9, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (0, 51ae32f468089a8169aaf1567de355ff4a3e0842, rpcs3/rpcs3-binaries-mac, Intel) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (1, 8e21bdbc40711a3fccd18fbf17b742348b0f4281, rpcs3/rpcs3-binaries-mac-arm64, Apple Silicon) (push) Waiting to run
Build RPCS3 / RPCS3 Windows (push) Waiting to run
Build RPCS3 / RPCS3 Windows Clang ${{ matrix.arch }} (aarch64, clang, clangarm64, ARM64, windows-11-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Windows Clang ${{ matrix.arch }} (x86_64, clang, clang64, X64, windows-2025) (push) Waiting to run
Build RPCS3 / RPCS3 FreeBSD (push) Waiting to run
This is the iGPU on 9800X3D
2026-03-09 19:32:09 +02:00
kd-11 5f6822042d gl: Silence warnings
Some checks are pending
Generate Translation Template / Generate Translation Template (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux-aarch64.sh, gcc, rpcs3/rpcs3-ci-jammy-aarch64:1.9, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux.sh, gcc, rpcs3/rpcs3-ci-jammy:1.9, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (a1d35836e8d45bfc6f63c26f0a3e5d46ef622fe1, rpcs3/rpcs3-binaries-linux-arm64, /rpcs3/.ci/build-linux-aarch64.sh, clang, rpcs3/rpcs3-ci-jammy-aarch64:1.9, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (d812f1254a1157c80fd402f94446310560f54e5f, rpcs3/rpcs3-binaries-linux, /rpcs3/.ci/build-linux.sh, clang, rpcs3/rpcs3-ci-jammy:1.9, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (0, 51ae32f468089a8169aaf1567de355ff4a3e0842, rpcs3/rpcs3-binaries-mac, Intel) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (1, 8e21bdbc40711a3fccd18fbf17b742348b0f4281, rpcs3/rpcs3-binaries-mac-arm64, Apple Silicon) (push) Waiting to run
Build RPCS3 / RPCS3 Windows (push) Waiting to run
Build RPCS3 / RPCS3 Windows Clang ${{ matrix.arch }} (aarch64, clang, clangarm64, ARM64, windows-11-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Windows Clang ${{ matrix.arch }} (x86_64, clang, clang64, X64, windows-2025) (push) Waiting to run
Build RPCS3 / RPCS3 FreeBSD (push) Waiting to run
2026-03-09 15:18:47 +03:00
kd-11 302e87c920 rsx/vk: Improve robustness when encountering corrupted shaders 2026-03-09 15:18:47 +03:00
RipleyTom 77cbdd82ab LLVM 22 fixups
Some checks are pending
Generate Translation Template / Generate Translation Template (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux-aarch64.sh, gcc, rpcs3/rpcs3-ci-jammy-aarch64:1.9, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux.sh, gcc, rpcs3/rpcs3-ci-jammy:1.9, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (a1d35836e8d45bfc6f63c26f0a3e5d46ef622fe1, rpcs3/rpcs3-binaries-linux-arm64, /rpcs3/.ci/build-linux-aarch64.sh, clang, rpcs3/rpcs3-ci-jammy-aarch64:1.9, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (d812f1254a1157c80fd402f94446310560f54e5f, rpcs3/rpcs3-binaries-linux, /rpcs3/.ci/build-linux.sh, clang, rpcs3/rpcs3-ci-jammy:1.9, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (0, 51ae32f468089a8169aaf1567de355ff4a3e0842, rpcs3/rpcs3-binaries-mac, Intel) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (1, 8e21bdbc40711a3fccd18fbf17b742348b0f4281, rpcs3/rpcs3-binaries-mac-arm64, Apple Silicon) (push) Waiting to run
Build RPCS3 / RPCS3 Windows (push) Waiting to run
Build RPCS3 / RPCS3 Windows Clang ${{ matrix.arch }} (aarch64, clang, clangarm64, ARM64, windows-11-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Windows Clang ${{ matrix.arch }} (x86_64, clang, clang64, X64, windows-2025) (push) Waiting to run
Build RPCS3 / RPCS3 FreeBSD (push) Waiting to run
From https://releases.llvm.org/22.1.0/docs/ReleaseNotes.html:
The alignment argument of the @llvm.masked.load, @llvm.masked.store, @llvm.masked.gather and @llvm.masked.scatter intrinsics has been removed. Instead, the align attribute should be placed on the pointer (or vector of pointers) argument.

They also changed(not in changelog for some reason):
vpdpbusd_128: [v4i32] -> [v4i32, v4i32, v4i32]
to
vpdpbusd_128: [v4i32] -> [v4i32, v16i8, v16i8]
2026-03-09 06:30:29 +02:00
Megamouse 41db06b53f cellGem: fix handle_pos calculation
Some checks are pending
Generate Translation Template / Generate Translation Template (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux-aarch64.sh, gcc, rpcs3/rpcs3-ci-jammy-aarch64:1.9, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux.sh, gcc, rpcs3/rpcs3-ci-jammy:1.9, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (a1d35836e8d45bfc6f63c26f0a3e5d46ef622fe1, rpcs3/rpcs3-binaries-linux-arm64, /rpcs3/.ci/build-linux-aarch64.sh, clang, rpcs3/rpcs3-ci-jammy-aarch64:1.9, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (d812f1254a1157c80fd402f94446310560f54e5f, rpcs3/rpcs3-binaries-linux, /rpcs3/.ci/build-linux.sh, clang, rpcs3/rpcs3-ci-jammy:1.9, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (0, 51ae32f468089a8169aaf1567de355ff4a3e0842, rpcs3/rpcs3-binaries-mac, Intel) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (1, 8e21bdbc40711a3fccd18fbf17b742348b0f4281, rpcs3/rpcs3-binaries-mac-arm64, Apple Silicon) (push) Waiting to run
Build RPCS3 / RPCS3 Windows (push) Waiting to run
Build RPCS3 / RPCS3 Windows Clang ${{ matrix.arch }} (aarch64, clang, clangarm64, ARM64, windows-11-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Windows Clang ${{ matrix.arch }} (x86_64, clang, clang64, X64, windows-2025) (push) Waiting to run
Build RPCS3 / RPCS3 FreeBSD (push) Waiting to run
The handle position depends on the sphere position and the orientation
2026-03-08 16:12:44 +01:00
Megamouse eeda9c7738 cellGem: improve quaternion rotation
rotate_vector caused wrong results for default_orientation and 0,0,x
2026-03-08 16:12:44 +01:00
Megamouse c38bf70464 cellCamera: improve error logging 2026-03-08 16:12:44 +01:00
RipleyTom 43b295892f PPUAnalyzer: Fix SLDI shift operand
Some checks are pending
Generate Translation Template / Generate Translation Template (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux-aarch64.sh, gcc, rpcs3/rpcs3-ci-jammy-aarch64:1.9, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux.sh, gcc, rpcs3/rpcs3-ci-jammy:1.9, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (a1d35836e8d45bfc6f63c26f0a3e5d46ef622fe1, rpcs3/rpcs3-binaries-linux-arm64, /rpcs3/.ci/build-linux-aarch64.sh, clang, rpcs3/rpcs3-ci-jammy-aarch64:1.9, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (d812f1254a1157c80fd402f94446310560f54e5f, rpcs3/rpcs3-binaries-linux, /rpcs3/.ci/build-linux.sh, clang, rpcs3/rpcs3-ci-jammy:1.9, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (0, 51ae32f468089a8169aaf1567de355ff4a3e0842, rpcs3/rpcs3-binaries-mac, Intel) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (1, 8e21bdbc40711a3fccd18fbf17b742348b0f4281, rpcs3/rpcs3-binaries-mac-arm64, Apple Silicon) (push) Waiting to run
Build RPCS3 / RPCS3 Windows (push) Waiting to run
Build RPCS3 / RPCS3 Windows Clang ${{ matrix.arch }} (aarch64, clang, clangarm64, ARM64, windows-11-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Windows Clang ${{ matrix.arch }} (x86_64, clang, clang64, X64, windows-2025) (push) Waiting to run
Build RPCS3 / RPCS3 FreeBSD (push) Waiting to run
2026-03-08 09:29:48 +02:00
capriots 2573cc5fd0 cellDmuxPamf: fix stream cache not being consumed in some cases
Some checks are pending
Generate Translation Template / Generate Translation Template (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux-aarch64.sh, gcc, rpcs3/rpcs3-ci-jammy-aarch64:1.9, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux.sh, gcc, rpcs3/rpcs3-ci-jammy:1.9, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (a1d35836e8d45bfc6f63c26f0a3e5d46ef622fe1, rpcs3/rpcs3-binaries-linux-arm64, /rpcs3/.ci/build-linux-aarch64.sh, clang, rpcs3/rpcs3-ci-jammy-aarch64:1.9, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (d812f1254a1157c80fd402f94446310560f54e5f, rpcs3/rpcs3-binaries-linux, /rpcs3/.ci/build-linux.sh, clang, rpcs3/rpcs3-ci-jammy:1.9, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (0, 51ae32f468089a8169aaf1567de355ff4a3e0842, rpcs3/rpcs3-binaries-mac, Intel) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (1, 8e21bdbc40711a3fccd18fbf17b742348b0f4281, rpcs3/rpcs3-binaries-mac-arm64, Apple Silicon) (push) Waiting to run
Build RPCS3 / RPCS3 Windows (push) Waiting to run
Build RPCS3 / RPCS3 Windows Clang ${{ matrix.arch }} (aarch64, clang, clangarm64, ARM64, windows-11-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Windows Clang ${{ matrix.arch }} (x86_64, clang, clang64, X64, windows-2025) (push) Waiting to run
Build RPCS3 / RPCS3 FreeBSD (push) Waiting to run
2026-03-07 21:46:07 +02:00
capriots 4828d4d2d6 cellDmuxPamf: review fixes 2026-03-07 21:46:07 +02:00
capriots c5f278ed37 cellDmuxPamf: properly handle streams smaller than 0x800 bytes 2026-03-07 21:46:07 +02:00
capriots b839d4d1a6 cellDmuxPamf: consume guest memory on SPU thread group creation 2026-03-07 21:46:07 +02:00
capriots 3616424b26 cellDmuxPamf: fix lv2 mutex + cond not being destroyed on close 2026-03-07 21:46:07 +02:00
capriots 4d6da6542e tests: enable cellDmuxPamf tests in CMakeLists 2026-03-07 21:46:07 +02:00
capriots f2aa347608 cellDmuxPamf: review fixes + improvements 2026-03-07 21:46:07 +02:00
capriots bd7d5faa9f cellDmuxPamf implementation part 2: PPU thread 2026-03-07 21:46:07 +02:00
capriots a3d09a7427 tests: cellDmuxPamf 2026-03-07 21:46:07 +02:00
capriots 7dad9663b2 cellDmuxPamf implementation part 1: SPU thread 2026-03-07 21:46:07 +02:00
kd-11 cae8ae63e3 gl: Use image dimensions to determine read buffer size 2026-03-07 16:29:11 +03:00
kd-11 728d84b1fe gl: Add debug names to some objects 2026-03-07 16:29:11 +03:00
kd-11 4a51302c58 gl: Propagate native layout from parent when creating temporary subresources 2026-03-07 16:29:11 +03:00
kd-11 0ea692e9ab gl: Use named_object<GL_TEXTURE> as the base class for images 2026-03-07 16:29:11 +03:00
kd-11 1e16b338b4 gl: Add support for named objects 2026-03-07 16:29:11 +03:00
kd-11 14789b536f gl: Clean up the awful image copy API
- Wrap everything in rsx::io_buffer and gl::buffer to avoid out of bounds issues.
- Also abstracts away nasty things like OpenGL offset pointer casts.
2026-03-07 16:29:11 +03:00
RipleyTom ac30feeddb Revert enabling PPU jump elider
Some checks are pending
Generate Translation Template / Generate Translation Template (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux-aarch64.sh, gcc, rpcs3/rpcs3-ci-jammy-aarch64:1.9, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux.sh, gcc, rpcs3/rpcs3-ci-jammy:1.9, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (a1d35836e8d45bfc6f63c26f0a3e5d46ef622fe1, rpcs3/rpcs3-binaries-linux-arm64, /rpcs3/.ci/build-linux-aarch64.sh, clang, rpcs3/rpcs3-ci-jammy-aarch64:1.9, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (d812f1254a1157c80fd402f94446310560f54e5f, rpcs3/rpcs3-binaries-linux, /rpcs3/.ci/build-linux.sh, clang, rpcs3/rpcs3-ci-jammy:1.9, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (0, 51ae32f468089a8169aaf1567de355ff4a3e0842, rpcs3/rpcs3-binaries-mac, Intel) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (1, 8e21bdbc40711a3fccd18fbf17b742348b0f4281, rpcs3/rpcs3-binaries-mac-arm64, Apple Silicon) (push) Waiting to run
Build RPCS3 / RPCS3 Windows (push) Waiting to run
Build RPCS3 / RPCS3 Windows Clang ${{ matrix.arch }} (aarch64, clang, clangarm64, ARM64, windows-11-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Windows Clang ${{ matrix.arch }} (x86_64, clang, clang64, X64, windows-2025) (push) Waiting to run
Build RPCS3 / RPCS3 FreeBSD (push) Waiting to run
2026-03-06 21:10:40 +00:00
Megamouse 0d80e300a0 Qt: add log level settings
Some checks are pending
Generate Translation Template / Generate Translation Template (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux-aarch64.sh, gcc, rpcs3/rpcs3-ci-jammy-aarch64:1.9, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux.sh, gcc, rpcs3/rpcs3-ci-jammy:1.9, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (a1d35836e8d45bfc6f63c26f0a3e5d46ef622fe1, rpcs3/rpcs3-binaries-linux-arm64, /rpcs3/.ci/build-linux-aarch64.sh, clang, rpcs3/rpcs3-ci-jammy-aarch64:1.9, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (d812f1254a1157c80fd402f94446310560f54e5f, rpcs3/rpcs3-binaries-linux, /rpcs3/.ci/build-linux.sh, clang, rpcs3/rpcs3-ci-jammy:1.9, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (0, 51ae32f468089a8169aaf1567de355ff4a3e0842, rpcs3/rpcs3-binaries-mac, Intel) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (1, 8e21bdbc40711a3fccd18fbf17b742348b0f4281, rpcs3/rpcs3-binaries-mac-arm64, Apple Silicon) (push) Waiting to run
Build RPCS3 / RPCS3 Windows (push) Waiting to run
Build RPCS3 / RPCS3 Windows Clang ${{ matrix.arch }} (aarch64, clang, clangarm64, ARM64, windows-11-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Windows Clang ${{ matrix.arch }} (x86_64, clang, clang64, X64, windows-2025) (push) Waiting to run
Build RPCS3 / RPCS3 FreeBSD (push) Waiting to run
2026-03-06 15:06:25 +01:00
Megamouse 69384d7bb4 Update codebase to SDL 3.4.0 2026-03-06 13:56:04 +01:00
Megamouse 4fd2409b8b Update FAudio to 26.03 2026-03-06 13:56:04 +01:00
Megamouse d97851376d Add stacktrace in case of exception 2026-03-06 13:56:04 +01:00
Megamouse 1c5e30e83f input/qt: fix default squircle value in text and remove duplicate comments 2026-03-06 13:56:04 +01:00
kd-11 414df8432e gl: Respect internal offsets when performing DMA transfer operations
Some checks are pending
Generate Translation Template / Generate Translation Template (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux-aarch64.sh, gcc, rpcs3/rpcs3-ci-jammy-aarch64:1.9, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux.sh, gcc, rpcs3/rpcs3-ci-jammy:1.9, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (a1d35836e8d45bfc6f63c26f0a3e5d46ef622fe1, rpcs3/rpcs3-binaries-linux-arm64, /rpcs3/.ci/build-linux-aarch64.sh, clang, rpcs3/rpcs3-ci-jammy-aarch64:1.9, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (d812f1254a1157c80fd402f94446310560f54e5f, rpcs3/rpcs3-binaries-linux, /rpcs3/.ci/build-linux.sh, clang, rpcs3/rpcs3-ci-jammy:1.9, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (0, 51ae32f468089a8169aaf1567de355ff4a3e0842, rpcs3/rpcs3-binaries-mac, Intel) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (1, 8e21bdbc40711a3fccd18fbf17b742348b0f4281, rpcs3/rpcs3-binaries-mac-arm64, Apple Silicon) (push) Waiting to run
Build RPCS3 / RPCS3 Windows (push) Waiting to run
Build RPCS3 / RPCS3 Windows Clang ${{ matrix.arch }} (aarch64, clang, clangarm64, ARM64, windows-11-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Windows Clang ${{ matrix.arch }} (x86_64, clang, clang64, X64, windows-2025) (push) Waiting to run
Build RPCS3 / RPCS3 FreeBSD (push) Waiting to run
2026-03-06 12:18:18 +03:00
kd-11 92f63ccc0b rsx/cfg: Silence GCC noise 2026-03-06 12:18:18 +03:00
kd-11 d75e8b24f7 [FIXUP] API extend 2026-03-06 12:18:18 +03:00
kd-11 a1af15b907 gl/dma: Fix range calculation when creating DMA blocks 2026-03-06 12:18:18 +03:00
kd-11 cf5eb22591 glutils: Extend buffer_object interface 2026-03-06 12:18:18 +03:00
RipleyTom 2f9f79eea2 PPU Fixes
-CallFunction empty function/jump elision was never gone through as cond was always false
-MSelf duplicate offset detection never triggered because set was reset each loop
-Rel executable memory size calculation used wrong section type
2026-03-06 10:49:59 +02:00
Megamouse c57d6110c4 rsx: add missing default to switch
Some checks are pending
Generate Translation Template / Generate Translation Template (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux-aarch64.sh, gcc, rpcs3/rpcs3-ci-jammy-aarch64:1.9, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux.sh, gcc, rpcs3/rpcs3-ci-jammy:1.9, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (a1d35836e8d45bfc6f63c26f0a3e5d46ef622fe1, rpcs3/rpcs3-binaries-linux-arm64, /rpcs3/.ci/build-linux-aarch64.sh, clang, rpcs3/rpcs3-ci-jammy-aarch64:1.9, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (d812f1254a1157c80fd402f94446310560f54e5f, rpcs3/rpcs3-binaries-linux, /rpcs3/.ci/build-linux.sh, clang, rpcs3/rpcs3-ci-jammy:1.9, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (0, 51ae32f468089a8169aaf1567de355ff4a3e0842, rpcs3/rpcs3-binaries-mac, Intel) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (1, 8e21bdbc40711a3fccd18fbf17b742348b0f4281, rpcs3/rpcs3-binaries-mac-arm64, Apple Silicon) (push) Waiting to run
Build RPCS3 / RPCS3 Windows (push) Waiting to run
Build RPCS3 / RPCS3 Windows Clang ${{ matrix.arch }} (aarch64, clang, clangarm64, ARM64, windows-11-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Windows Clang ${{ matrix.arch }} (x86_64, clang, clang64, X64, windows-2025) (push) Waiting to run
Build RPCS3 / RPCS3 FreeBSD (push) Waiting to run
2026-03-05 21:05:15 +01:00
Megamouse 2a292d1e2e rsx: fix unused parameter warning 2026-03-05 21:05:15 +01:00
Megamouse f2c8b157ef ISO: pass mode to file 2026-03-05 21:05:15 +01:00
Megamouse ec00a06caf Fix warning suppression in windows clang 2026-03-05 21:05:15 +01:00
Megamouse ae6172d86b Remove unused function 2026-03-05 21:05:15 +01:00
Megamouse 5605cf2141 Qt: Do not check return code of rpcs3 download 2026-03-05 17:25:45 +01:00
RipleyTom d46ddcee5d Fix mac build
Some checks are pending
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux-aarch64.sh, gcc, rpcs3/rpcs3-ci-jammy-aarch64:1.9, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux.sh, gcc, rpcs3/rpcs3-ci-jammy:1.9, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (a1d35836e8d45bfc6f63c26f0a3e5d46ef622fe1, rpcs3/rpcs3-binaries-linux-arm64, /rpcs3/.ci/build-linux-aarch64.sh, clang, rpcs3/rpcs3-ci-jammy-aarch64:1.9, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (d812f1254a1157c80fd402f94446310560f54e5f, rpcs3/rpcs3-binaries-linux, /rpcs3/.ci/build-linux.sh, clang, rpcs3/rpcs3-ci-jammy:1.9, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (0, 51ae32f468089a8169aaf1567de355ff4a3e0842, rpcs3/rpcs3-binaries-mac, Intel) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (1, 8e21bdbc40711a3fccd18fbf17b742348b0f4281, rpcs3/rpcs3-binaries-mac-arm64, Apple Silicon) (push) Waiting to run
Build RPCS3 / RPCS3 Windows (push) Waiting to run
Build RPCS3 / RPCS3 Windows Clang ${{ matrix.arch }} (aarch64, clang, clangarm64, ARM64, windows-11-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Windows Clang ${{ matrix.arch }} (x86_64, clang, clang64, X64, windows-2025) (push) Waiting to run
Build RPCS3 / RPCS3 FreeBSD (push) Waiting to run
2026-03-04 21:08:07 +03:00
Megamouse 3750fb2c1f cellGem: Fix deadlock when cellGemUpdateStart is called before cellCamera delivers images
Some checks failed
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux-aarch64.sh, gcc, rpcs3/rpcs3-ci-jammy-aarch64:1.9, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux.sh, gcc, rpcs3/rpcs3-ci-jammy:1.9, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (a1d35836e8d45bfc6f63c26f0a3e5d46ef622fe1, rpcs3/rpcs3-binaries-linux-arm64, /rpcs3/.ci/build-linux-aarch64.sh, clang, rpcs3/rpcs3-ci-jammy-aarch64:1.9, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (d812f1254a1157c80fd402f94446310560f54e5f, rpcs3/rpcs3-binaries-linux, /rpcs3/.ci/build-linux.sh, clang, rpcs3/rpcs3-ci-jammy:1.9, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (0, 51ae32f468089a8169aaf1567de355ff4a3e0842, rpcs3/rpcs3-binaries-mac, Intel) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (1, 8e21bdbc40711a3fccd18fbf17b742348b0f4281, rpcs3/rpcs3-binaries-mac-arm64, Apple Silicon) (push) Waiting to run
Build RPCS3 / RPCS3 Windows (push) Waiting to run
Build RPCS3 / RPCS3 Windows Clang ${{ matrix.arch }} (aarch64, clang, clangarm64, ARM64, windows-11-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Windows Clang ${{ matrix.arch }} (x86_64, clang, clang64, X64, windows-2025) (push) Waiting to run
Build RPCS3 / RPCS3 FreeBSD (push) Waiting to run
Generate Translation Template / Generate Translation Template (push) Has been cancelled
2026-03-04 11:31:32 +01:00
kd-11 86b2773c28 rsx: Clean up after vertex cache changes
Some checks are pending
Generate Translation Template / Generate Translation Template (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux-aarch64.sh, gcc, rpcs3/rpcs3-ci-jammy-aarch64:1.9, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux.sh, gcc, rpcs3/rpcs3-ci-jammy:1.9, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (a1d35836e8d45bfc6f63c26f0a3e5d46ef622fe1, rpcs3/rpcs3-binaries-linux-arm64, /rpcs3/.ci/build-linux-aarch64.sh, clang, rpcs3/rpcs3-ci-jammy-aarch64:1.9, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (d812f1254a1157c80fd402f94446310560f54e5f, rpcs3/rpcs3-binaries-linux, /rpcs3/.ci/build-linux.sh, clang, rpcs3/rpcs3-ci-jammy:1.9, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (0, 51ae32f468089a8169aaf1567de355ff4a3e0842, rpcs3/rpcs3-binaries-mac, Intel) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (1, 8e21bdbc40711a3fccd18fbf17b742348b0f4281, rpcs3/rpcs3-binaries-mac-arm64, Apple Silicon) (push) Waiting to run
Build RPCS3 / RPCS3 Windows (push) Waiting to run
Build RPCS3 / RPCS3 Windows Clang ${{ matrix.arch }} (aarch64, clang, clangarm64, ARM64, windows-11-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Windows Clang ${{ matrix.arch }} (x86_64, clang, clang64, X64, windows-2025) (push) Waiting to run
Build RPCS3 / RPCS3 FreeBSD (push) Waiting to run
2026-03-04 03:54:39 +03:00
kd-11 11a9011510 rsx: Fix memory misalignment for temporary storage
- We create the temp storage with alignment of U but then do a type cast to u128 later. This obviously causes problems.
2026-03-04 03:54:39 +03:00
Iván Díaz Álvarez e66f1fa306 Solves render problems due to vertex data being modified before reuse
* Stores first 64bit of the vertex data to compare on retrieval as a fingerprint of if the underlying vertex data has been changed
2026-03-04 01:31:01 +03:00
115 changed files with 5936 additions and 625 deletions

View file

@ -17,7 +17,7 @@ brew install -f --overwrite --quiet ccache "llvm@$LLVM_COMPILER_VER"
brew link -f --overwrite --quiet "llvm@$LLVM_COMPILER_VER"
if [ "$AARCH64" -eq 1 ]; then
brew install -f --overwrite --quiet googletest opencv@4 sdl3 vulkan-headers vulkan-loader molten-vk
brew unlink --quiet ffmpeg fmt qtbase qtsvg qtdeclarative protobuf
brew unlink --quiet ffmpeg fmt qtbase qtsvg qtdeclarative
else
arch -x86_64 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
arch -x86_64 /usr/local/bin/brew install -f --overwrite --quiet python@3.14 opencv@4 "llvm@$LLVM_COMPILER_VER" sdl3 vulkan-headers vulkan-loader molten-vk

2
3rdparty/FAudio vendored

@ -1 +1 @@
Subproject commit e67d761ead486de3e69fa11705456bf94df734ca
Subproject commit dc034fc671b07bbd14e8410d5dd6be6da38fdf6d

@ -1 +1 @@
Subproject commit 05c44fcd18074836e21e1eda9fc02b3a4a1529b5
Subproject commit 51a5d623e3fde1f58829a56ba910f1cb33596222

View file

@ -416,7 +416,7 @@ void cfg::encode(YAML::Emitter& out, const cfg::_base& rhs)
out << YAML::BeginMap;
for (const auto& np : static_cast<const log_entry&>(rhs).get_map())
{
if (np.second == logs::level::notice) continue;
if (np.second == logs::level::_default) continue;
out << YAML::Key << np.first;
out << YAML::Value << fmt::format("%s", np.second);
}

View file

@ -16,12 +16,12 @@
#include <errno.h>
#endif
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4996)
#elif defined(__clang__)
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#elif defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable : 4996)
#else
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"

View file

@ -14,6 +14,11 @@
#include "Emu/CPU/Backends/AArch64/AArch64Signal.h"
#endif
#ifdef __cpp_lib_stacktrace
#include "rpcs3_version.h"
#include <stacktrace>
#endif
#ifdef _WIN32
#include <Windows.h>
#include <Psapi.h>
@ -2800,6 +2805,16 @@ void thread_base::exec()
[[noreturn]] void thread_ctrl::emergency_exit(std::string_view reason)
{
// Print stacktrace
#ifdef __cpp_lib_stacktrace
if (rpcs3::is_local_build())
{
std::ostringstream oss;
oss << std::stacktrace::current();
sys_log.notice("StackTrace\n\n%s\n", oss.str());
}
#endif
if (const std::string info = dump_useful_thread_info(); !info.empty())
{
sys_log.notice("\n%s", info);

View file

@ -195,6 +195,7 @@ if(BUILD_RPCS3_TESTS)
tests/test_address_range.cpp
tests/test_rsx_cfg.cpp
tests/test_rsx_fp_asm.cpp
tests/test_dmux_pamf.cpp
)
target_link_libraries(rpcs3_test
@ -202,6 +203,7 @@ if(BUILD_RPCS3_TESTS)
rpcs3_lib
rpcs3_emu
GTest::gtest
GTest::gmock
)
target_include_directories(rpcs3_test

View file

@ -500,6 +500,7 @@ target_sources(rpcs3_emu PRIVATE
RSX/Overlays/overlays.cpp
RSX/Overlays/overlay_animated_icon.cpp
RSX/Overlays/overlay_animation.cpp
RSX/Overlays/overlay_audio.cpp
RSX/Overlays/overlay_compile_notification.cpp
RSX/Overlays/overlay_controls.cpp
RSX/Overlays/overlay_cursor.cpp

View file

@ -20,19 +20,19 @@ namespace aarch64
sp
};
static const char* gpr_names[] =
[[maybe_unused]] static const char* gpr_names[] =
{
"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9",
"x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "x19",
"x20", "x21", "x22", "x23", "x24", "x25", "x26", "x27", "x28", "x29", "x30"
};
static const char* spr_names[] =
[[maybe_unused]] static const char* spr_names[] =
{
"xzr", "pc", "sp"
};
static const char* spr_asm_names[] =
[[maybe_unused]] static const char* spr_asm_names[] =
{
"xzr", ".", "sp"
};

View file

@ -1373,7 +1373,7 @@ std::vector<std::pair<u32, u32>> cpu_thread::dump_callstack_list() const
std::string cpu_thread::dump_misc() const
{
return fmt::format("Type: %s; State: %s\n", get_class() == thread_class::ppu ? "PPU" : get_class() == thread_class::spu ? "SPU" : "RSX", state.load());
return fmt::format("%s[0x%x]; State: %s\n", get_class() == thread_class::ppu ? "PPU" : get_class() == thread_class::spu ? "SPU" : "RSX", id, state.load());
}
bool cpu_thread::suspend_work::push(cpu_thread* _this) noexcept

View file

@ -3647,7 +3647,14 @@ public:
const auto data0 = a.eval(m_ir);
const auto data1 = b.eval(m_ir);
const auto data2 = c.eval(m_ir);
#if LLVM_VERSION_MAJOR >= 22
// LLVM 22+ changed the intrinsic signature from v4i32 to v16i8 for operands 2 and 3
result.value = m_ir->CreateCall(get_intrinsic(llvm::Intrinsic::x86_avx512_vpdpbusd_128),
{data0, m_ir->CreateBitCast(data1, get_type<u8[16]>()), m_ir->CreateBitCast(data2, get_type<u8[16]>())});
#else
result.value = m_ir->CreateCall(get_intrinsic(llvm::Intrinsic::x86_avx512_vpdpbusd_128), {data0, data1, data2});
#endif
return result;
}

View file

@ -919,7 +919,7 @@ error_code cellCameraGetAttribute(s32 dev_num, s32 attrib, vm::ptr<u32> arg1, vm
if (!check_dev_num(dev_num))
{
return CELL_CAMERA_ERROR_PARAM;
return { CELL_CAMERA_ERROR_PARAM, "dev_num=%d", dev_num };
}
if (g_cfg.io.camera == camera_handler::null)
@ -935,7 +935,7 @@ error_code cellCameraGetAttribute(s32 dev_num, s32 attrib, vm::ptr<u32> arg1, vm
if (!arg1)
{
return CELL_CAMERA_ERROR_PARAM;
return { CELL_CAMERA_ERROR_PARAM, "arg1=null" };
}
if (error_code error = check_resolution(dev_num))
@ -952,7 +952,7 @@ error_code cellCameraGetAttribute(s32 dev_num, s32 attrib, vm::ptr<u32> arg1, vm
if (!attr_name) // invalid attributes don't have a name
{
return CELL_CAMERA_ERROR_PARAM;
return { CELL_CAMERA_ERROR_PARAM, "attrib=0x%x", attrib };
}
if (arg1)
@ -983,7 +983,7 @@ error_code cellCameraSetAttribute(s32 dev_num, s32 attrib, u32 arg1, u32 arg2)
if (!check_dev_num(dev_num))
{
return CELL_CAMERA_ERROR_PARAM;
return { CELL_CAMERA_ERROR_PARAM, "dev_num=%d", dev_num };
}
if (g_cfg.io.camera == camera_handler::null)
@ -1004,7 +1004,7 @@ error_code cellCameraSetAttribute(s32 dev_num, s32 attrib, u32 arg1, u32 arg2)
if (!attr_name) // invalid attributes don't have a name
{
return CELL_CAMERA_ERROR_PARAM;
return { CELL_CAMERA_ERROR_PARAM, "attrib=0x%x", attrib };
}
g_camera.set_attr(attrib, arg1, arg2);

View file

@ -169,18 +169,18 @@ public:
static const u32 id_count = 1023;
SAVESTATE_INIT_POS(34);
ElementaryStream(Demuxer* dmux, u32 addr, u32 size, u32 fidMajor, u32 fidMinor, u32 sup1, u32 sup2, vm::ptr<CellDmuxCbEsMsg> cbFunc, u32 cbArg, u32 spec);
ElementaryStream(Demuxer* dmux, vm::ptr<void> addr, u32 size, u32 fidMajor, u32 fidMinor, u32 sup1, u32 sup2, vm::ptr<CellDmuxCbEsMsg> cbFunc, vm::ptr<void> cbArg, u32 spec);
Demuxer* dmux;
const u32 id = idm::last_id();
const u32 memAddr;
const vm::ptr<void> memAddr;
const u32 memSize;
const u32 fidMajor;
const u32 fidMinor;
const u32 sup1;
const u32 sup2;
const vm::ptr<CellDmuxCbEsMsg> cbFunc;
const u32 cbArg;
const vm::ptr<void> cbArg;
const u32 spec; //addr
std::vector<u8> raw_data; // demultiplexed data stream (managed by demuxer thread)
@ -208,13 +208,13 @@ public:
const u32 memAddr;
const u32 memSize;
const vm::ptr<CellDmuxCbMsg> cbFunc;
const u32 cbArg;
const vm::ptr<void> cbArg;
volatile bool is_finished = false;
volatile bool is_closed = false;
atomic_t<bool> is_running = false;
atomic_t<bool> is_working = false;
Demuxer(u32 addr, u32 size, vm::ptr<CellDmuxCbMsg> func, u32 arg)
Demuxer(u32 addr, u32 size, vm::ptr<CellDmuxCbMsg> func, vm::ptr<void> arg)
: ppu_thread({}, "", 0)
, memAddr(addr)
, memSize(size)
@ -755,11 +755,11 @@ PesHeader::PesHeader(DemuxerStream& stream)
is_ok = true;
}
ElementaryStream::ElementaryStream(Demuxer* dmux, u32 addr, u32 size, u32 fidMajor, u32 fidMinor, u32 sup1, u32 sup2, vm::ptr<CellDmuxCbEsMsg> cbFunc, u32 cbArg, u32 spec)
: put(utils::align(addr, 128))
ElementaryStream::ElementaryStream(Demuxer* dmux, vm::ptr<void> addr, u32 size, u32 fidMajor, u32 fidMinor, u32 sup1, u32 sup2, vm::ptr<CellDmuxCbEsMsg> cbFunc, vm::ptr<void> cbArg, u32 spec)
: put(utils::align(addr.addr(), 128))
, dmux(dmux)
, memAddr(utils::align(addr, 128))
, memSize(size - (addr - memAddr))
, memAddr(vm::ptr<void>::make(utils::align(addr.addr(), 128)))
, memSize(size - (addr.addr() - memAddr.addr()))
, fidMajor(fidMajor)
, fidMinor(fidMinor)
, sup1(sup1)
@ -788,9 +788,9 @@ bool ElementaryStream::is_full(u32 space)
{
return first - put < space + 128;
}
else if (put + space + 128 > memAddr + memSize)
else if (put + space + 128 > memAddr.addr() + memSize)
{
return first - memAddr < space + 128;
return first - memAddr.addr() < space + 128;
}
else
{
@ -816,35 +816,35 @@ void ElementaryStream::push_au(u32 size, u64 dts, u64 pts, u64 userdata, bool ra
std::lock_guard lock(m_mutex);
ensure(!is_full(size));
if (put + size + 128 > memAddr + memSize)
if (put + size + 128 > memAddr.addr() + memSize)
{
put = memAddr;
put = memAddr.addr();
}
std::memcpy(vm::base(put + 128), raw_data.data(), size);
raw_data.erase(raw_data.begin(), raw_data.begin() + size);
auto info = vm::ptr<CellDmuxAuInfoEx>::make(put);
info->auAddr = put + 128;
info->auAddr.set(put + 128);
info->auSize = size;
info->dts.lower = static_cast<u32>(dts);
info->dts.upper = static_cast<u32>(dts >> 32);
info->pts.lower = static_cast<u32>(pts);
info->pts.upper = static_cast<u32>(pts >> 32);
info->isRap = rap;
info->reserved = 0;
info->auMaxSize = 0;
info->userData = userdata;
auto spec = vm::ptr<u32>::make(put + u32{sizeof(CellDmuxAuInfoEx)});
*spec = specific;
auto inf = vm::ptr<CellDmuxAuInfo>::make(put + 64);
inf->auAddr = put + 128;
inf->auAddr.set(put + 128);
inf->auSize = size;
inf->dtsLower = static_cast<u32>(dts);
inf->dtsUpper = static_cast<u32>(dts >> 32);
inf->ptsLower = static_cast<u32>(pts);
inf->ptsUpper = static_cast<u32>(pts >> 32);
inf->dts.lower = static_cast<u32>(dts);
inf->dts.upper = static_cast<u32>(dts >> 32);
inf->pts.lower = static_cast<u32>(pts);
inf->pts.upper = static_cast<u32>(pts >> 32);
inf->auMaxSize = 0; // ?????
inf->userData = userdata;
@ -927,7 +927,7 @@ bool ElementaryStream::peek(u32& out_data, bool no_ex, u32& out_spec, bool updat
void ElementaryStream::reset()
{
std::lock_guard lock(m_mutex);
put = memAddr;
put = memAddr.addr();
entries.clear();
put_count = 0;
got_count = 0;

View file

@ -33,118 +33,6 @@ enum CellDmuxEsMsgType : s32
CELL_DMUX_ES_MSG_TYPE_FLUSH_DONE = 1,
};
enum CellDmuxPamfM2vLevel : s32
{
CELL_DMUX_PAMF_M2V_MP_LL = 0,
CELL_DMUX_PAMF_M2V_MP_ML,
CELL_DMUX_PAMF_M2V_MP_H14,
CELL_DMUX_PAMF_M2V_MP_HL,
};
enum CellDmuxPamfAvcLevel : s32
{
CELL_DMUX_PAMF_AVC_LEVEL_2P1 = 21,
CELL_DMUX_PAMF_AVC_LEVEL_3P0 = 30,
CELL_DMUX_PAMF_AVC_LEVEL_3P1 = 31,
CELL_DMUX_PAMF_AVC_LEVEL_3P2 = 32,
CELL_DMUX_PAMF_AVC_LEVEL_4P1 = 41,
CELL_DMUX_PAMF_AVC_LEVEL_4P2 = 42,
};
struct CellDmuxPamfAuSpecificInfoM2v
{
be_t<u32> reserved1;
};
struct CellDmuxPamfAuSpecificInfoAvc
{
be_t<u32> reserved1;
};
struct CellDmuxPamfAuSpecificInfoLpcm
{
u8 channelAssignmentInfo;
u8 samplingFreqInfo;
u8 bitsPerSample;
};
struct CellDmuxPamfAuSpecificInfoAc3
{
be_t<u32> reserved1;
};
struct CellDmuxPamfAuSpecificInfoAtrac3plus
{
be_t<u32> reserved1;
};
struct CellDmuxPamfAuSpecificInfoUserData
{
be_t<u32> reserved1;
};
struct CellDmuxPamfEsSpecificInfoM2v
{
be_t<u32> profileLevel;
};
struct CellDmuxPamfEsSpecificInfoAvc
{
be_t<u32> level;
};
struct CellDmuxPamfEsSpecificInfoLpcm
{
be_t<u32> samplingFreq;
be_t<u32> numOfChannels;
be_t<u32> bitsPerSample;
};
struct CellDmuxPamfEsSpecificInfoAc3
{
be_t<u32> reserved1;
};
struct CellDmuxPamfEsSpecificInfoAtrac3plus
{
be_t<u32> reserved1;
};
struct CellDmuxPamfEsSpecificInfoUserData
{
be_t<u32> reserved1;
};
enum CellDmuxPamfSamplingFrequency : s32
{
CELL_DMUX_PAMF_FS_48K = 48000,
};
enum CellDmuxPamfBitsPerSample : s32
{
CELL_DMUX_PAMF_BITS_PER_SAMPLE_16 = 16,
CELL_DMUX_PAMF_BITS_PER_SAMPLE_24 = 24,
};
enum CellDmuxPamfLpcmChannelAssignmentInfo : s32
{
CELL_DMUX_PAMF_LPCM_CH_M1 = 1,
CELL_DMUX_PAMF_LPCM_CH_LR = 3,
CELL_DMUX_PAMF_LPCM_CH_LRCLSRSLFE = 9,
CELL_DMUX_PAMF_LPCM_CH_LRCLSCS1CS2RSLFE = 11,
};
enum CellDmuxPamfLpcmFs : s32
{
CELL_DMUX_PAMF_LPCM_FS_48K = 1,
};
enum CellDmuxPamfLpcmBitsPerSamples : s32
{
CELL_DMUX_PAMF_LPCM_BITS_PER_SAMPLE_16 = 1,
CELL_DMUX_PAMF_LPCM_BITS_PER_SAMPLE_24 = 3,
};
struct CellDmuxMsg
{
be_t<s32> msgType; // CellDmuxMsgType
@ -163,12 +51,6 @@ struct CellDmuxType
be_t<u32> reserved[2];
};
struct CellDmuxPamfSpecificInfo
{
be_t<u32> thisSize;
b8 programEndCodeCb;
};
struct CellDmuxType2
{
be_t<s32> streamType; // CellDmuxStreamType
@ -177,7 +59,7 @@ struct CellDmuxType2
struct CellDmuxResource
{
be_t<u32> memAddr;
vm::bptr<void> memAddr;
be_t<u32> memSize;
be_t<u32> ppuThreadPriority;
be_t<u32> ppuThreadStackSize;
@ -187,7 +69,7 @@ struct CellDmuxResource
struct CellDmuxResourceEx
{
be_t<u32> memAddr;
vm::bptr<void> memAddr;
be_t<u32> memSize;
be_t<u32> ppuThreadPriority;
be_t<u32> ppuThreadStackSize;
@ -227,16 +109,16 @@ struct CellDmuxResource2
be_t<u32> shit[4];
};
using CellDmuxCbMsg = u32(u32 demuxerHandle, vm::ptr<CellDmuxMsg> demuxerMsg, u32 cbArg);
using CellDmuxCbMsg = u32(u32 demuxerHandle, vm::cptr<CellDmuxMsg> demuxerMsg, vm::ptr<void> cbArg);
using CellDmuxCbEsMsg = u32(u32 demuxerHandle, u32 esHandle, vm::ptr<CellDmuxEsMsg> esMsg, u32 cbArg);
using CellDmuxCbEsMsg = u32(u32 demuxerHandle, u32 esHandle, vm::cptr<CellDmuxEsMsg> esMsg, vm::ptr<void> cbArg);
// Used for internal callbacks as well
template <typename F>
struct DmuxCb
{
vm::bptr<F> cbFunc;
be_t<u32> cbArg;
vm::bptr<void> cbArg;
};
using CellDmuxCb = DmuxCb<CellDmuxCbMsg>;
@ -250,42 +132,50 @@ struct CellDmuxAttr
be_t<u32> demuxerVerLower;
};
struct CellDmuxPamfAttr
{
be_t<u32> maxEnabledEsNum;
be_t<u32> version;
be_t<u32> memSize;
};
struct CellDmuxEsAttr
{
be_t<u32> memSize;
};
struct CellDmuxPamfEsAttr
{
be_t<u32> auQueueMaxSize;
be_t<u32> memSize;
be_t<u32> specificInfoSize;
};
struct CellDmuxEsResource
{
be_t<u32> memAddr;
vm::bptr<void> memAddr;
be_t<u32> memSize;
};
struct CellDmuxAuInfo
{
be_t<u32> auAddr;
vm::bptr<void> auAddr;
be_t<u32> auSize;
be_t<u32> auMaxSize;
be_t<u64> userData;
be_t<u32> ptsUpper;
be_t<u32> ptsLower;
be_t<u32> dtsUpper;
be_t<u32> dtsLower;
};
struct CellDmuxAuInfoEx
{
be_t<u32> auAddr;
be_t<u32> auSize;
be_t<u32> reserved;
b8 isRap;
be_t<u64> userData;
CellCodecTimeStamp pts;
CellCodecTimeStamp dts;
};
struct CellDmuxPamfAttr;
struct CellDmuxPamfEsAttr;
using CellDmuxAuInfoEx = CellDmuxAuInfo;
struct DmuxAuInfo
{
CellDmuxAuInfo info;
vm::bptr<void> specific_info;
be_t<u32> specific_info_size;
};
using DmuxNotifyDemuxDone = error_code(vm::ptr<void>, u32, vm::ptr<void>);
using DmuxNotifyFatalErr = error_code(vm::ptr<void>, u32, vm::ptr<void>);
@ -301,7 +191,7 @@ using CellDmuxCoreOpResetStream = error_code(vm::ptr<void>);
using CellDmuxCoreOpCreateThread = error_code(vm::ptr<void>);
using CellDmuxCoreOpJoinThread = error_code(vm::ptr<void>);
using CellDmuxCoreOpSetStream = error_code(vm::ptr<void>, vm::cptr<void>, u32, b8, u64);
using CellDmuxCoreOpFreeMemory = error_code(vm::ptr<void>, vm::ptr<void>, u32);
using CellDmuxCoreOpReleaseAu = error_code(vm::ptr<void>, vm::ptr<void>, u32);
using CellDmuxCoreOpQueryEsAttr = error_code(vm::cptr<void>, vm::cptr<void>, vm::ptr<CellDmuxPamfEsAttr>);
using CellDmuxCoreOpEnableEs = error_code(vm::ptr<void>, vm::cptr<void>, vm::cptr<CellDmuxEsResource>, vm::cptr<DmuxCb<DmuxEsNotifyAuFound>>, vm::cptr<DmuxCb<DmuxEsNotifyFlushDone>>, vm::cptr<void>, vm::pptr<void>);
using CellDmuxCoreOpDisableEs = u32(vm::ptr<void>);
@ -318,7 +208,7 @@ struct CellDmuxCoreOps
vm::bptr<CellDmuxCoreOpCreateThread> createThread;
vm::bptr<CellDmuxCoreOpJoinThread> joinThread;
vm::bptr<CellDmuxCoreOpSetStream> setStream;
vm::bptr<CellDmuxCoreOpFreeMemory> freeMemory;
vm::bptr<CellDmuxCoreOpReleaseAu> releaseAu;
vm::bptr<CellDmuxCoreOpQueryEsAttr> queryEsAttr;
vm::bptr<CellDmuxCoreOpEnableEs> enableEs;
vm::bptr<CellDmuxCoreOpDisableEs> disableEs;

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -770,8 +770,8 @@ namespace gem
if constexpr (use_gain)
{
dst0[0] = static_cast<u8>(std::clamp(r * gain_r, 0.0f, 255.0f));
dst0[1] = static_cast<u8>(std::clamp(b * gain_b, 0.0f, 255.0f));
dst0[2] = static_cast<u8>(std::clamp(g * gain_g, 0.0f, 255.0f));
dst0[1] = static_cast<u8>(std::clamp(g * gain_g, 0.0f, 255.0f));
dst0[2] = static_cast<u8>(std::clamp(b * gain_b, 0.0f, 255.0f));
}
else
{
@ -822,8 +822,8 @@ namespace gem
if constexpr (use_gain)
{
dst0[0] = static_cast<u8>(std::clamp(r * gain_r, 0.0f, 255.0f));
dst0[1] = static_cast<u8>(std::clamp(b * gain_b, 0.0f, 255.0f));
dst0[2] = static_cast<u8>(std::clamp(g * gain_g, 0.0f, 255.0f));
dst0[1] = static_cast<u8>(std::clamp(g * gain_g, 0.0f, 255.0f));
dst0[2] = static_cast<u8>(std::clamp(b * gain_b, 0.0f, 255.0f));
}
else
{
@ -845,6 +845,53 @@ namespace gem
debayer_raw8_impl<false>(src, dst, alpha, gain_r, gain_g, gain_b);
}
template <bool use_gain>
static inline void debayer_raw8_downscale_impl(const u8* src, u8* dst, u8 alpha, f32 gain_r, f32 gain_g, f32 gain_b)
{
constexpr u32 in_pitch = 640;
constexpr u32 out_pitch = 320 * 4;
// Simple debayer
for (s32 y = 0; y < 240; y++)
{
const u8* src0 = src + y * 2 * in_pitch;
const u8* src1 = src0 + in_pitch;
u8* dst0 = dst + y * out_pitch;
for (s32 x = 0; x < 320; x++, dst0 += 4, src0 += 2, src1 += 2)
{
const u8 b = src0[0];
const u8 g0 = src0[1];
const u8 g1 = src1[0];
const u8 r = src1[1];
const u8 g = (g0 + g1) >> 1;
if constexpr (use_gain)
{
dst0[0] = static_cast<u8>(std::clamp(r * gain_r, 0.0f, 255.0f));
dst0[1] = static_cast<u8>(std::clamp(g * gain_g, 0.0f, 255.0f));
dst0[2] = static_cast<u8>(std::clamp(b * gain_b, 0.0f, 255.0f));
}
else
{
dst0[0] = r;
dst0[1] = g;
dst0[2] = b;
}
dst0[3] = alpha;
}
}
}
static void debayer_raw8_downscale(const u8* src, u8* dst, u8 alpha, f32 gain_r, f32 gain_g, f32 gain_b)
{
if (gain_r != 1.0f || gain_g != 1.0f || gain_b != 1.0f)
debayer_raw8_downscale_impl<true>(src, dst, alpha, gain_r, gain_g, gain_b);
else
debayer_raw8_downscale_impl<false>(src, dst, alpha, gain_r, gain_g, gain_b);
}
bool convert_image_format(CellCameraFormat input_format, const CellGemVideoConvertAttribute& vc,
const std::vector<u8>& video_data_in, u32 width, u32 height,
u8* video_data_out, u32 video_data_out_size, u8* buffer_memory,
@ -881,9 +928,9 @@ namespace gem
const u8* src_data = video_data_in.data();
const u8 alpha = vc.alpha;
const f32 gain_r = vc.gain * vc.blue_gain;
const f32 gain_r = vc.gain * vc.red_gain;
const f32 gain_g = vc.gain * vc.green_gain;
const f32 gain_b = vc.gain * vc.red_gain;
const f32 gain_b = vc.gain * vc.blue_gain;
// Only RAW8 should be relevant for cellGem unless I'm mistaken
if (input_format == CELL_CAMERA_RAW8)
@ -1183,34 +1230,7 @@ namespace gem
{
case CELL_CAMERA_RAW8:
{
const u32 in_pitch = width;
const u32 out_pitch = width * 4 / 2;
for (u32 y = 0; y < height - 1; y += 2)
{
const u8* src0 = src_data + y * in_pitch;
const u8* src1 = src0 + in_pitch;
u8* dst0 = video_data_out + (y / 2) * out_pitch;
u8* dst1 = dst0 + out_pitch;
for (u32 x = 0; x < width - 1; x += 2, src0 += 2, src1 += 2, dst0 += 4, dst1 += 4)
{
const u8 b = src0[0];
const u8 g0 = src0[1];
const u8 g1 = src1[0];
const u8 r = src1[1];
const u8 top[4] = { r, g0, b, alpha };
const u8 bottom[4] = { r, g1, b, alpha };
// Top-Left
std::memcpy(dst0, top, 4);
// Bottom-Left Pixel
std::memcpy(dst1, bottom, 4);
}
}
debayer_raw8_downscale(src_data, video_data_out, alpha, gain_r, gain_g, gain_b);
break;
}
case CELL_CAMERA_RGBA:
@ -1609,13 +1629,8 @@ public:
return false;
}
if (!m_camera_info.bytesize)
{
cellGem.error("gem_tracker: unexpected image size: %d", m_camera_info.bytesize);
return false;
}
m_tracker.set_image_data(m_camera_info.buffer.get_ptr(), m_camera_info.bytesize, m_camera_info.width, m_camera_info.height, m_camera_info.format);
m_framenumber++; // using framenumber instead of timestamp since the timestamp could be identical
return true;
}
@ -1648,6 +1663,7 @@ public:
}
auto& gem = g_fxo->get<gem_config>();
u64 last_framenumber = 0;
while (thread_ctrl::state() != thread_state::aborting)
{
@ -1663,6 +1679,13 @@ public:
}
}
if (std::exchange(last_framenumber, m_framenumber.load()) == last_framenumber)
{
cellGem.warning("Tracker woke up without new frame. Skipping processing (framenumber=%d)", last_framenumber);
tracker_done();
continue;
}
m_busy.release(true);
// Update PS Move LED colors
@ -1754,6 +1777,7 @@ public:
private:
atomic_t<u32> m_wake_up_tracker = 0;
atomic_t<u32> m_tracker_done = 0;
atomic_t<u64> m_framenumber = 0;
atomic_t<bool> m_busy = false;
ps_move_tracker<false> m_tracker{};
CellCameraInfoEx m_camera_info{};
@ -1873,21 +1897,10 @@ static inline void pos_to_gem_state(u32 gem_num, gem_config::gem_controller& con
gem_state->pos[2] = controller.distance_mm;
gem_state->pos[3] = 0.f;
// TODO: calculate handle position based on our world coordinate and the angles
gem_state->handle_pos[0] = camera_x;
gem_state->handle_pos[1] = camera_y;
gem_state->handle_pos[2] = controller.distance_mm + 10.0f;
gem_state->handle_pos[3] = 0.f;
// Calculate orientation
if (g_cfg.io.move == move_handler::real || (g_cfg.io.move == move_handler::fake && move_data.orientation_enabled))
{
gem_state->quat[0] = move_data.quaternion.x();
gem_state->quat[1] = move_data.quaternion.y();
gem_state->quat[2] = move_data.quaternion.z();
gem_state->quat[3] = move_data.quaternion.w();
}
else
ps_move_data::vect<4> quat = move_data.quaternion;
if (g_cfg.io.move != move_handler::real && !(g_cfg.io.move == move_handler::fake && move_data.orientation_enabled))
{
const f32 max_angle_per_side_h = g_cfg.io.fake_move_rotation_cone_h / 2.0f;
const f32 max_angle_per_side_v = g_cfg.io.fake_move_rotation_cone_v / 2.0f;
@ -1901,17 +1914,27 @@ static inline void pos_to_gem_state(u32 gem_num, gem_config::gem_controller& con
const f32 cy = std::cos(yaw * 0.5f);
const f32 sy = std::sin(yaw * 0.5f);
const f32 q_x = sr * cp * cy - cr * sp * sy;
const f32 q_y = cr * sp * cy + sr * cp * sy;
const f32 q_z = cr * cp * sy - sr * sp * cy;
const f32 q_w = cr * cp * cy + sr * sp * sy;
gem_state->quat[0] = q_x;
gem_state->quat[1] = q_y;
gem_state->quat[2] = q_z;
gem_state->quat[3] = q_w;
quat.x() = sr * cp * cy - cr * sp * sy;
quat.y() = cr * sp * cy + sr * cp * sy;
quat.z() = cr * cp * sy - sr * sp * cy;
quat.w() = cr * cp * cy + sr * sp * sy;
}
gem_state->quat[0] = quat.x();
gem_state->quat[1] = quat.y();
gem_state->quat[2] = quat.z();
gem_state->quat[3] = quat.w();
// Calculate handle position based on our world coordinate and the current orientation
constexpr ps_move_data::vect<3> offset_local_mm({0.f, 0.f, -45.f}); // handle is ~45 mm below sphere
const ps_move_data::vect<3> offset_world = ps_move_data::rotate_vector(quat, offset_local_mm);
gem_state->handle_pos[0] = gem_state->pos[0] - offset_world.x(); // Flip x offset
gem_state->handle_pos[1] = gem_state->pos[1] - offset_world.y(); // Flip y offset
gem_state->handle_pos[2] = gem_state->pos[2] + offset_world.z();
gem_state->handle_pos[3] = 0.f;
// Calculate velocity
if constexpr (!ps_move_data::use_imu_for_velocity)
{
move_data.update_velocity(shared_data.frame_timestamp_us, gem_state->pos);
@ -1920,6 +1943,10 @@ static inline void pos_to_gem_state(u32 gem_num, gem_config::gem_controller& con
{
gem_state->vel[i] = move_data.vel_world[i];
gem_state->accel[i] = move_data.accel_world[i];
// TODO: maybe this also needs to be adjusted depending on the orientation
gem_state->handle_vel[i] = gem_state->vel[i];
gem_state->handle_accel[i] = gem_state->accel[i];
}
}
@ -3612,7 +3639,7 @@ error_code cellGemReadExternalPortDeviceInfo(u32 gem_num, vm::ptr<u32> ext_id, v
if (!pad->move_data.external_device_read_requested)
{
*ext_id = controller.ext_id = pad->move_data.external_device_id;
std::memcpy(pad->move_data.external_device_read.data(), ext_info.get_ptr(), CELL_GEM_EXTERNAL_PORT_OUTPUT_SIZE);
std::memcpy(ext_info.get_ptr(), pad->move_data.external_device_read.data(), CELL_GEM_EXTERNAL_PORT_DEVICE_INFO_SIZE);
break;
}
}
@ -3876,13 +3903,15 @@ error_code cellGemUpdateStart(vm::cptr<void> camera_frame, u64 timestamp)
gem.camera_frame = camera_frame.addr();
if (!tracker.set_image(gem.camera_frame))
const bool image_set = tracker.set_image(gem.camera_frame);
tracker.wake_up_tracker();
if (!image_set)
{
return not_an_error(CELL_GEM_NO_VIDEO);
}
tracker.wake_up_tracker();
return CELL_OK;
}

View file

@ -1,5 +1,6 @@
#pragma once
#include "Emu/Cell/ErrorCodes.h"
#include "Emu/Memory/vm_ptr.h"
// Error Codes

View file

@ -2535,7 +2535,7 @@ bool ppu_module<lv2_obj>::analyse(u32 lib_toc, u32 entry, const u32 sec_end, con
// SLDI mnemonic
reg_state_t rs = get_reg(op.rs);
if (!rs.shift_left(op.sh32, reg_tag_allocator))
if (!rs.shift_left(sh, reg_tag_allocator))
{
unmap_reg(op.ra);
}

View file

@ -1004,7 +1004,7 @@ static import_result_t ppu_load_imports(const ppu_module<lv2_obj>& _module, std:
// Check address
// TODO: The address of use should be extracted from analyser instead
if (fstub && fstub >= _module.segs[0].addr && fstub <= _module.segs[0].addr + _module.segs[0].size)
if (fstub && fstub >= _module.segs[0].addr && fstub < _module.segs[0].addr + _module.segs[0].size)
{
nid_to_use_addr.emplace(fnid, fstub);
}
@ -1895,7 +1895,7 @@ shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, bool virtual_load, c
}
else
{
ppu_loader.error("Library %s: PRX library info not found");
ppu_loader.error("Library: PRX library info not found");
}
prx->start.set(prx->specials[0xbc9a0086]);
@ -3192,7 +3192,7 @@ bool ppu_load_rel_exec(const ppu_rel_object& elf)
for (const auto& s : elf.shdrs)
{
if (s.sh_type != sec_type::sht_progbits)
if (s.sh_type == sec_type::sht_progbits)
{
memsize = utils::align<u32>(memsize + vm::cast(s.sh_size), 128);
}

View file

@ -3867,12 +3867,12 @@ extern void ppu_precompile(std::vector<std::string>& dir_queue, std::vector<ppu_
if (mself.read(hdr) && hdr.get_count(mself.size()))
{
std::set<u64> offs;
for (u32 j = 0; j < hdr.count; j++)
{
mself_record rec{};
std::set<u64> offs;
if (mself.read(rec) && rec.get_pos(mself.size()))
{
if (rec.size <= 0x20)

View file

@ -550,11 +550,12 @@ void PPUTranslator::CallFunction(u64 target, Value* indirect)
else if (_target >= caddr && _target <= cend)
{
u32 target_last = static_cast<u32>(_target);
std::unordered_set<u32> passed_targets{target_last};
// Try to follow unconditional branches as long as there is no infinite loop
while (target_last != _target)
// !! Triggers compilation issues in Asura's Wrath in other parts of the code
// !! See https://github.com/RPCS3/rpcs3/issues/18287
while (false)
{
const ppu_opcode_t op{*ensure(m_info.get_ptr<u32>(target_last))};
const ppu_itype::type itype = g_ppu_itype.decode(op.opcode);
@ -1304,7 +1305,7 @@ void PPUTranslator::VMADDFP(ppu_opcode_t op)
if (!m_use_fma && data == v128{})
{
set_vr(op.vd, vec_handle_result(a * c + fsplat<f32[4]>(0.f)));
ppu_log.notice("LLVM: VMADDFP with -0 addend at [0x%08x]", m_addr + (m_reloc ? m_reloc->addr : 0));
ppu_log.notice("LLVM: VMADDFP with +0 addend at [0x%08x]", m_addr + (m_reloc ? m_reloc->addr : 0));
return;
}
}
@ -3680,9 +3681,7 @@ void PPUTranslator::STVLX(ppu_opcode_t op)
const auto addr = op.ra ? m_ir->CreateAdd(GetGpr(op.ra), GetGpr(op.rb)) : GetGpr(op.rb);
const auto data = pshufb(get_vr<u8[16]>(op.vs), build<u8[16]>(127, 126, 125, 124, 123, 122, 121, 120, 119, 118, 117, 116, 115, 114, 113, 112) + vsplat<u8[16]>(trunc<u8>(value<u64>(addr) & 0xf)));
const auto mask = bitcast<bool[16]>(splat<u16>(0xffff) << trunc<u16>(value<u64>(addr) & 0xf));
const auto ptr = value<u8(*)[16]>(GetMemory(m_ir->CreateAnd(addr, ~0xfull)));
const auto align = splat<u32>(16);
eval(llvm_calli<void, decltype(data), decltype(ptr), decltype(align), decltype(mask)>{"llvm.masked.store.v16i8.p0", {data, ptr, align, mask}});
m_ir->CreateMaskedStore(data.eval(m_ir), GetMemory(m_ir->CreateAnd(addr, ~0xfull)), llvm::Align(16), mask.eval(m_ir));
}
void PPUTranslator::STDBRX(ppu_opcode_t op)
@ -3710,9 +3709,7 @@ void PPUTranslator::STVRX(ppu_opcode_t op)
const auto addr = op.ra ? m_ir->CreateAdd(GetGpr(op.ra), GetGpr(op.rb)) : GetGpr(op.rb);
const auto data = pshufb(get_vr<u8[16]>(op.vs), build<u8[16]>(255, 254, 253, 252, 251, 250, 249, 248, 247, 246, 245, 244, 243, 242, 241, 240) + vsplat<u8[16]>(trunc<u8>(value<u64>(addr) & 0xf)));
const auto mask = bitcast<bool[16]>(trunc<u16>(splat<u64>(0xffff) << (value<u64>(addr) & 0xf) >> 16));
const auto ptr = value<u8(*)[16]>(GetMemory(m_ir->CreateAnd(addr, ~0xfull)));
const auto align = splat<u32>(16);
eval(llvm_calli<void, decltype(data), decltype(ptr), decltype(align), decltype(mask)>{"llvm.masked.store.v16i8.p0", {data, ptr, align, mask}});
m_ir->CreateMaskedStore(data.eval(m_ir), GetMemory(m_ir->CreateAnd(addr, ~0xfull)), llvm::Align(16), mask.eval(m_ir));
}
void PPUTranslator::STFSUX(ppu_opcode_t op)

View file

@ -2219,6 +2219,28 @@ void lv2_obj::prepare_for_sleep(cpu_thread& cpu)
cpu_counter::remove(&cpu);
}
ppu_thread* lv2_obj::get_running_ppu(u32 index)
{
usz thread_count = g_cfg.core.ppu_threads;
if (index >= thread_count)
{
return nullptr;
}
auto target = atomic_storage<ppu_thread*>::load(g_ppu);
for (usz cur = 0; target; target = atomic_storage<ppu_thread*>::load(target->next_ppu), cur++)
{
if (cur == index)
{
return target;
}
}
return nullptr;
}
void lv2_obj::notify_all() noexcept
{
for (auto cpu : g_to_notify)

View file

@ -67,7 +67,6 @@ u32 sys_gamepad_ycon_is_gem(vm::ptr<u8> in, vm::ptr<u8> out)
// syscall(621,packet_id,u8 *in,u8 *out) Talk:LV2_Functions_and_Syscalls#Syscall_621_.280x26D.29 gamepad_if usage
u32 sys_gamepad_ycon_if(u8 packet_id, vm::ptr<u8> in, vm::ptr<u8> out)
{
switch (packet_id)
{
case 0:

View file

@ -15,6 +15,18 @@ LOG_CHANNEL(sys_memory);
//
static shared_mutex s_memstats_mtx;
// This struct is for reduced logging repetition
struct last_reported_memory_stats
{
struct inner_body
{
u32 prev_total = umax;
u32 prev_avail = umax;
};
atomic_t<inner_body> body{};
};
lv2_memory_container::lv2_memory_container(u32 size, bool from_idm) noexcept
: size(size)
, id{from_idm ? idm::last_id() : SYS_MEMORY_CONTAINER_ID_INVALID}
@ -313,8 +325,6 @@ error_code sys_memory_get_user_memory_size(cpu_thread& cpu, vm::ptr<sys_memory_i
{
cpu.state += cpu_flag::wait;
sys_memory.warning("sys_memory_get_user_memory_size(mem_info=*0x%x)", mem_info);
// Get "default" memory container
auto& dct = g_fxo->get<lv2_memory_container>();
@ -332,6 +342,22 @@ error_code sys_memory_get_user_memory_size(cpu_thread& cpu, vm::ptr<sys_memory_i
});
}
typename last_reported_memory_stats::inner_body now;
now.prev_total = out.total_user_memory;
now.prev_avail = out.available_user_memory;
now = g_fxo->get<last_reported_memory_stats>().body.exchange(now);
if (now.prev_total != out.total_user_memory || now.prev_avail != out.available_user_memory)
{
// Log on change
sys_memory.warning("sys_memory_get_user_memory_size(mem_info=*0x%x): Avail=0x%x, Total=0x%x", mem_info, out.available_user_memory, out.total_user_memory);
}
else
{
sys_memory.trace("sys_memory_get_user_memory_size(mem_info=*0x%x): Avail=0x%x, Total=0x%x", mem_info, out.available_user_memory, out.total_user_memory);
}
cpu.check_state();
*mem_info = out;
return CELL_OK;

View file

@ -64,7 +64,7 @@ extern const std::map<std::string_view, int> g_prx_list
{ "libddpdec.sprx", 0 },
{ "libdivxdec.sprx", 0 },
{ "libdmux.sprx", 0 },
{ "libdmuxpamf.sprx", 0 },
{ "libdmuxpamf.sprx", 1 },
{ "libdtslbrdec.sprx", 0 },
{ "libfiber.sprx", 0 },
{ "libfont.sprx", 0 },

View file

@ -453,6 +453,7 @@ public:
// Can be called before the actual sleep call in order to move it out of mutex scope
static void prepare_for_sleep(cpu_thread& cpu);
static ppu_thread* get_running_ppu(u32 index);
struct notify_all_t
{

View file

@ -8,6 +8,7 @@ struct GameInfo
std::string path;
std::string icon_path;
std::string movie_path;
std::string audio_path;
std::string name;
std::string serial;

View file

@ -945,17 +945,6 @@ static u8 sdl_to_logitech_g27_pedal(std::map<u64, std::vector<SDL_Joystick*>>& j
return unsigned_avg * 0xFF / 0xFFFF;
}
static inline void set_bit(u8* buf, int bit_num, bool set)
{
const int byte_num = bit_num / 8;
bit_num %= 8;
const u8 mask = 1 << bit_num;
if (set)
buf[byte_num] = buf[byte_num] | mask;
else
buf[byte_num] = buf[byte_num] & (~mask);
}
void usb_device_logitech_g27::transfer_dfex(u32 buf_size, u8* buf, UsbTransfer* transfer)
{
DFEX_data data{};

View file

@ -38,10 +38,7 @@ struct logitech_g27_ffb_slot
logitech_g27_ffb_state state = logitech_g27_ffb_state::inactive;
u64 last_update = 0;
SDL_HapticEffect last_effect {};
// TODO switch to SDL_HapticEffectID when it becomes available in a future SDL release
// Match the return of SDL_CreateHapticEffect for now
int effect_id = -1;
SDL_HapticEffectID effect_id = -1;
};
struct sdl_mapping

View file

@ -24,13 +24,11 @@ std::set<u32> PadHandlerBase::narrow_set(const std::set<u64>& src)
return dst;
}
// Get new multiplied value based on the multiplier
s32 PadHandlerBase::MultipliedInput(s32 raw_value, s32 multiplier)
{
return (multiplier * raw_value) / 100;
}
// Get new scaled value between 0 and range based on its minimum and maximum
f32 PadHandlerBase::ScaledInput(f32 raw_value, f32 minimum, f32 maximum, f32 deadzone, f32 range)
{
if (deadzone > 0 && deadzone > minimum)
@ -46,7 +44,6 @@ f32 PadHandlerBase::ScaledInput(f32 raw_value, f32 minimum, f32 maximum, f32 dea
return range * val;
}
// Get new scaled value between -range and range based on its minimum and maximum
f32 PadHandlerBase::ScaledAxisInput(f32 raw_value, f32 minimum, f32 maximum, f32 deadzone, f32 range)
{
// convert [min, max] to [0, 1]
@ -79,7 +76,6 @@ f32 PadHandlerBase::ScaledAxisInput(f32 raw_value, f32 minimum, f32 maximum, f32
return (2.0f * range * val) - range;
}
// Get normalized trigger value based on the range defined by a threshold
u16 PadHandlerBase::NormalizeTriggerInput(u16 value, u32 threshold) const
{
if (value <= threshold || threshold >= trigger_max)
@ -90,8 +86,6 @@ u16 PadHandlerBase::NormalizeTriggerInput(u16 value, u32 threshold) const
return static_cast<u16>(ScaledInput(static_cast<f32>(value), static_cast<f32>(trigger_min), static_cast<f32>(trigger_max), static_cast<f32>(threshold)));
}
// normalizes a directed input, meaning it will correspond to a single "button" and not an axis with two directions
// the input values must lie in 0+
u16 PadHandlerBase::NormalizeDirectedInput(s32 raw_value, s32 threshold, s32 maximum) const
{
if (threshold >= maximum || maximum <= 0 || raw_value < 0)
@ -114,9 +108,6 @@ u16 PadHandlerBase::NormalizeStickInput(u16 raw_value, s32 threshold, s32 multip
return static_cast<u16>(ScaledInput(static_cast<f32>(scaled_value), 0.0f, static_cast<f32>(thumb_max), static_cast<f32>(threshold)));
}
// This function normalizes stick deadzone based on the DS3's deadzone, which is ~13% (default of anti deadzone)
// X and Y is expected to be in (-255) to 255 range, deadzone should be in terms of thumb stick range
// return is new x and y values in 0-255 range
std::tuple<u16, u16> PadHandlerBase::NormalizeStickDeadzone(s32 inX, s32 inY, u32 deadzone, u32 anti_deadzone) const
{
f32 X = inX / 255.0f;
@ -150,28 +141,21 @@ std::tuple<u16, u16> PadHandlerBase::NormalizeStickDeadzone(s32 inX, s32 inY, u3
return std::tuple<u16, u16>(ConvertAxis(X), ConvertAxis(Y));
}
// get clamped value between 0 and 255
u16 PadHandlerBase::Clamp0To255(f32 input)
{
return static_cast<u16>(std::clamp(input, 0.0f, 255.0f));
}
// get clamped value between 0 and 1023
u16 PadHandlerBase::Clamp0To1023(f32 input)
{
return static_cast<u16>(std::clamp(input, 0.0f, 1023.0f));
}
// input has to be [-1,1]. result will be [0,255]
u16 PadHandlerBase::ConvertAxis(f32 value)
{
return static_cast<u16>((value + 1.0) * (255.0 / 2.0));
}
// The DS3, (and i think xbox controllers) give a 'square-ish' type response, so that the corners will give (almost)max x/y instead of the ~30x30 from a perfect circle
// using a simple scale/sensitivity increase would *work* although it eats a chunk of our usable range in exchange
// this might be the best for now, in practice it seems to push the corners to max of 20x20, with a squircle_factor of ~4000
// This function assumes inX and inY is already in 0-255
void PadHandlerBase::ConvertToSquirclePoint(u16& inX, u16& inY, u32 squircle_factor)
{
if (!squircle_factor)

View file

@ -274,7 +274,7 @@ protected:
// the input values must lie in 0+
u16 NormalizeDirectedInput(s32 raw_value, s32 threshold, s32 maximum) const;
// This function normalizes stick deadzone based on the DS3's deadzone, which is ~13%
// This function normalizes stick deadzone based on the DS3's deadzone, which is ~13% (default of anti deadzone)
// X and Y is expected to be in (-255) to 255 range, deadzone should be in terms of thumb stick range
// return is new x and y values in 0-255 range
std::tuple<u16, u16> NormalizeStickDeadzone(s32 inX, s32 inY, u32 deadzone, u32 anti_deadzone) const;
@ -284,10 +284,10 @@ public:
// Get new multiplied value based on the multiplier
static s32 MultipliedInput(s32 raw_value, s32 multiplier);
// Get new scaled value between 0 and 255 based on its minimum and maximum
// Get new scaled value between 0 and range based on its minimum and maximum
static f32 ScaledInput(f32 raw_value, f32 minimum, f32 maximum, f32 deadzone, f32 range = 255.0f);
// Get new scaled value between -255 and 255 based on its minimum and maximum
// Get new scaled value between -range and range based on its minimum and maximum
static f32 ScaledAxisInput(f32 raw_value, f32 minimum, f32 maximum, f32 deadzone, f32 range = 255.0f);
// get clamped value between 0 and 255
@ -301,7 +301,7 @@ public:
// The DS3, (and i think xbox controllers) give a 'square-ish' type response, so that the corners will give (almost)max x/y instead of the ~30x30 from a perfect circle
// using a simple scale/sensitivity increase would *work* although it eats a chunk of our usable range in exchange
// this might be the best for now, in practice it seems to push the corners to max of 20x20, with a squircle_factor of 8000
// this might be the best for now, in practice it seems to push the corners to max of 20x20, with a squircle_factor of ~4000
// This function assumes inX and inY is already in 0-255
static void ConvertToSquirclePoint(u16& inX, u16& inY, u32 squircle_factor);

View file

@ -24,34 +24,34 @@ void ps_move_data::reset_sensors()
angaccel_world = {};
}
ps_move_data::vect<3> ps_move_data::rotate_vector(const vect<4>& q, const vect<3>& v)
{
const auto cross = [](const vect<3>& a, const vect<3>& b)
{
return vect<3>({
a.y() * b.z() - a.z() * b.y(),
a.z() * b.x() - a.x() * b.z(),
a.x() * b.y() - a.y() * b.x()
});
};
// q = (x, y, z, w)
const vect<3> q_vec({q.x(), q.y(), q.z()});
// t = 2 * cross(q_vec, v)
const vect<3> t = cross(q_vec, v) * 2.0f;
// v' = v + w * t + cross(q_vec, t)
const vect<3> v_prime = v + t * q.w() + cross(q_vec, t);
return v_prime;
}
void ps_move_data::update_orientation(f32 delta_time)
{
if (!delta_time)
return;
// Rotate vector v by quaternion q
const auto rotate_vector = [](const vect<4>& q, const vect<3>& v)
{
const vect<4> qv({0.0f, v.x(), v.y(), v.z()});
const vect<4> q_inv({q.w(), -q.x(), -q.y(), -q.z()});
// t = q * v
vect<4> t;
t.w() = -q.x() * qv.x() - q.y() * qv.y() - q.z() * qv.z();
t.x() = q.w() * qv.x() + q.y() * qv.z() - q.z() * qv.y();
t.y() = q.w() * qv.y() - q.x() * qv.z() + q.z() * qv.x();
t.z() = q.w() * qv.z() + q.x() * qv.y() - q.y() * qv.x();
// r = t * q_inv
vect<4> r;
r.w() = -t.x() * q_inv.x() - t.y() * q_inv.y() - t.z() * q_inv.z();
r.x() = t.w() * q_inv.x() + t.y() * q_inv.z() - t.z() * q_inv.y();
r.y() = t.w() * q_inv.y() - t.x() * q_inv.z() + t.z() * q_inv.x();
r.z() = t.w() * q_inv.z() + t.x() * q_inv.y() - t.y() * q_inv.x();
return vect<3>({r.x(), r.y(), r.z()});
};
if constexpr (use_imu_for_velocity)
{
// Gravity in world frame

View file

@ -15,6 +15,26 @@ struct ps_move_data
template <typename I>
const T& operator[](I i) const { return data[i]; }
vect<Size, T> operator*(f32 s) const
{
vect<Size, T> result = *this;
for (int i = 0; i < Size; ++i)
{
result[i] *= s;
}
return result;
}
vect<Size, T> operator+(const vect<Size, T>& other) const
{
vect<Size, T> result = *this;
for (int i = 0; i < Size; ++i)
{
result[i] += other[i];
}
return result;
}
T x() const requires (Size >= 1) { return data[0]; }
T y() const requires (Size >= 2) { return data[1]; }
T z() const requires (Size >= 3) { return data[2]; }
@ -72,4 +92,7 @@ struct ps_move_data
void reset_sensors();
void update_orientation(f32 delta_time);
void update_velocity(u64 timestamp, be_t<f32> pos_world[4]);
// Rotate vector v by quaternion q
static vect<3> rotate_vector(const vect<4>& q, const vect<3>& v);
};

View file

@ -10,8 +10,7 @@ void cfg_rpcn::load()
{
const std::string path = cfg_rpcn::get_path();
fs::file cfg_file(path, fs::read);
if (cfg_file)
if (fs::file cfg_file(path, fs::read); cfg_file)
{
rpcn_log.notice("Loading RPCN config. Path: %s", path);
from_string(cfg_file.to_string());

View file

@ -4,7 +4,7 @@
struct cfg_rpcn : cfg::node
{
cfg::uint32 version{this, "Version", 1};
cfg::uint32 version{this, "Version", 2};
cfg::string host{this, "Host", "np.rpcs3.net"};
cfg::string npid{this, "NPID", ""};
cfg::string password{this, "Password", ""};

View file

@ -244,7 +244,7 @@ struct copy_unmodified_block_swizzled
}
const u32 size_in_block = padded_width * padded_height * depth * 2;
rsx::simple_array<U> tmp(size_in_block * words_per_block);
rsx::simple_array<U, sizeof(u128)> tmp(size_in_block * words_per_block);
if (words_per_block == 1) [[likely]]
{

View file

@ -9,7 +9,7 @@ namespace rsx
template <typename T>
concept SpanLike = requires(T t)
{
{ t.data() } -> std::convertible_to<void*>;
{ t.data() } -> std::convertible_to<const void*>;
{ t.size_bytes() } -> std::convertible_to<usz>;
};
@ -71,9 +71,10 @@ namespace rsx
return static_cast<T*>(m_ptr);
}
usz size() const
template <Integral T = usz>
T size() const
{
return m_size;
return static_cast<T>(m_size);
}
template<typename T>

View file

@ -340,7 +340,8 @@ namespace gl
void cs_d24x8_to_ssbo::run(gl::command_context& cmd, gl::viewable_image* src, const gl::buffer* dst, u32 out_offset, const coordu& region, const gl::pixel_buffer_layout& layout)
{
const auto row_pitch = region.width;
const auto row_pitch = layout.row_length ? layout.row_length : region.width;
ensure(row_pitch >= region.width);
m_program.uniforms["swap_bytes"] = layout.swap_bytes;
m_program.uniforms["output_pitch"] = row_pitch;
@ -390,14 +391,15 @@ namespace gl
void cs_rgba8_to_ssbo::run(gl::command_context& cmd, gl::viewable_image* src, const gl::buffer* dst, u32 out_offset, const coordu& region, const gl::pixel_buffer_layout& layout)
{
const auto row_pitch = region.width;
const auto row_pitch = layout.row_length ? layout.row_length : region.width;
ensure(row_pitch >= region.width);
m_program.uniforms["swap_bytes"] = layout.swap_bytes;
m_program.uniforms["output_pitch"] = row_pitch;
m_program.uniforms["region_offset"] = color2i(region.x, region.y);
m_program.uniforms["region_size"] = color2i(region.width, region.height);
m_program.uniforms["is_bgra"] = (layout.format == static_cast<GLenum>(gl::texture::format::bgra));
m_program.uniforms["block_width"] = static_cast<u32>(layout.size);
m_program.uniforms["block_width"] = static_cast<u32>(layout.block_size);
auto data_view = src->get_view(rsx::default_remap_vector.with_encoding(GL_REMAP_IDENTITY), gl::image_aspect::color);
@ -441,6 +443,7 @@ namespace gl
{
const u32 bpp = dst->image()->pitch() / dst->image()->width();
const u32 row_length = utils::align(dst_region.width * bpp, std::max<int>(layout.alignment, 1)) / bpp;
ensure(row_length >= dst_region.width);
m_program.uniforms["swap_bytes"] = layout.swap_bytes;
m_program.uniforms["src_pitch"] = row_length;

View file

@ -22,7 +22,7 @@ namespace gl
void* userptr = vm::get_super_ptr(base_address);
m_data = std::make_unique<gl::buffer>();
m_data->create(buffer::target::array, block_size, userptr, buffer::memory_type::userptr, 0);
m_data->create(buffer::target::copy_dst, block_size, userptr, buffer::memory_type::userptr, 0);
m_base_address = base_address;
// Some drivers may reject userptr input for whatever reason. Check that the state is still valid.
@ -77,7 +77,7 @@ namespace gl
{
const auto start_block_address = start & s_dma_block_mask;
const auto end_block_address = (start + length + s_dma_block_size - 1) & s_dma_block_mask;
return utils::address_range32::start_end(start_block_address, end_block_address);
return utils::address_range32::start_length(start_block_address, end_block_address - start_block_address);
}
const dma_block& get_block(u32 start, u32 length)

View file

@ -249,22 +249,23 @@ void GLGSRender::on_init_thread()
// Fallback null texture instead of relying on texture0
{
std::array<u32, 8> pixeldata = { 0, 0, 0, 0, 0, 0, 0, 0 };
const rsx::io_buffer src_buf = std::span<u32>(pixeldata);
// 1D
auto tex1D = std::make_unique<gl::texture>(GL_TEXTURE_1D, 1, 1, 1, 1, 1, GL_RGBA8, RSX_FORMAT_CLASS_COLOR);
tex1D->copy_from(pixeldata.data(), gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
tex1D->copy_from(src_buf, gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
// 2D
auto tex2D = std::make_unique<gl::texture>(GL_TEXTURE_2D, 1, 1, 1, 1, 1, GL_RGBA8, RSX_FORMAT_CLASS_COLOR);
tex2D->copy_from(pixeldata.data(), gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
tex2D->copy_from(src_buf, gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
// 3D
auto tex3D = std::make_unique<gl::texture>(GL_TEXTURE_3D, 1, 1, 1, 1, 1, GL_RGBA8, RSX_FORMAT_CLASS_COLOR);
tex3D->copy_from(pixeldata.data(), gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
tex3D->copy_from(src_buf, gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
// CUBE
auto texCUBE = std::make_unique<gl::texture>(GL_TEXTURE_CUBE_MAP, 1, 1, 1, 1, 1, GL_RGBA8, RSX_FORMAT_CLASS_COLOR);
texCUBE->copy_from(pixeldata.data(), gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
texCUBE->copy_from(src_buf, gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
m_null_textures[GL_TEXTURE_1D] = std::move(tex1D);
m_null_textures[GL_TEXTURE_2D] = std::move(tex2D);
@ -397,6 +398,7 @@ void GLGSRender::on_init_thread()
m_ui_renderer.create();
m_video_output_pass.create();
gl::init_global_texture_resources();
m_gl_texture_cache.initialize();
m_prog_buffer.initialize

View file

@ -223,7 +223,7 @@ namespace gl
gl::texture_view* ui_overlay_renderer::load_simple_image(rsx::overlays::image_info_base* desc, bool temp_resource, u32 owner_uid)
{
auto tex = std::make_unique<gl::texture>(GL_TEXTURE_2D, desc->w, desc->h, 1, 1, 1, GL_RGBA8, RSX_FORMAT_CLASS_COLOR);
tex->copy_from(desc->get_data(), gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
tex->copy_from(desc->as_span(), gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
const GLenum remap[] = { GL_RED, GL_ALPHA, GL_BLUE, GL_GREEN };
auto view = std::make_unique<gl::texture_view>(tex.get(), remap);
@ -308,7 +308,7 @@ namespace gl
const std::vector<u8>& glyph_data = font->get_glyph_data();
auto tex = std::make_unique<gl::texture>(GL_TEXTURE_2D_ARRAY, font_size.width, font_size.height, font_size.depth, 1, 1, GL_R8, RSX_FORMAT_CLASS_COLOR);
tex->copy_from(glyph_data.data(), gl::texture::format::r, gl::texture::type::ubyte, {});
tex->copy_from(std::span<const u8>(glyph_data), gl::texture::format::r, gl::texture::type::ubyte, {});
GLenum remap[] = { GL_RED, GL_RED, GL_RED, GL_RED };
auto view = std::make_unique<gl::texture_view>(tex.get(), remap);
@ -332,7 +332,7 @@ namespace gl
if (dirty)
{
view->image()->copy_from(desc->get_data(), gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
view->image()->copy_from(desc->as_span(), gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
}
return view;
@ -551,7 +551,8 @@ namespace gl
const pixel_buffer_layout& layout)
{
const u32 bpp = dst->image()->pitch() / dst->image()->width();
const u32 row_length = utils::align(dst_region.width * bpp, std::max<int>(layout.alignment, 1)) / bpp;
const u32 aligned_width = utils::align(dst_region.width * bpp, std::max<int>(layout.alignment, 1)) / bpp;
const u32 row_length = layout.row_length ? layout.row_length : aligned_width;
program_handle.uniforms["src_pitch"] = row_length;
program_handle.uniforms["swap_bytes"] = layout.swap_bytes;

View file

@ -132,7 +132,8 @@ gl::texture* GLGSRender::get_present_source(gl::present_surface_info* info, cons
const auto range = utils::address_range32::start_length(info->address, info->pitch * info->height);
m_gl_texture_cache.invalidate_range(cmd, range, rsx::invalidation_cause::read);
flip_image->copy_from(vm::base(info->address), static_cast<gl::texture::format>(expected_format), gl::texture::type::uint_8_8_8_8, unpack_settings);
const rsx::io_buffer read_buf = { vm::base(info->address), range.length() };
flip_image->copy_from(read_buf, static_cast<gl::texture::format>(expected_format), gl::texture::type::uint_8_8_8_8, unpack_settings);
image = flip_image.get();
}
else if (image->get_internal_format() != static_cast<gl::texture::internal_format>(expected_format))
@ -368,7 +369,7 @@ void GLGSRender::flip(const rsx::display_flip_info_t& info)
std::vector<u8> sshot_frame(buffer_height * buffer_width * 4);
glGetError();
tex->copy_to(sshot_frame.data(), gl::texture::format::rgba, gl::texture::type::ubyte, pack_settings);
tex->copy_to(std::span<const u8>(sshot_frame), gl::texture::format::rgba, gl::texture::type::ubyte, pack_settings);
m_sshot_tex.reset();

View file

@ -218,6 +218,9 @@ OPENGL_PROC(PFNGLNAMEDBUFFERDATAEXTPROC, NamedBufferDataEXT);
OPENGL_PROC(PFNGLNAMEDBUFFERSUBDATAPROC, NamedBufferSubData);
OPENGL_PROC(PFNGLNAMEDBUFFERSUBDATAEXTPROC, NamedBufferSubDataEXT);
OPENGL_PROC(PFNGLCLEARNAMEDBUFFERSUBDATAPROC, ClearNamedBufferSubData);
OPENGL_PROC(PFNGLCLEARNAMEDBUFFERSUBDATAEXTPROC, ClearNamedBufferSubDataEXT);
// ARB_shader_image_load_store
OPENGL_PROC(PFNGLBINDIMAGETEXTUREPROC, BindImageTexture);
@ -256,6 +259,7 @@ OPENGL_PROC(PFNGLDELETESYNCPROC, DeleteSync);
// KHR_debug
OPENGL_PROC(PFNGLDEBUGMESSAGECALLBACKPROC, DebugMessageCallback);
OPENGL_PROC(PFNGLOBJECTLABELPROC, ObjectLabel);
// Immutable textures
OPENGL_PROC(PFNGLTEXSTORAGE1DPROC, TexStorage1D);

View file

@ -689,6 +689,8 @@ gl::viewable_image* gl::render_target::get_resolve_target_safe(gl::command_conte
static_cast<GLenum>(get_internal_format()),
format_class()
));
resolve_surface->set_name(fmt::format("MSAA_Resolve_%u@0x%x", resolve_surface->id(), base_addr));
}
return static_cast<gl::viewable_image*>(resolve_surface.get());

View file

@ -160,6 +160,7 @@ struct gl_render_target_traits
std::unique_ptr<gl::render_target> result(new gl::render_target(width_, height_, samples,
static_cast<GLenum>(format.internal_format), RSX_FORMAT_CLASS_COLOR));
result->set_name(fmt::format("RTV_%u@0x%x", result->id(), address));
result->set_aa_mode(antialias);
result->set_native_pitch(static_cast<u32>(width) * get_format_block_size_in_bytes(surface_color_format) * result->samples_x);
result->set_surface_dimensions(static_cast<u16>(width), static_cast<u16>(height), static_cast<u32>(pitch));
@ -203,6 +204,7 @@ struct gl_render_target_traits
std::unique_ptr<gl::render_target> result(new gl::render_target(width_, height_, samples,
static_cast<GLenum>(format.internal_format), rsx::classify_format(surface_depth_format)));
result->set_name(fmt::format("DSV_%u@0x%x", result->id(), address));
result->set_aa_mode(antialias);
result->set_surface_dimensions(static_cast<u16>(width), static_cast<u16>(height), static_cast<u32>(pitch));
result->set_format(surface_depth_format);
@ -238,6 +240,7 @@ struct gl_render_target_traits
sink->state_flags = rsx::surface_state_flags::erase_bkgnd;
sink->format_info = ref->format_info;
sink->set_name(fmt::format("SINK_%u@0x%x", sink->id(), address));
sink->set_spp(ref->get_spp());
sink->set_native_pitch(static_cast<u32>(prev.width) * ref->get_bpp() * ref->samples_x);
sink->set_rsx_pitch(ref->get_rsx_pitch());
@ -325,6 +328,7 @@ struct gl_render_target_traits
std::array<GLenum, 4> native_layout = { static_cast<GLenum>(fmt.swizzle.a), static_cast<GLenum>(fmt.swizzle.r), static_cast<GLenum>(fmt.swizzle.g), static_cast<GLenum>(fmt.swizzle.b) };
surface->set_native_component_layout(native_layout);
surface->set_format(format);
surface->set_name(fmt::format("RTV_%u@0x%x", surface->id(), address));
int_invalidate_surface_contents(cmd, surface, address, pitch);
}
@ -338,6 +342,7 @@ struct gl_render_target_traits
usz pitch)
{
surface->set_format(format);
surface->set_name(fmt::format("DSV_%u@0x%x", surface->id(), address));
int_invalidate_surface_contents(cmd, surface, address, pitch);
}

View file

@ -300,6 +300,7 @@ namespace gl
}
builder << "\n"
"#undef TEX_PARAM\n"
"#define TEX_PARAM(index) texture_parameters[index + texture_base_index]\n"
"#define IS_TEXTURE_RESIDENT(index) (texture_handles[index] < 0xFF)\n"
"#define SAMPLER1D(index) sampler1D_array[texture_handles[index]]\n"

View file

@ -22,6 +22,13 @@ namespace gl
legacy_ring_buffer g_upload_transfer_buffer;
scratch_ring_buffer g_compute_decode_buffer;
scratch_ring_buffer g_deswizzle_scratch_buffer;
blitter g_blitter;
void init_global_texture_resources()
{
g_blitter.init();
g_hw_blitter = &g_blitter;
}
void destroy_global_texture_resources()
{
@ -29,6 +36,8 @@ namespace gl
g_upload_transfer_buffer.remove();
g_compute_decode_buffer.remove();
g_deswizzle_scratch_buffer.remove();
g_blitter.destroy();
g_hw_blitter = nullptr;
}
template <typename WordType, bool SwapBytes>
@ -157,42 +166,42 @@ namespace gl
case texture::internal_format::compressed_rgba_s3tc_dxt1:
case texture::internal_format::compressed_rgba_s3tc_dxt3:
case texture::internal_format::compressed_rgba_s3tc_dxt5:
return { GL_RGBA, GL_UNSIGNED_BYTE, 1, false };
return { .format = GL_RGBA, .type = GL_UNSIGNED_BYTE, .block_size = 1, .swap_bytes = false };
case texture::internal_format::r8:
return { GL_RED, GL_UNSIGNED_BYTE, 1, false };
return { .format = GL_RED, .type = GL_UNSIGNED_BYTE, .block_size = 1, .swap_bytes = false };
case texture::internal_format::r16:
return { GL_RED, GL_UNSIGNED_SHORT, 2, true };
return { .format = GL_RED, .type = GL_UNSIGNED_SHORT, .block_size = 2, .swap_bytes = true };
case texture::internal_format::r32f:
return { GL_RED, GL_FLOAT, 4, true };
return { .format = GL_RED, .type = GL_FLOAT, .block_size = 4, .swap_bytes = true };
case texture::internal_format::rg8:
return { GL_RG, GL_UNSIGNED_SHORT, 2, true };
return { .format = GL_RG, .type = GL_UNSIGNED_SHORT, .block_size = 2, .swap_bytes = true };
case texture::internal_format::rg16:
return { GL_RG, GL_UNSIGNED_SHORT, 2, true };
return { .format = GL_RG, .type = GL_UNSIGNED_SHORT, .block_size = 2, .swap_bytes = true };
case texture::internal_format::rg16f:
return { GL_RG, GL_HALF_FLOAT, 2, true };
return { .format = GL_RG, .type = GL_HALF_FLOAT, .block_size = 2, .swap_bytes = true };
case texture::internal_format::rgb565:
return { GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 2, true };
return { .format = GL_RGB, .type = GL_UNSIGNED_SHORT_5_6_5, .block_size = 2, .swap_bytes = true };
case texture::internal_format::rgb5a1:
return { GL_RGB, GL_UNSIGNED_SHORT_5_5_5_1, 2, true };
return { .format = GL_RGB, .type = GL_UNSIGNED_SHORT_5_5_5_1, .block_size = 2, .swap_bytes = true };
case texture::internal_format::bgr5a1:
return { GL_RGB, GL_UNSIGNED_SHORT_1_5_5_5_REV, 2, true };
return { .format = GL_RGB, .type = GL_UNSIGNED_SHORT_1_5_5_5_REV, .block_size = 2, .swap_bytes = true };
case texture::internal_format::rgba4:
return { GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4, 2, false };
return { .format = GL_BGRA, .type = GL_UNSIGNED_SHORT_4_4_4_4, .block_size = 2, .swap_bytes = false };
case texture::internal_format::rgba8:
return { GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, 4, true };
return { .format = GL_RGBA, .type = GL_UNSIGNED_INT_8_8_8_8_REV, .block_size = 4, .swap_bytes = true };
case texture::internal_format::bgra8:
return { GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, 4, true };
return { .format = GL_BGRA, .type = GL_UNSIGNED_INT_8_8_8_8_REV, .block_size = 4, .swap_bytes = true };
case texture::internal_format::rgba16f:
return { GL_RGBA, GL_HALF_FLOAT, 2, true };
return { .format = GL_RGBA, .type = GL_HALF_FLOAT, .block_size = 2, .swap_bytes = true };
case texture::internal_format::rgba32f:
return { GL_RGBA, GL_FLOAT, 4, true };
return { .format = GL_RGBA, .type = GL_FLOAT, .block_size = 4, .swap_bytes = true };
case texture::internal_format::depth16:
return { GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, 2, true };
return { .format = GL_DEPTH_COMPONENT, .type = GL_UNSIGNED_SHORT, .block_size = 2, .swap_bytes = true };
case texture::internal_format::depth32f:
return { GL_DEPTH_COMPONENT, GL_FLOAT, 2, true };
return { .format = GL_DEPTH_COMPONENT, .type = GL_FLOAT, .block_size = 2, .swap_bytes = true };
case texture::internal_format::depth24_stencil8:
case texture::internal_format::depth32f_stencil8:
return { GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, 4, true };
return { .format = GL_DEPTH_STENCIL, .type = GL_UNSIGNED_INT_24_8, .block_size = 4, .swap_bytes = true };
default:
fmt::throw_exception("Unexpected internal format 0x%X", static_cast<u32>(format));
}
@ -311,7 +320,7 @@ namespace gl
return nullptr;
}
switch (pack_info.size)
switch (pack_info.block_size)
{
case 1:
return nullptr;
@ -363,8 +372,10 @@ namespace gl
}
}
dst->bind(buffer::target::pixel_pack);
src->copy_to(reinterpret_cast<void*>(static_cast<uintptr_t>(dst_offset)), static_cast<texture::format>(pack_info.format), static_cast<texture::type>(pack_info.type), src_level, src_region, {});
pixel_pack_settings pack_settings{};
if (pack_info.alignment) pack_settings.alignment(pack_info.alignment);
if (pack_info.row_length) pack_settings.row_length(pack_info.row_length);
src->copy_to(*dst, dst_offset, static_cast<texture::format>(pack_info.format), static_cast<texture::type>(pack_info.type), src_level, src_region, pack_settings);
return false;
};
@ -611,10 +622,12 @@ namespace gl
}
glBindBuffer(GL_SHADER_STORAGE_BUFFER, GL_NONE);
transfer_buf->bind(buffer::target::pixel_unpack);
dst->copy_from(reinterpret_cast<void*>(u64(out_offset)), static_cast<texture::format>(unpack_info.format),
static_cast<texture::type>(unpack_info.type), dst_level, dst_region, {});
pixel_unpack_settings unpack_settings{};
if (unpack_info.alignment) unpack_settings.alignment(unpack_info.alignment);
if (unpack_info.format) unpack_settings.row_length(unpack_info.row_length);
dst->copy_from(*transfer_buf, out_offset, static_cast<texture::format>(unpack_info.format),
static_cast<texture::type>(unpack_info.type), dst_level, dst_region, unpack_settings);
}
}
@ -712,7 +725,6 @@ namespace gl
pixel_buffer_layout mem_layout;
std::span<std::byte> dst_buffer = staging_buffer;
void* out_pointer = staging_buffer.data();
u8 block_size_in_bytes = rsx::get_format_block_size_in_bytes(format);
u64 image_linear_size = staging_buffer.size();
@ -731,8 +743,6 @@ namespace gl
g_compute_decode_buffer.remove();
g_compute_decode_buffer.create(gl::buffer::target::ssbo, min_required_buffer_size);
}
out_pointer = nullptr;
}
for (const rsx::subresource_layout& layout : input_layouts)
@ -776,7 +786,7 @@ namespace gl
mem_layout.swap_bytes = op.require_swap;
mem_layout.format = gl_format;
mem_layout.type = gl_type;
mem_layout.size = block_size_in_bytes;
mem_layout.block_size = block_size_in_bytes;
// 2. Upload memory to GPU
if (!op.require_deswizzle)
@ -867,7 +877,7 @@ namespace gl
else
{
unpack_settings.swap_bytes(op.require_swap);
dst->copy_from(out_pointer, static_cast<texture::format>(gl_format), static_cast<texture::type>(gl_type), layout.level, region, unpack_settings);
dst->copy_from(staging_buffer, static_cast<texture::format>(gl_format), static_cast<texture::type>(gl_type), layout.level, region, unpack_settings);
}
}
}
@ -1057,7 +1067,7 @@ namespace gl
skip_transform = (pack_info.format == unpack_info.format &&
pack_info.type == unpack_info.type &&
pack_info.swap_bytes == unpack_info.swap_bytes &&
pack_info.size == unpack_info.size);
pack_info.block_size == unpack_info.block_size);
}
if (skip_transform) [[likely]]
@ -1138,7 +1148,7 @@ namespace gl
if (src->aspect() & image_aspect::depth)
{
// Source is depth, modify unpack rule
if (pack_info.size == 4 && unpack_info.size == 4)
if (pack_info.block_size == 4 && unpack_info.block_size == 4)
{
unpack_info.swap_bytes = !unpack_info.swap_bytes;
}
@ -1146,7 +1156,7 @@ namespace gl
else
{
// Dest is depth, modify pack rule
if (pack_info.size == 4 && unpack_info.size == 4)
if (pack_info.block_size == 4 && unpack_info.block_size == 4)
{
pack_info.swap_bytes = !pack_info.swap_bytes;
}
@ -1156,9 +1166,7 @@ namespace gl
// Start pack operation
pixel_pack_settings pack_settings{};
pack_settings.swap_bytes(pack_info.swap_bytes);
g_typeless_transfer_buffer.get().bind(buffer::target::pixel_pack);
src->copy_to(nullptr, static_cast<texture::format>(pack_info.format), static_cast<texture::type>(pack_info.type), 0, src_region, pack_settings);
src->copy_to(g_typeless_transfer_buffer.get(), 0, static_cast<texture::format>(pack_info.format), static_cast<texture::type>(pack_info.type), 0, src_region, pack_settings);
glBindBuffer(GL_PIXEL_PACK_BUFFER, GL_NONE);
@ -1166,8 +1174,7 @@ namespace gl
pixel_unpack_settings unpack_settings{};
unpack_settings.swap_bytes(unpack_info.swap_bytes);
g_typeless_transfer_buffer.get().bind(buffer::target::pixel_unpack);
dst->copy_from(nullptr, static_cast<texture::format>(unpack_info.format), static_cast<texture::type>(unpack_info.type), 0, dst_region, unpack_settings);
dst->copy_from(g_typeless_transfer_buffer.get(), 0, static_cast<texture::format>(unpack_info.format), static_cast<texture::type>(unpack_info.type), 0, dst_region, unpack_settings);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, GL_NONE);
}
}

View file

@ -16,9 +16,11 @@ namespace gl
{
GLenum format;
GLenum type;
u8 size;
u32 row_length;
u8 block_size;
bool swap_bytes;
u8 alignment;
u8 reserved;
};
struct image_memory_requirements
@ -86,5 +88,6 @@ namespace gl
extern std::unique_ptr<texture> g_vis_texture;
}
void init_global_texture_resources();
void destroy_global_texture_resources();
}

View file

@ -152,6 +152,8 @@ namespace gl
dst = data.get();
dst->properties_encoding = match_key;
m_temporary_surfaces.emplace_back(std::move(data));
dst->set_name(fmt::format("[Temp View] id=%u, fmt=0x%x", dst->id(), gcm_format));
}
dst->add_ref();
@ -179,6 +181,10 @@ namespace gl
auto components = get_component_mapping(gcm_format, rsx::component_order::default_);
dst->set_native_component_layout(components);
}
else
{
dst->set_native_component_layout(src->get_native_component_layout());
}
return dst->get_view(remap);
}

View file

@ -48,7 +48,7 @@ namespace gl
void init_buffer(const gl::texture* src)
{
const u32 vram_size = src->pitch() * src->height();
const u32 vram_size = std::max(src->pitch() * src->height(), get_section_size());
const u32 buffer_size = utils::align(vram_size, 4096);
if (pbo)
@ -148,7 +148,7 @@ namespace gl
}
}
void dma_transfer(gl::command_context& cmd, gl::texture* src, const areai& /*src_area*/, const utils::address_range32& /*valid_range*/, u32 pitch)
void dma_transfer(gl::command_context& cmd, gl::texture* src, const areai& src_area, const utils::address_range32& valid_range, u32 pitch)
{
init_buffer(src);
glGetError();
@ -165,6 +165,20 @@ namespace gl
real_pitch = src->pitch();
rsx_pitch = pitch;
const coord3u src_rgn =
{
{ static_cast<u32>(src_area.x1), static_cast<u32>(src_area.y1), 0 },
{ static_cast<u32>(src_area.width()), static_cast<u32>(src_area.height()), 1 }
};
u32 pbo_offset = 0;
if (valid_range.valid())
{
const u32 section_base = get_section_base();
pbo_offset = valid_range.start - section_base;
ensure(valid_range.start >= section_base && pbo_offset <= pbo.size());
}
bool use_driver_pixel_transform = true;
if (get_driver_caps().ARB_compute_shader_supported) [[likely]]
{
@ -180,11 +194,12 @@ namespace gl
pack_info.format = static_cast<GLenum>(format);
pack_info.type = static_cast<GLenum>(type);
pack_info.size = (src->aspect() & image_aspect::stencil) ? 4 : 2;
pack_info.block_size = (src->aspect() & image_aspect::stencil) ? 4 : 2;
pack_info.swap_bytes = true;
pack_info.row_length = rsx_pitch / pack_info.block_size;
mem_info.image_size_in_texels = src->width() * src->height();
mem_info.image_size_in_bytes = src->pitch() * src->height();
mem_info.image_size_in_texels = pack_info.row_length * src_area.height();
mem_info.image_size_in_bytes = rsx_pitch * src_area.height();
mem_info.memory_required = 0;
if (pack_info.type == GL_FLOAT_32_UNSIGNED_INT_24_8_REV)
@ -193,14 +208,16 @@ namespace gl
mem_info.image_size_in_bytes *= 2;
}
void* out_offset = copy_image_to_buffer(cmd, pack_info, src, &scratch_mem, 0, 0, { {}, src->size3D() }, &mem_info);
void* out_offset = copy_image_to_buffer(cmd, pack_info, src, &scratch_mem, 0, 0, src_rgn, &mem_info);
real_pitch = rsx_pitch;
glBindBuffer(GL_SHADER_STORAGE_BUFFER, GL_NONE);
glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
real_pitch = pack_info.size * src->width();
const u64 data_length = pack_info.size * mem_info.image_size_in_texels;
scratch_mem.copy_to(&pbo, reinterpret_cast<u64>(out_offset), 0, data_length);
const u64 data_length = mem_info.image_size_in_bytes - rsx_pitch + (src_area.width() * pack_info.block_size);
ensure(data_length + pbo_offset <= static_cast<u64>(pbo.size()), "Memory allocation cannot fit image contents. Report to developers.");
scratch_mem.copy_to(&pbo, reinterpret_cast<u64>(out_offset), pbo_offset, data_length);
}
else
{
@ -219,13 +236,16 @@ namespace gl
pack_unpack_swap_bytes = false;
}
pbo.bind(buffer::target::pixel_pack);
const auto bpp = src->pitch() / src->width();
real_pitch = rsx_pitch;
ensure((real_pitch % bpp) == 0);
pixel_pack_settings pack_settings;
pack_settings.alignment(1);
pack_settings.swap_bytes(pack_unpack_swap_bytes);
pack_settings.row_length(rsx_pitch / bpp);
src->copy_to(nullptr, format, type, pack_settings);
src->copy_to(pbo, pbo_offset, format, type, 0, src_rgn, pack_settings);
}
if (auto error = glGetError())
@ -266,6 +286,7 @@ namespace gl
gl::texture* target_texture = vram_texture;
u32 transfer_width = width;
u32 transfer_height = height;
u32 transfer_x = 0, transfer_y = 0;
if (context == rsx::texture_upload_context::framebuffer_storage)
{
@ -311,7 +332,35 @@ namespace gl
}
}
dma_transfer(cmd, target_texture, {}, {}, rsx_pitch);
const auto valid_range = get_confirmed_range();
if (const auto section_range = get_section_range(); section_range != valid_range)
{
if (const auto offset = (valid_range.start - get_section_base()))
{
transfer_y = offset / rsx_pitch;
transfer_x = (offset % rsx_pitch) / rsx::get_format_block_size_in_bytes(gcm_format);
ensure(transfer_width >= transfer_x);
ensure(transfer_height >= transfer_y);
transfer_width -= transfer_x;
transfer_height -= transfer_y;
}
if (const auto tail = (section_range.end - valid_range.end))
{
const auto row_count = tail / rsx_pitch;
ensure(transfer_height >= row_count);
transfer_height -= row_count;
}
}
areai src_area;
src_area.x1 = static_cast<s32>(transfer_x);
src_area.y1 = static_cast<s32>(transfer_y);
src_area.x2 = s32(transfer_x + transfer_width);
src_area.y2 = s32(transfer_y + transfer_height);
dma_transfer(cmd, target_texture, src_area, valid_range, rsx_pitch);
}
/**
@ -427,9 +476,7 @@ namespace gl
using gl::viewable_image::viewable_image;
};
blitter m_hw_blitter;
std::vector<std::unique_ptr<temporary_image_t>> m_temporary_surfaces;
const u32 max_cached_image_pool_size = 256;
private:
@ -733,6 +780,7 @@ namespace gl
gl::upload_texture(cmd, section->get_raw_texture(), gcm_format, input_swizzled, subresource_layout);
section->get_raw_texture()->set_name(fmt::format("Raw Texture @0x%x", rsx_range.start));
section->last_write_tag = rsx::get_shared_tag();
return section;
}
@ -810,16 +858,11 @@ namespace gl
using baseclass::texture_cache;
void initialize()
{
m_hw_blitter.init();
g_hw_blitter = &m_hw_blitter;
}
{}
void destroy() override
{
clear();
g_hw_blitter = nullptr;
m_hw_blitter.destroy();
}
bool is_depth_texture(u32 rsx_address, u32 rsx_size) override
@ -865,7 +908,7 @@ namespace gl
bool blit(gl::command_context& cmd, const rsx::blit_src_info& src, const rsx::blit_dst_info& dst, bool linear_interpolate, gl_render_targets& m_rtts)
{
auto result = upload_scaled_image(src, dst, linear_interpolate, cmd, m_rtts, m_hw_blitter);
auto result = upload_scaled_image(src, dst, linear_interpolate, cmd, m_rtts, *g_hw_blitter);
if (result.succeeded)
{

View file

@ -8,6 +8,18 @@ namespace gl
{
blitter* g_hw_blitter = nullptr;
void blitter::init()
{
blit_src.create();
blit_dst.create();
}
void blitter::destroy()
{
blit_dst.remove();
blit_src.remove();
}
void blitter::copy_image(gl::command_context&, const texture* src, const texture* dst, int src_level, int dst_level, const position3i& src_offset, const position3i& dst_offset, const size3i& size) const
{
ensure(src_level == 0);
@ -147,6 +159,9 @@ namespace gl
gl::fbo::attachment dst_att{ blit_dst, static_cast<fbo::attachment::type>(attachment) };
dst_att = *real_dst;
blit_src.check();
blit_dst.check();
blit_src.blit(blit_dst, src_rect, dst_rect, target, interp);
// Release the attachments explicitly (not doing so causes glitches, e.g Journey Menu)

View file

@ -30,17 +30,9 @@ namespace gl
public:
void init()
{
blit_src.create();
blit_dst.create();
}
void init();
void destroy()
{
blit_dst.remove();
blit_src.remove();
}
void destroy();
void scale_image(gl::command_context& cmd, const texture* src, texture* dst, areai src_rect, areai dst_rect, bool linear_interpolation,
const rsx::typeless_xfer& xfer_info);

View file

@ -131,6 +131,11 @@ namespace gl
DSA_CALL2(NamedBufferSubData, m_id, offset, length, data);
}
void buffer::fill(GLsizeiptr offset, GLsizeiptr length, GLuint pattern)
{
DSA_CALL2(ClearNamedBufferSubData, m_id, GL_R32UI, offset, length, GL_RED, GL_UNSIGNED_INT, &pattern);
}
GLubyte* buffer::map(GLsizeiptr offset, GLsizeiptr length, access access_)
{
ensure(m_memory_type == memory_type::host_visible);

View file

@ -15,7 +15,9 @@ namespace gl
element_array = GL_ELEMENT_ARRAY_BUFFER,
uniform = GL_UNIFORM_BUFFER,
texture = GL_TEXTURE_BUFFER,
ssbo = GL_SHADER_STORAGE_BUFFER
ssbo = GL_SHADER_STORAGE_BUFFER,
copy_src = GL_COPY_READ_BUFFER,
copy_dst = GL_COPY_WRITE_BUFFER
};
enum class access
@ -65,6 +67,8 @@ namespace gl
case target::uniform: pname = GL_UNIFORM_BUFFER_BINDING; break;
case target::texture: pname = GL_TEXTURE_BUFFER_BINDING; break;
case target::ssbo: pname = GL_SHADER_STORAGE_BUFFER_BINDING; break;
case target::copy_src: pname = GL_COPY_READ_BUFFER_BINDING; break;
case target::copy_dst: pname = GL_COPY_WRITE_BUFFER_BINDING; break;
default: fmt::throw_exception("Invalid binding state target (0x%x)", static_cast<int>(target_));
}
@ -113,6 +117,7 @@ namespace gl
void data(GLsizeiptr size, const void* data_ = nullptr, GLenum usage = GL_STREAM_DRAW);
void sub_data(GLsizeiptr offset, GLsizeiptr length, const GLvoid* data);
void fill(GLsizeiptr offset, GLsizeiptr length, GLuint pattern);
GLubyte* map(GLsizeiptr offset, GLsizeiptr length, access access_);
void unmap();

View file

@ -2,6 +2,7 @@
#include "capabilities.h"
#include "Utilities/StrUtil.h"
#include "Emu/system_config.h"
#include <unordered_set>
@ -43,6 +44,8 @@ namespace gl
all_extensions.emplace(reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, i)));
}
RENDERDOC_debug = !!g_cfg.video.renderdoc_compatiblity;
#define CHECK_EXTENSION_SUPPORT(extension_short_name)\
do {\
if (all_extensions.contains("GL_"#extension_short_name)) {\

View file

@ -23,6 +23,7 @@ namespace gl
bool initialized = false;
version_info glsl_version;
bool RENDERDOC_debug = false;
bool EXT_direct_state_access_supported = false;
bool EXT_depth_bounds_test_supported = false;
bool AMD_pinned_memory_supported = false;

View file

@ -76,10 +76,30 @@ namespace gl
}
};
// Very useful util when capturing traces with RenderDoc
static inline void push_debug_label(const char* label)
template <GLenum Ns>
struct named_object
{
glInsertEventMarkerEXT(static_cast<GLsizei>(strlen(label)), label);
protected:
GLuint m_id = GL_NONE;
std::string m_name = "Unnamed";
public:
void set_name(std::string_view name)
{
m_name = name.data();
glObjectLabel(Ns, m_id, static_cast<GLsizei>(name.length()), name.data());
}
std::string_view name() const
{
return m_name;
}
};
// Very useful util when capturing traces with RenderDoc
static inline void push_debug_label(std::string_view label)
{
glInsertEventMarkerEXT(static_cast<GLsizei>(label.size()), label.data());
}
// Checks if GL state is still valid

View file

@ -19,6 +19,54 @@ namespace gl
}
}
static const char* gl_type_to_str(texture::type type)
{
switch (type)
{
case texture::type::ubyte: return "GL_UNSIGNED_BYTE";
case texture::type::ushort: return "GL_UNSIGNED_SHORT";
case texture::type::uint: return "GL_UNSIGNED_INT";
case texture::type::ubyte_3_3_2: return "GL_UNSIGNED_BYTE_3_3_2";
case texture::type::ubyte_2_3_3_rev: return "GL_UNSIGNED_BYTE_2_3_3_REV";
case texture::type::ushort_5_6_5: return "GL_UNSIGNED_SHORT_5_6_5";
case texture::type::ushort_5_6_5_rev: return "GL_UNSIGNED_SHORT_5_6_5_REV";
case texture::type::ushort_4_4_4_4: return "GL_UNSIGNED_SHORT_4_4_4_4";
case texture::type::ushort_4_4_4_4_rev: return "GL_UNSIGNED_SHORT_4_4_4_4_REV";
case texture::type::ushort_5_5_5_1: return "GL_UNSIGNED_SHORT_5_5_5_1";
case texture::type::ushort_1_5_5_5_rev: return "GL_UNSIGNED_SHORT_1_5_5_5_REV";
case texture::type::uint_8_8_8_8: return "GL_UNSIGNED_INT_8_8_8_8";
case texture::type::uint_8_8_8_8_rev: return "GL_UNSIGNED_INT_8_8_8_8_REV";
case texture::type::uint_10_10_10_2: return "GL_UNSIGNED_INT_10_10_10_2";
case texture::type::uint_2_10_10_10_rev: return "GL_UNSIGNED_INT_2_10_10_10_REV";
case texture::type::uint_24_8: return "GL_UNSIGNED_INT_24_8";
case texture::type::float32_uint8: return "GL_FLOAT_32_UNSIGNED_INT_24_8_REV";
case texture::type::sbyte: return "GL_BYTE";
case texture::type::sshort: return "GL_SHORT";
case texture::type::sint: return "GL_INT";
case texture::type::f16: return "GL_HALF_FLOAT";
case texture::type::f32: return "GL_FLOAT";
case texture::type::f64: return "GL_DOUBLE";
default: return "UNKNOWN";
}
}
static const char* gl_format_to_str(texture::format format)
{
switch (format)
{
case texture::format::r: return "GL_RED";
case texture::format::rg: return "GL_RG";
case texture::format::rgb: return "GL_RGB";
case texture::format::rgba: return "GL_RGBA";
case texture::format::bgr: return "GL_BGR";
case texture::format::bgra: return "GL_BGRA";
case texture::format::stencil: return "GL_STENCIL_INDEX";
case texture::format::depth: return "GL_DEPTH_COMPONENT";
case texture::format::depth_stencil: return "GL_DEPTH_STENCIL";
default: return "UNKNOWN";
}
}
texture::texture(GLenum target, GLuint width, GLuint height, GLuint depth, GLuint mipmaps, GLubyte samples, GLenum sized_format, rsx::format_class format_class)
{
// Upgrade targets for MSAA
@ -175,7 +223,7 @@ namespace gl
m_id = GL_NONE;
}
void texture::copy_from(const void* src, texture::format format, texture::type type, int level, const coord3u region, const pixel_unpack_settings& pixel_settings)
void texture::copy_from(const rsx::io_buffer& src, texture::format format, texture::type type, int level, const coord3u region, const pixel_unpack_settings& pixel_settings)
{
ensure(m_samples <= 1, "Transfer operations are unsupported on multisampled textures.");
@ -185,30 +233,30 @@ namespace gl
{
case GL_TEXTURE_1D:
{
DSA_CALL(TextureSubImage1D, m_id, GL_TEXTURE_1D, level, region.x, region.width, static_cast<GLenum>(format), static_cast<GLenum>(type), src);
DSA_CALL(TextureSubImage1D, m_id, GL_TEXTURE_1D, level, region.x, region.width, static_cast<GLenum>(format), static_cast<GLenum>(type), src.data());
break;
}
case GL_TEXTURE_2D:
{
DSA_CALL(TextureSubImage2D, m_id, GL_TEXTURE_2D, level, region.x, region.y, region.width, region.height, static_cast<GLenum>(format), static_cast<GLenum>(type), src);
DSA_CALL(TextureSubImage2D, m_id, GL_TEXTURE_2D, level, region.x, region.y, region.width, region.height, static_cast<GLenum>(format), static_cast<GLenum>(type), src.data());
break;
}
case GL_TEXTURE_3D:
case GL_TEXTURE_2D_ARRAY:
{
DSA_CALL(TextureSubImage3D, m_id, target_, level, region.x, region.y, region.z, region.width, region.height, region.depth, static_cast<GLenum>(format), static_cast<GLenum>(type), src);
DSA_CALL(TextureSubImage3D, m_id, target_, level, region.x, region.y, region.z, region.width, region.height, region.depth, static_cast<GLenum>(format), static_cast<GLenum>(type), src.data());
break;
}
case GL_TEXTURE_CUBE_MAP:
{
if (get_driver_caps().ARB_direct_state_access_supported)
{
glTextureSubImage3D(m_id, level, region.x, region.y, region.z, region.width, region.height, region.depth, static_cast<GLenum>(format), static_cast<GLenum>(type), src);
glTextureSubImage3D(m_id, level, region.x, region.y, region.z, region.width, region.height, region.depth, static_cast<GLenum>(format), static_cast<GLenum>(type), src.data());
}
else
{
rsx_log.warning("Cubemap upload via texture::copy_from is halfplemented!");
auto ptr = static_cast<const u8*>(src);
auto ptr = static_cast<const u8*>(src.data());
const auto end = std::min(6u, region.z + region.depth);
for (unsigned face = region.z; face < end; ++face)
{
@ -221,40 +269,51 @@ namespace gl
}
}
void texture::copy_from(buffer& buf, u32 gl_format_type, u32 offset, u32 length)
void texture::copy_from(buffer& buf, GLsizeiptr offset, texture::format format, texture::type type, int level, const coord3u region, const pixel_unpack_settings& pixel_settings)
{
ensure(m_samples <= 1, "Transfer operations are unsupported on multisampled textures.");
if (get_target() != target::textureBuffer)
fmt::throw_exception("OpenGL error: texture cannot copy from buffer");
buf.bind(buffer::target::pixel_unpack);
DSA_CALL(TextureBufferRange, m_id, GL_TEXTURE_BUFFER, gl_format_type, buf.id(), offset, length);
const rsx::io_buffer src{ reinterpret_cast<void*>(static_cast<uintptr_t>(offset)), buf.size() - offset };
copy_from(src, format, type, level, region, pixel_settings);
}
void texture::copy_from(buffer_view& view)
{
copy_from(*view.value(), view.format(), view.offset(), view.range());
if (get_target() != target::textureBuffer)
fmt::throw_exception("OpenGL error: texture cannot copy from buffer");
DSA_CALL(TextureBufferRange, m_id, GL_TEXTURE_BUFFER, view.format(), view.value()->id(), view.offset(), view.range());
}
void texture::copy_to(void* dst, texture::format format, texture::type type, int level, const coord3u& region, const pixel_pack_settings& pixel_settings) const
void texture::copy_to(const rsx::io_buffer& dst, texture::format format, texture::type type, int level, const coord3u& region, const pixel_pack_settings& pixel_settings) const
{
ensure(m_samples <= 1, "Transfer operations are unsupported on multisampled textures.");
pixel_settings.apply();
const auto& caps = get_driver_caps();
if (caps.RENDERDOC_debug)
{
const auto msg = fmt::format("glGetTextureSubImage('[%u] %s', %u, %u, %u, %u, %u, %u, %u, %s, %s, %d, %p)",
m_id, m_name.c_str(), level, region.x, region.y, region.z, region.width, region.height, region.depth,
gl_format_to_str(format), gl_type_to_str(type), s32{ smax }, dst.data());
push_debug_label(msg);
}
if (!region.x && !region.y && !region.z &&
region.width == m_width && region.height == m_height && region.depth == m_depth)
{
if (caps.ARB_direct_state_access_supported)
glGetTextureImage(m_id, level, static_cast<GLenum>(format), static_cast<GLenum>(type), s32{ smax }, dst);
glGetTextureImage(m_id, level, static_cast<GLenum>(format), static_cast<GLenum>(type), dst.size<GLsizei>(), dst.data());
else
glGetTextureImageEXT(m_id, static_cast<GLenum>(m_target), level, static_cast<GLenum>(format), static_cast<GLenum>(type), dst);
glGetTextureImageEXT(m_id, static_cast<GLenum>(m_target), level, static_cast<GLenum>(format), static_cast<GLenum>(type), dst.data());
}
else if (caps.ARB_direct_state_access_supported)
{
glGetTextureSubImage(m_id, level, region.x, region.y, region.z, region.width, region.height, region.depth,
static_cast<GLenum>(format), static_cast<GLenum>(type), s32{ smax }, dst);
static_cast<GLenum>(format), static_cast<GLenum>(type), s32{ smax }, dst.data());
}
else
{
@ -269,6 +328,16 @@ namespace gl
}
}
void texture::copy_to(buffer& buf, GLsizeiptr offset, texture::format format, texture::type type, int level, const coord3u& region, const pixel_pack_settings& pixel_settings) const
{
ensure(offset < buf.size(), "PBO write is out of range");
buf.bind(buffer::target::pixel_pack);
const rsx::io_buffer dst{ reinterpret_cast<void*>(static_cast<uintptr_t>(offset)), buf.size() - offset };
copy_to(dst, format, type, level, region, pixel_settings);
}
void texture_view::create(texture* data, GLenum target, GLenum sized_format, const subresource_range& range, const GLenum* argb_swizzle)
{
m_target = target;
@ -397,6 +466,8 @@ namespace gl
auto view = std::make_unique<texture_view>(this, swizzle, aspect_flags);
auto result = view.get();
views.emplace(key, std::move(view));
result->set_name(fmt::format("%s, remap=%x", name(), remap.encoded));
return result;
}

View file

@ -4,6 +4,7 @@
#include "Utilities/geometry.h"
#include "Emu/RSX/Common/TextureUtils.h"
#include "Emu/RSX/Common/io_buffer.h"
//using enum rsx::format_class;
using namespace ::rsx::format_class_;
@ -58,7 +59,7 @@ namespace gl
GLuint num_layers;
};
class texture
class texture : public named_object<GL_TEXTURE>
{
friend class texture_view;
@ -180,7 +181,6 @@ namespace gl
};
protected:
GLuint m_id = GL_NONE;
GLuint m_width = 0;
GLuint m_height = 0;
GLuint m_depth = 0;
@ -321,32 +321,33 @@ namespace gl
}
// Data management
void copy_from(const void* src, texture::format format, texture::type type, int level, const coord3u region, const pixel_unpack_settings& pixel_settings);
void copy_from(const rsx::io_buffer& src, texture::format format, texture::type type, int level, const coord3u region, const pixel_unpack_settings& pixel_settings);
void copy_from(buffer& buf, u32 gl_format_type, u32 offset, u32 length);
void copy_from(buffer& buf, GLsizeiptr offset, texture::format format, texture::type type, int level, const coord3u region, const pixel_unpack_settings& pixel_settings);
void copy_from(buffer_view& view);
void copy_to(void* dst, texture::format format, texture::type type, int level, const coord3u& region, const pixel_pack_settings& pixel_settings) const;
void copy_to(const rsx::io_buffer& dst, texture::format format, texture::type type, int level, const coord3u& region, const pixel_pack_settings& pixel_settings) const;
void copy_to(buffer& buf, GLsizeiptr offset, texture::format format, texture::type type, int level, const coord3u& region, const pixel_pack_settings& pixel_settings) const;
// Convenience wrappers
void copy_from(const void* src, texture::format format, texture::type type, const pixel_unpack_settings& pixel_settings)
void copy_from(const rsx::io_buffer& src, texture::format format, texture::type type, const pixel_unpack_settings& pixel_settings)
{
const coord3u region = { {}, size3D() };
copy_from(src, format, type, 0, region, pixel_settings);
}
void copy_to(void* dst, texture::format format, texture::type type, const pixel_pack_settings& pixel_settings) const
void copy_to(const rsx::io_buffer& dst, texture::format format, texture::type type, const pixel_pack_settings& pixel_settings) const
{
const coord3u region = { {}, size3D() };
copy_to(dst, format, type, 0, region, pixel_settings);
}
};
class texture_view
class texture_view : public named_object<GL_TEXTURE>
{
protected:
GLuint m_id = GL_NONE;
GLenum m_target = 0;
GLenum m_format = 0;
GLenum m_view_format = 0;
@ -462,6 +463,7 @@ namespace gl
class viewable_image : public texture
{
protected:
std::unordered_map<u64, std::unique_ptr<texture_view>> views;
public:

View file

@ -306,7 +306,7 @@ namespace rsx
REGS(ctx)->decode(reg, REGS(ctx)->latch);
}
void set_aa_control(context* ctx, u32 reg, u32 arg)
void set_aa_control(context* ctx, u32 /*reg*/, u32 arg)
{
const auto latch = REGS(ctx)->latch;
if (arg == latch)

View file

@ -0,0 +1,30 @@
#include "stdafx.h"
#include "overlay_audio.h"
#include "Emu/System.h"
namespace rsx
{
namespace overlays
{
audio_player::audio_player(const std::string& audio_path)
{
init_audio(audio_path);
}
void audio_player::init_audio(const std::string& audio_path)
{
if (audio_path.empty()) return;
m_video_source = ensure(Emu.GetCallbacks().make_video_source());
m_video_source->set_audio_path(audio_path);
}
void audio_player::set_active(bool active)
{
if (m_video_source)
{
m_video_source->set_active(active);
}
}
}
}

View file

@ -0,0 +1,23 @@
#pragma once
#include "util/video_source.h"
namespace rsx
{
namespace overlays
{
class audio_player
{
public:
audio_player(const std::string& audio_path);
~audio_player() = default;
void set_active(bool active);
private:
void init_audio(const std::string& audio_path);
std::unique_ptr<video_source> m_video_source;
};
}
}

View file

@ -5,6 +5,7 @@
#include "Emu/localized_string.h"
#include <memory>
#include <span>
// Definitions for common UI controls and their routines
namespace rsx
@ -39,6 +40,9 @@ namespace rsx
image_info_base() {}
virtual ~image_info_base() {}
virtual const u8* get_data() const = 0;
virtual usz size_bytes() const { return static_cast<usz>(w * h * 4); } // UI images get converted to RGBA8
std::span<const u8> as_span() const { return { get_data(), size_bytes() }; }
};
struct image_info : public image_info_base

View file

@ -167,6 +167,23 @@ namespace rsx
}
}
void display_manager::start_audio(const std::string& audio_path)
{
if (audio_path.empty())
{
m_audio_player.reset();
return;
}
m_audio_player = std::make_unique<audio_player>(audio_path);
m_audio_player->set_active(true);
}
void display_manager::stop_audio()
{
m_audio_player.reset();
}
void display_manager::on_overlay_activated(const std::shared_ptr<overlay>& /*item*/)
{
// TODO: Internal management, callbacks, etc

View file

@ -1,6 +1,7 @@
#pragma once
#include "overlays.h"
#include "overlay_audio.h"
#include "Emu/IdManager.h"
#include "Utilities/mutex.h"
@ -25,6 +26,8 @@ namespace rsx
lf_queue<u32> m_type_ids_to_remove;
atomic_t<u32> m_pending_removals_count = 0;
std::unique_ptr<audio_player> m_audio_player;
bool remove_type(u32 type_id);
bool remove_uid(u32 uid);
@ -167,6 +170,9 @@ namespace rsx
std::function<void(s32)> on_input_loop_exit = nullptr, // [optional] What to do with the result if any
std::function<s32()> input_loop_override = nullptr); // [optional] What to do during the input loop. By default calls user_interface::run_input_loop
void start_audio(const std::string& audio_path);
void stop_audio();
private:
struct overlay_input_thread
{

View file

@ -9,10 +9,11 @@ namespace rsx
{
save_dialog::save_dialog_entry::save_dialog_entry(const std::string& text1, const std::string& text2, const std::string& text3, u8 resource_id, const std::vector<u8>& icon_buf, const std::string& video_path)
{
const std::string audio_path; // no audio here
std::unique_ptr<overlay_element> image = resource_id != image_resource_id::raw_image
? std::make_unique<video_view>(video_path, resource_id)
: !icon_buf.empty() ? std::make_unique<video_view>(video_path, icon_buf)
: std::make_unique<video_view>(video_path, resource_config::standard_image_resource::save); // Fallback
? std::make_unique<video_view>(video_path, audio_path, resource_id)
: !icon_buf.empty() ? std::make_unique<video_view>(video_path, audio_path, icon_buf)
: std::make_unique<video_view>(video_path, audio_path, resource_config::standard_image_resource::save); // Fallback
image->set_size(160, 110);
image->set_padding(36, 36, 11, 11); // Square image, 88x88

View file

@ -6,9 +6,9 @@ namespace rsx
{
namespace overlays
{
video_view::video_view(const std::string& video_path, const std::string& thumbnail_path)
video_view::video_view(const std::string& video_path, const std::string& audio_path, const std::string& thumbnail_path)
{
init_video(video_path);
init_video(video_path, audio_path);
if (!thumbnail_path.empty())
{
@ -17,9 +17,9 @@ namespace rsx
}
}
video_view::video_view(const std::string& video_path, const std::vector<u8>& thumbnail_buf)
video_view::video_view(const std::string& video_path, const std::string& audio_path, const std::vector<u8>& thumbnail_buf)
{
init_video(video_path);
init_video(video_path, audio_path);
if (!thumbnail_buf.empty())
{
@ -28,10 +28,10 @@ namespace rsx
}
}
video_view::video_view(const std::string& video_path, u8 thumbnail_id)
video_view::video_view(const std::string& video_path, const std::string& audio_path, u8 thumbnail_id)
: m_thumbnail_id(thumbnail_id)
{
init_video(video_path);
init_video(video_path, audio_path);
set_image_resource(thumbnail_id);
}
@ -39,13 +39,11 @@ namespace rsx
{
}
void video_view::init_video(const std::string& video_path)
void video_view::init_video(const std::string& video_path, const std::string& audio_path)
{
if (video_path.empty()) return;
m_video_source = Emu.GetCallbacks().make_video_source();
ensure(!!m_video_source);
m_video_source = ensure(Emu.GetCallbacks().make_video_source());
m_video_source->set_update_callback([this]()
{
if (m_video_active)
@ -54,6 +52,7 @@ namespace rsx
}
});
m_video_source->set_video_path(video_path);
m_video_source->set_audio_path(audio_path);
}
void video_view::set_active(bool active)

View file

@ -19,9 +19,9 @@ namespace rsx
class video_view final : public image_view
{
public:
video_view(const std::string& video_path, const std::string& thumbnail_path);
video_view(const std::string& video_path, const std::vector<u8>& thumbnail_buf);
video_view(const std::string& video_path, u8 thumbnail_id);
video_view(const std::string& video_path, const std::string& audio_path, const std::string& thumbnail_path);
video_view(const std::string& video_path, const std::string& audio_path, const std::vector<u8>& thumbnail_buf);
video_view(const std::string& video_path, const std::string& audio_path, u8 thumbnail_id);
virtual ~video_view();
void set_active(bool active);
@ -30,7 +30,7 @@ namespace rsx
compiled_resource& get_compiled() override;
private:
void init_video(const std::string& video_path);
void init_video(const std::string& video_path, const std::string& audio_path);
usz m_buffer_index = 0;
std::array<std::unique_ptr<video_info>, 2> m_video_info; // double buffer

View file

@ -31,14 +31,14 @@ namespace rsx::assembler::FP
switch (dst.prec)
{
case RSX_FP_PRECISION_REAL:
case RSX_FP_PRECISION_UNKNOWN:
// case RSX_FP_PRECISION_UNKNOWN: // Unreachable
break;
case RSX_FP_PRECISION_HALF:
if (!src0.fp16) return false;
break;
case RSX_FP_PRECISION_FIXED12:
case RSX_FP_PRECISION_FIXED9:
case RSX_FP_PRECISION_SATURATE:
// case RSX_FP_PRECISION_SATURATE: // Unreachable
return false;
}

View file

@ -868,8 +868,11 @@ std::string FragmentProgramDecompiler::BuildCode()
if (!m_is_valid_ucode)
{
// If the code is broken, do not compile. Simply NOP main and write empty outputs
m_parr.params[PF_PARAM_UNIFORM].clear();
insertHeader(OS);
OS << "\n";
insertConstants(OS);
OS << "\n";
OS << "void main()\n";
OS << "{\n";
OS << "#if 0\n";

View file

@ -675,6 +675,8 @@ fragment_program_utils::fragment_program_metadata fragment_program_utils::analys
// Otherwise we would need to follow the execution chain
result.has_branch_instructions = true;
break;
default:
break;
}
if (rsx::assembler::FP::get_operand_count(opcode) > 0 &&

View file

@ -711,6 +711,11 @@ namespace rsx
if (g_cfg.misc.use_native_interface && (g_cfg.video.renderer == video_renderer::opengl || g_cfg.video.renderer == video_renderer::vulkan))
{
m_overlay_manager = g_fxo->init<rsx::overlays::display_manager>(0);
if (const std::string audio_path = Emu.GetSfoDir(true) + "/SND0.AT3"; fs::is_file(audio_path))
{
m_overlay_manager->start_audio(audio_path);
}
}
if (!_ar)
@ -1101,6 +1106,11 @@ namespace rsx
thread_ctrl::set_thread_affinity_mask(thread_ctrl::get_affinity_mask(thread_class::rsx));
}
if (auto manager = g_fxo->try_get<rsx::overlays::display_manager>())
{
manager->stop_audio();
}
while (!test_stopped())
{
// Wait for external pause events

View file

@ -635,9 +635,16 @@ bool VKGSRender::bind_texture_env()
{
if (!(textures_ref & 1))
{
// Unused TIU
continue;
}
if (m_fs_binding_table->ftex_location[i] == umax)
{
// Corrupt shader table
break;
}
vk::image_view* view = nullptr;
auto sampler_state = static_cast<vk::texture_cache::sampled_image_descriptor*>(fs_sampler_state[i].get());
@ -707,9 +714,16 @@ bool VKGSRender::bind_texture_env()
{
if (!(textures_ref & 1))
{
// Unused TIU
continue;
}
if (m_vs_binding_table->vtex_location[i] == umax)
{
// Corrupt shader
break;
}
if (!rsx::method_registers.vertex_textures[i].enabled())
{
const auto view_type = vk::get_view_type(current_vertex_program.get_texture_dimension(i));

View file

@ -264,6 +264,7 @@ namespace vk
}
builder << "\n"
"#undef TEX_PARAM\n"
"#define TEX_PARAM(index) texture_parameters[index + texture_base_index]\n"
"#define IS_TEXTURE_RESIDENT(index) true\n"
"#define SAMPLER1D(index) sampler1D_array[index]\n"

View file

@ -28,6 +28,7 @@ namespace vk
table.add(0x7420, 0x743F, chip_class::AMD_navi2x); // Navi 24 (Beige Goby)
table.add(0x163F, chip_class::AMD_navi2x); // Navi 2X (Van Gogh)
table.add(0x164D, 0x1681, chip_class::AMD_navi2x); // Navi 2X (Yellow Carp)
table.add(0x13C0, chip_class::AMD_navi2x); // Navi 2X (Raphael Mendocino)
table.add(0x7440, 0x745F, chip_class::AMD_navi3x); // Navi 31 (Only 744c, NAVI31XTX is confirmed)
table.add(0x7460, 0x747F, chip_class::AMD_navi3x); // Navi 32 (Unverified)
table.add(0x7480, 0x749F, chip_class::AMD_navi3x); // Navi 33 (Unverified)

View file

@ -7,6 +7,7 @@
#include "Common/unordered_map.hpp"
#include "Emu/System.h"
#include "Emu/cache_utils.hpp"
#include "Emu/Memory/vm.h"
#include "Emu/RSX/Program/RSXVertexProgram.h"
#include "Emu/RSX/Program/RSXFragmentProgram.h"
#include "Overlays/Shaders/shader_loading_dialog.h"
@ -478,6 +479,7 @@ namespace rsx
uptr local_address;
u32 offset_in_heap;
u32 data_length;
u64 fingerprint;
};
// A weak vertex cache with no data checks or memory range locks
@ -502,11 +504,20 @@ namespace rsx
{
const auto key = hash(local_addr, data_length);
const auto found = vertex_ranges.find(key);
if (found == vertex_ranges.end())
{
return nullptr;
}
// Check if data in local_address changed vs what was stored in the vertex_cache
if (auto sudo_ptr = vm::get_super_ptr<char>(local_addr);
data_length >= 8 && found->second.fingerprint != *utils::bless<u64>(sudo_ptr))
{
vertex_ranges.erase(key);
return nullptr;
}
return std::addressof(found->second);
}
@ -517,6 +528,11 @@ namespace rsx
v.local_address = local_addr;
v.offset_in_heap = offset_in_heap;
if (auto sudo_ptr = vm::get_super_ptr<char>(local_addr); data_length >= 8)
{
v.fingerprint = *utils::bless<u64>(sudo_ptr);
}
const auto key = hash(local_addr, data_length);
vertex_ranges[key] = v;
}

View file

@ -23,7 +23,7 @@ struct serial_ver_t
std::set<u16> compatible_versions;
};
static std::array<serial_ver_t, 27> s_serial_versions;
static std::array<serial_ver_t, 34> s_serial_versions;
#define SERIALIZATION_VER(name, identifier, ...) \
\
@ -40,7 +40,7 @@ static std::array<serial_ver_t, 27> s_serial_versions;
return ::s_serial_versions[identifier].current_version;\
}
SERIALIZATION_VER(global_version, 0, 19) // For stuff not listed here
SERIALIZATION_VER(global_version, 0, 20) // For stuff not listed here
SERIALIZATION_VER(ppu, 1, 1, 2/*PPU sleep order*/, 3/*PPU FNID and module*/)
SERIALIZATION_VER(spu, 2, 1)
SERIALIZATION_VER(lv2_sync, 3, 1)
@ -85,6 +85,16 @@ SERIALIZATION_VER(LLE, 24, 1)
SERIALIZATION_VER(HLE, 25, 1)
SERIALIZATION_VER(cellSysutil, 26, 1, 2/*AVC2 Muting,Volume*/)
SERIALIZATION_VER(cellDmuxPamf, 27, 1)
// For future modules
SERIALIZATION_VER(cellReserved1, 27, 1)
SERIALIZATION_VER(cellReserved2, 28, 1)
SERIALIZATION_VER(cellReserved3, 29, 1)
SERIALIZATION_VER(cellReserved4, 30, 1)
SERIALIZATION_VER(cellReserved6, 31, 1)
SERIALIZATION_VER(cellReserved7, 32, 1)
SERIALIZATION_VER(cellReserved8, 33, 1)
template <>
void fmt_class_string<std::remove_cvref_t<decltype(s_serial_versions)>>::format(std::string& out, u64 arg)

View file

@ -10,15 +10,6 @@
LOG_CHANNEL(camera_log, "Camera");
#if !(SDL_VERSION_ATLEAST(3, 4, 0))
namespace SDL_CameraPermissionState
{
constexpr int SDL_CAMERA_PERMISSION_STATE_DENIED = -1;
constexpr int SDL_CAMERA_PERMISSION_STATE_PENDING = 0;
constexpr int SDL_CAMERA_PERMISSION_STATE_APPROVED = 1;
}
#endif
template <>
void fmt_class_string<SDL_CameraSpec>::format(std::string& out, u64 arg)
{

View file

@ -102,8 +102,8 @@ bool sdl_instance::initialize_impl()
set_hint(SDL_HINT_JOYSTICK_HIDAPI_PS3, "1");
#endif
// Disable LG4FF driver on windows (only needed for SDL 3.4.0)
#if _WIN32 && SDL_VERSION_ATLEAST(3, 4, 0)
// Disable LG4FF driver on windows
#if _WIN32
set_hint(SDL_HINT_JOYSTICK_HIDAPI_LG4FF, "0");
#endif

View file

@ -569,7 +569,7 @@ std::unique_ptr<fs::file_base> iso_device::open(const std::string& path, bs_t<fs
return nullptr;
}
return std::make_unique<iso_file>(fs::file(iso_path), *node);
return std::make_unique<iso_file>(fs::file(iso_path, mode), *node);
}
std::unique_ptr<fs::dir_base> iso_device::open_dir(const std::string& path)

View file

@ -145,6 +145,7 @@
<ClCompile Include="Emu\RSX\Overlays\Network\overlay_recvmessage_dialog.cpp" />
<ClCompile Include="Emu\RSX\Overlays\Network\overlay_sendmessage_dialog.cpp" />
<ClCompile Include="Emu\RSX\Overlays\overlay_animated_icon.cpp" />
<ClCompile Include="Emu\RSX\Overlays\overlay_audio.cpp" />
<ClCompile Include="Emu\RSX\Overlays\overlay_controls.cpp" />
<ClCompile Include="Emu\RSX\Overlays\overlay_cursor.cpp" />
<ClCompile Include="Emu\RSX\Overlays\overlay_debug_overlay.cpp" />
@ -704,6 +705,7 @@
<ClInclude Include="Emu\RSX\Overlays\Network\overlay_recvmessage_dialog.h" />
<ClInclude Include="Emu\RSX\Overlays\Network\overlay_sendmessage_dialog.h" />
<ClInclude Include="Emu\RSX\Overlays\overlay_animated_icon.h" />
<ClInclude Include="Emu\RSX\Overlays\overlay_audio.h" />
<ClInclude Include="Emu\RSX\Overlays\overlay_cursor.h" />
<ClInclude Include="Emu\RSX\Overlays\overlay_debug_overlay.h" />
<ClInclude Include="Emu\RSX\Overlays\overlay_edit_text.hpp" />
@ -1103,4 +1105,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View file

@ -1411,6 +1411,9 @@
<ClCompile Include="Loader\ISO.cpp">
<Filter>Loader</Filter>
</ClCompile>
<ClCompile Include="Emu\RSX\Overlays\overlay_audio.cpp">
<Filter>Emu\GPU\RSX\Overlays</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Crypto\aes.h">
@ -2833,6 +2836,9 @@
<ClInclude Include="Loader\ISO.h">
<Filter>Loader</Filter>
</ClInclude>
<ClInclude Include="Emu\RSX\Overlays\overlay_audio.h">
<Filter>Emu\GPU\RSX\Overlays</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="Emu\RSX\Program\GLSLSnippets\GPUDeswizzle.glsl">

View file

@ -826,6 +826,7 @@
<ClCompile Include="rpcs3qt\call_stack_list.cpp" />
<ClCompile Include="rpcs3qt\camera_settings_dialog.cpp" />
<ClCompile Include="rpcs3qt\gui_game_info.cpp" />
<ClCompile Include="rpcs3qt\log_level_dialog.cpp" />
<ClCompile Include="rpcs3qt\permissions.cpp" />
<ClCompile Include="rpcs3qt\ps_move_tracker_dialog.cpp" />
<ClCompile Include="rpcs3qt\cheat_manager.cpp" />
@ -1578,6 +1579,7 @@
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWIN32_LEAN_AND_MEAN -DHAVE_VULKAN -DWITH_DISCORD_RPC -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DNDEBUG -DQT_CONCURRENT_LIB -DQT_MULTIMEDIA_LIB -DQT_MULTIMEDIAWIDGETS_LIB -DQT_SVG_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\SoundTouch\soundtouch\include" "-I.\..\3rdparty\cubeb\extra" "-I.\..\3rdparty\cubeb\cubeb\include" "-I.\..\3rdparty\protobuf\protobuf\src" "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtCore" "-I.\release" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtMultimedia" "-I$(QTDIR)\include\QtMultimediaWidgets" "-I$(QTDIR)\include\QtSvg"</Command>
</CustomBuild>
<ClInclude Include="rpcs3qt\hex_validator.h" />
<ClInclude Include="rpcs3qt\log_level_dialog.h" />
<ClInclude Include="rpcs3qt\movie_item.h" />
<ClInclude Include="rpcs3qt\movie_item_base.h" />
<ClInclude Include="rpcs3qt\numbered_widget_item.h" />

View file

@ -1275,6 +1275,9 @@
<ClCompile Include="Input\mouse_gyro_handler.cpp">
<Filter>Io</Filter>
</ClCompile>
<ClCompile Include="rpcs3qt\log_level_dialog.cpp">
<Filter>Gui\settings</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Input\ds4_pad_handler.h">
@ -1517,6 +1520,9 @@
<ClInclude Include="Input\mouse_gyro_handler.h">
<Filter>Io</Filter>
</ClInclude>
<ClInclude Include="rpcs3qt\log_level_dialog.h">
<Filter>Gui\settings</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClInclude Include="resource.h">

View file

@ -53,6 +53,7 @@ add_library(rpcs3_ui STATIC
localized.cpp
localized_emu.cpp
log_frame.cpp
log_level_dialog.cpp
log_viewer.cpp
main_window.cpp
memory_string_searcher.cpp

View file

@ -16,6 +16,7 @@
#include "Emu/IdManager.h"
#include "Emu/RSX/RSXThread.h"
#include "Emu/RSX/RSXDisAsm.h"
#include "Emu/Cell/lv2/sys_sync.h"
#include "Emu/Cell/PPUAnalyser.h"
#include "Emu/Cell/PPUDisAsm.h"
#include "Emu/Cell/PPUThread.h"
@ -804,12 +805,47 @@ cpu_thread* debugger_frame::get_cpu()
return nullptr;
}
if (u32 cur = m_choice_units->currentIndex(); cur >= m_hw_ppu_idx && cur < g_cfg.core.ppu_threads + m_hw_ppu_idx)
{
reader_lock lock(lv2_obj::g_mutex);
const auto ppu = lv2_obj::get_running_ppu(cur - m_hw_ppu_idx);
if (ppu == m_cpu.get())
{
// Nothing to do
}
else if (ppu)
{
m_cpu = idm::get_unlocked<named_thread<ppu_thread>>(ppu->id);
}
else
{
m_cpu.reset();
}
}
if (!!m_disasm != !!m_cpu)
{
// Fixup for HW PPU viewer
if (m_cpu)
{
m_disasm = make_disasm(m_cpu.get(), m_cpu);
}
else
{
m_disasm.reset();
}
m_debugger_list->UpdateCPUData(m_disasm);
m_breakpoint_list->UpdateCPUData(m_disasm);
}
// Wait flag is raised by the thread itself, acknowledging exit
if (m_cpu)
{
if (m_cpu->state.all_of(cpu_flag::wait + cpu_flag::exit))
{
m_cpu.reset();
return nullptr;
}
@ -823,12 +859,13 @@ cpu_thread* debugger_frame::get_cpu()
{
if (g_fxo->try_get<rsx::thread>() != m_rsx || !m_rsx->ctrl || m_rsx->state.all_of(cpu_flag::wait + cpu_flag::exit))
{
m_rsx = nullptr;
return nullptr;
}
return m_rsx;
}
return m_rsx;
return nullptr;
}
std::function<cpu_thread*()> debugger_frame::make_check_cpu(cpu_thread* cpu, bool unlocked)
@ -922,19 +959,20 @@ std::function<cpu_thread*()> debugger_frame::make_check_cpu(cpu_thread* cpu, boo
void debugger_frame::UpdateUI()
{
const auto cpu = get_cpu();
auto cpu = get_cpu();
// Refresh at a high rate during initialization (looks weird otherwise)
if (m_ui_update_ctr % (cpu || m_ui_update_ctr < 200 || m_debugger_list->m_dirty_flag ? 5 : 50) == 0)
{
// If no change to instruction position happened, update instruction list at 20hz
ShowPC();
ShowPC(false, cpu);
}
if (m_ui_update_ctr % 20 == 0 && !m_thread_list_pending_update)
{
// Update threads list at 5hz (low priority)
UpdateUnitList();
cpu = get_cpu();
}
if (!cpu)
@ -945,12 +983,13 @@ void debugger_frame::UpdateUI()
{
// Update threads list (thread exited)
UpdateUnitList();
cpu = get_cpu();
}
ShowPC();
ShowPC(false, cpu);
m_last_query_state.clear();
m_last_pc = -1;
DoUpdate();
DoUpdate(cpu);
}
}
else if (m_ui_update_ctr % 5 == 0 || m_ui_update_ctr < m_ui_fast_update_permission_deadline)
@ -966,7 +1005,7 @@ void debugger_frame::UpdateUI()
std::memcpy(m_last_query_state.data(), static_cast<void *>(cpu), size_context);
m_last_pc = cia;
DoUpdate();
DoUpdate(cpu);
const bool paused = !!(cpu->state & s_pause_flags);
@ -982,7 +1021,7 @@ void debugger_frame::UpdateUI()
if (m_ui_update_ctr % 5)
{
// Call if it hasn't been called before
ShowPC();
ShowPC(false, cpu);
}
if (is_using_interpreter(cpu->get_class()))
@ -1022,9 +1061,17 @@ void debugger_frame::UpdateUnitList()
}
std::vector<std::pair<QString, std::function<cpu_thread*()>>> cpu_list;
cpu_list.reserve(threads_created >= threads_deleted ? 0 : threads_created - threads_deleted);
cpu_list.reserve(threads_created >= threads_deleted ? threads_created - threads_deleted : 0);
usz reselected_index = umax;
usz hw_ppu_idx = umax;
if (u32 cur = m_choice_units->currentIndex(); cur >= m_hw_ppu_idx && cur < g_cfg.core.ppu_threads + m_hw_ppu_idx)
{
hw_ppu_idx = cur - m_hw_ppu_idx;
}
m_hw_ppu_idx = umax;
const auto on_select = [&](u32 id, cpu_thread& cpu)
{
@ -1033,7 +1080,7 @@ void debugger_frame::UpdateUnitList()
// Space at the end is to pad a gap on the right
cpu_list.emplace_back(QString::fromStdString((id >> 24 == 0x55 ? "RSX[0x55555555]" : cpu.get_name()) + ' '), std::move(func_cpu));
if (old_cpu_ptr == std::addressof(cpu))
if (old_cpu_ptr == std::addressof(cpu) && hw_ppu_idx == umax)
{
reselected_index = cpu_list.size() - 1;
}
@ -1046,6 +1093,40 @@ void debugger_frame::UpdateUnitList()
idm::select<named_thread<ppu_thread>>(on_select, idm::unlocked);
}
m_hw_ppu_idx = cpu_list.size() + 1; // Account for NoThreadString thread
for (u32 i = 0; i < g_cfg.core.ppu_threads + 0u; i++)
{
std::function<cpu_thread*()> get_ppu_at = [index = i, cpu_storage = shared_ptr<named_thread<ppu_thread>>()]() mutable
{
reader_lock lock(lv2_obj::g_mutex);
const auto ppu = lv2_obj::get_running_ppu(index);
if (ppu == cpu_storage.get())
{
// Nothing to do
}
else if (ppu)
{
cpu_storage = idm::get_unlocked<named_thread<ppu_thread>>(ppu->id);
}
else
{
cpu_storage.reset();
}
return cpu_storage.get();
};
if (hw_ppu_idx == i)
{
reselected_index = cpu_list.size();
}
cpu_list.emplace_back(tr("HwPPU[%0]: Hardware PPU Thread #%1").arg(i + 1).arg(i + 1), std::move(get_ppu_at));
}
if (g_fxo->is_init<id_manager::id_map<named_thread<spu_thread>>>())
{
idm::select<named_thread<spu_thread>>(on_select, idm::unlocked);
@ -1114,6 +1195,7 @@ void debugger_frame::OnSelectUnit()
}
cpu_thread* selected = nullptr;
usz hw_ppu_idx = umax;
if (m_emu_state != system_state::stopped)
{
@ -1135,7 +1217,14 @@ void debugger_frame::OnSelectUnit()
if (!selected && !m_rsx && !m_cpu)
{
return;
if (u32 cur = m_choice_units->currentIndex(); cur >= m_hw_ppu_idx && cur < g_cfg.core.ppu_threads + m_hw_ppu_idx)
{
hw_ppu_idx = cur - m_hw_ppu_idx;
}
else
{
return;
}
}
}
@ -1144,6 +1233,15 @@ void debugger_frame::OnSelectUnit()
m_rsx = nullptr;
m_spu_disasm_memory.reset();
if (hw_ppu_idx != umax)
{
if (hw_ppu_idx > 1)
{
// Sample PPU
selected = ::at32(m_threads_info, 1)();
}
}
if (selected)
{
const u32 cpu_id = selected->id;
@ -1198,8 +1296,8 @@ void debugger_frame::OnSelectUnit()
m_debugger_list->UpdateCPUData(m_disasm);
m_breakpoint_list->UpdateCPUData(m_disasm);
ShowPC(true);
DoUpdate();
ShowPC(true, selected);
DoUpdate(selected);
UpdateUI();
}
@ -1339,30 +1437,28 @@ void debugger_frame::OnSelectSPUDisassembler()
m_debugger_list->UpdateCPUData(m_disasm);
m_breakpoint_list->UpdateCPUData(m_disasm);
ShowPC(true);
DoUpdate();
ShowPC(true, nullptr);
DoUpdate(nullptr);
UpdateUI();
});
m_spu_disasm_dialog->show();
}
void debugger_frame::DoUpdate()
void debugger_frame::DoUpdate(cpu_thread* cpu0)
{
// Check if we need to disable a step over bp
if (const auto cpu0 = get_cpu(); cpu0 && m_last_step_over_breakpoint != umax && cpu0->get_pc() == m_last_step_over_breakpoint)
if (cpu0 && m_last_step_over_breakpoint != umax && cpu0->get_pc() == m_last_step_over_breakpoint)
{
m_ppu_breakpoint_handler->RemoveBreakpoint(m_last_step_over_breakpoint);
m_last_step_over_breakpoint = -1;
}
WritePanels();
WritePanels(cpu0);
}
void debugger_frame::WritePanels()
void debugger_frame::WritePanels(cpu_thread* cpu)
{
const auto cpu = get_cpu();
if (!cpu)
{
m_misc_state->clear();
@ -1412,7 +1508,9 @@ void debugger_frame::ShowGotoAddressDialog()
QLineEdit* expression_input(new QLineEdit(m_goto_dialog));
expression_input->setFont(m_mono);
if (const auto thread = get_cpu(); !thread || thread->get_class() != thread_class::spu)
const auto thread = get_cpu();
if (!thread || thread->get_class() != thread_class::spu)
{
expression_input->setValidator(new HexValidator(expression_input));
}
@ -1436,8 +1534,8 @@ void debugger_frame::ShowGotoAddressDialog()
m_goto_dialog->setLayout(vbox_panel);
const auto cpu_check = make_check_cpu(get_cpu());
const auto cpu = cpu_check();
const auto cpu_check = make_check_cpu(thread);
const auto cpu = thread;
const QFont font = expression_input->font();
// -1 from get_pc() turns into 0
@ -1544,9 +1642,12 @@ void debugger_frame::ClearCallStack()
Q_EMIT CallStackUpdateRequested({});
}
void debugger_frame::ShowPC(bool user_requested)
void debugger_frame::ShowPC(bool user_requested, cpu_thread* cpu0)
{
const auto cpu0 = get_cpu();
if (!cpu0)
{
cpu0 = get_cpu();
}
const u32 pc = (cpu0 ? cpu0->get_pc() : (m_is_spu_disasm_mode ? m_spu_disasm_pc : 0));

View file

@ -79,6 +79,7 @@ class debugger_frame : public custom_dock_widget
std::shared_ptr<CPUDisAsm> m_disasm; // Only shared to allow base/derived functionality
shared_ptr<cpu_thread> m_cpu;
rsx::thread* m_rsx = nullptr;
u32 m_hw_ppu_idx = umax;
std::shared_ptr<utils::shm> m_spu_disasm_memory;
u32 m_spu_disasm_origin_eal = 0;
u32 m_spu_disasm_pc = 0;
@ -107,8 +108,8 @@ public:
void UpdateUI();
void UpdateUnitList();
void DoUpdate();
void WritePanels();
void DoUpdate(cpu_thread* cpu0);
void WritePanels(cpu_thread* cpu);
void EnableButtons(bool enable);
void ShowGotoAddressDialog();
void PerformGoToRequest(const QString& text_argument);
@ -138,7 +139,7 @@ private Q_SLOTS:
void OnSelectUnit();
void OnSelectSPUDisassembler();
void OnRegsContextMenu(const QPoint& pos);
void ShowPC(bool user_requested = false);
void ShowPC(bool user_requested = false, cpu_thread* cpu = nullptr);
void EnableUpdateTimer(bool enable) const;
void RunBtnPress();
void RegsShowMemoryViewerAction();

View file

@ -34,7 +34,7 @@ downloader::~downloader()
}
}
void downloader::start(const std::string& url, bool follow_location, bool show_progress_dialog, const QString& progress_dialog_title, bool keep_progress_dialog_open, int expected_size, bool check_return_code, bool again)
void downloader::start(const std::string& url, bool follow_location, bool show_progress_dialog, bool check_return_code, const QString& progress_dialog_title, bool keep_progress_dialog_open, int expected_size, bool again)
{
network_log.notice("Starting download from URL: %s", url);
@ -121,7 +121,7 @@ void downloader::start(const std::string& url, bool follow_location, bool show_p
{
network_log.error("Error during download. Trying to download again (attempts=%d, return_code=%d)", m_download_attempts, return_code);
std::this_thread::sleep_for(500ms); // Wait for a little while
start(url, follow_location, show_progress_dialog, progress_dialog_title, keep_progress_dialog_open, expected_size, check_return_code, true);
start(url, follow_location, show_progress_dialog, check_return_code, progress_dialog_title, keep_progress_dialog_open, expected_size, true);
return;
}
}

View file

@ -21,7 +21,7 @@ public:
explicit downloader(QWidget* parent = nullptr);
~downloader();
void start(const std::string& url, bool follow_location, bool show_progress_dialog, const QString& progress_dialog_title = "", bool keep_progress_dialog_open = false, int expected_size = -1, bool check_return_code = true, bool again = false);
void start(const std::string& url, bool follow_location, bool show_progress_dialog, bool check_return_code, const QString& progress_dialog_title = "", bool keep_progress_dialog_open = false, int expected_size = -1, bool again = false);
usz update_buffer(char* data, usz size);
void update_progress_dialog(const QString& title) const;

View file

@ -31,18 +31,20 @@ namespace
out << YAML::Null;
return;
}
if (node.IsMap())
{
std::vector<std::string> keys;
keys.reserve(node.size());
// generate vector of strings to be sorted using the as function from YAML documentation
for (const auto& pair : node)
{
keys.push_back(pair.first.as<std::string>());
keys.push_back(pair.first.Scalar());
}
std::sort(keys.begin(), keys.end());
// recursively generate sorted maps
// alternative implementations could have stops at specified recursion levels or maybe just the first two levels would be sorted
out << YAML::BeginMap;
for (const std::string& key : keys)
{
@ -51,15 +53,10 @@ namespace
emit_data(out, node[key]);
}
out << YAML::EndMap;
return;
}
// alternatively: an else statement could be used however I wanted to follow a similar format to the += operator so the YAML Undefined class can be ignored
else if (node.IsScalar() || node.IsSequence())
{
out << node;
}
// this exists to preserve the same functionality as before where Undefined nodes would still be output, can be removed or consolidated with the else if branch
else
out << node;
out << node;
}
// Incrementally load YAML
@ -910,11 +907,38 @@ std::string emu_settings::GetSetting(emu_settings_type type) const
return "";
}
std::map<std::string, std::string> emu_settings::GetMapSettingDefault(emu_settings_type type) const
{
if (const auto node = cfg_adapter::get_node(m_default_settings, ::at32(settings_location, type)); node && node.IsMap())
{
return node.as<std::map<std::string, std::string>>();
}
cfg_log.fatal("GetMapSettingDefault(type=%d) could not retrieve the requested node", static_cast<int>(type));
return {};
}
std::map<std::string, std::string> emu_settings::GetMapSetting(emu_settings_type type) const
{
if (const auto node = cfg_adapter::get_node(m_current_settings, ::at32(settings_location, type)); node && node.IsMap())
{
return node.as<std::map<std::string, std::string>>();
}
cfg_log.fatal("GetMapSetting(type=%d) could not retrieve the requested node", static_cast<int>(type));
return {};
}
void emu_settings::SetSetting(emu_settings_type type, const std::string& val) const
{
cfg_adapter::get_node(m_current_settings, ::at32(settings_location, type)) = val;
}
void emu_settings::SetMapSetting(emu_settings_type type, const std::map<std::string, std::string>& val) const
{
cfg_adapter::get_node(m_current_settings, ::at32(settings_location, type)) = val;
}
emu_settings_type emu_settings::FindSettingsType(const cfg::_base* node) const
{
// Add key and value to static map on first use

View file

@ -78,9 +78,18 @@ public:
/** Returns the value of the setting type.*/
std::string GetSetting(emu_settings_type type) const;
/** Returns the default map value of the setting type.*/
std::map<std::string, std::string> GetMapSettingDefault(emu_settings_type type) const;
/** Returns the value of the setting type as map.*/
std::map<std::string, std::string> GetMapSetting(emu_settings_type type) const;
/** Sets the setting type to a given value.*/
void SetSetting(emu_settings_type type, const std::string& val) const;
/** Sets the setting type to a given map value.*/
void SetMapSetting(emu_settings_type type, const std::map<std::string, std::string>& val) const;
/** Try to find the settings type for a given string.*/
emu_settings_type FindSettingsType(const cfg::_base* node) const;

View file

@ -217,6 +217,9 @@ enum class emu_settings_type
EmptyHdd0Tmp,
LimitCacheSize,
MaximumCacheSize,
// Log
Log,
};
/** A helper map that keeps track of where a given setting type is located*/
@ -434,4 +437,7 @@ inline static const std::map<emu_settings_type, cfg_location> settings_location
{ emu_settings_type::SuspendEmulationSavestateMode, { "Savestate", "Suspend Emulation Savestate Mode" }},
{ emu_settings_type::CompatibleEmulationSavestateMode, { "Savestate", "Compatible Savestate Mode" }},
{ emu_settings_type::StartSavestatePaused, { "Savestate", "Start Paused" }},
// Logs
{ emu_settings_type::Log, { "Log" }},
};

View file

@ -36,7 +36,7 @@ void game_compatibility::handle_download_finished(const QByteArray& content)
compat_log.notice("Database download finished");
// Create new map from database and write database to file if database was valid
if (ReadJSON(QJsonDocument::fromJson(content).object(), true))
if (handle_json(content, true))
{
// Write database to file
QFile file(m_filepath);
@ -67,8 +67,9 @@ void game_compatibility::handle_download_canceled()
Q_EMIT DownloadCanceled();
}
bool game_compatibility::ReadJSON(const QJsonObject& json_data, bool after_download)
bool game_compatibility::handle_json(const QByteArray& data, bool after_download)
{
const QJsonObject json_data = QJsonDocument::fromJson(data).object();
const int return_code = json_data["return_code"].toInt(-255);
if (return_code < 0)
@ -101,7 +102,7 @@ bool game_compatibility::ReadJSON(const QJsonObject& json_data, bool after_downl
m_compat_database.clear();
QJsonObject json_results = json_data["results"].toObject();
const QJsonObject json_results = json_data["results"].toObject();
// Retrieve status data for every valid entry
for (const auto& key : json_results.keys())
@ -112,7 +113,7 @@ bool game_compatibility::ReadJSON(const QJsonObject& json_data, bool after_downl
continue;
}
QJsonObject json_result = json_results[key].toObject();
const QJsonObject json_result = json_results[key].toObject();
// Retrieve compatibility information from json
compat::status status = ::at32(Status_Data, json_result.value("status").toString("NoResult"));
@ -210,15 +211,14 @@ void game_compatibility::RequestCompatibility(bool online)
compat_log.notice("Finished reading database from file: %s", m_filepath);
// Create new map from database
ReadJSON(QJsonDocument::fromJson(content).object(), online);
handle_json(content, online);
return;
}
const std::string url = "https://rpcs3.net/compatibility?api=v1&export";
compat_log.notice("Beginning compatibility database download from: %s", url);
m_downloader->start(url, true, true, tr("Downloading Database"));
m_downloader->start(url, true, true, true, tr("Downloading Database"));
// We want to retrieve a new database, therefore refresh gamelist and indicate that
Q_EMIT DownloadStarted();

View file

@ -138,7 +138,7 @@ private:
std::map<std::string, compat::status> m_compat_database;
/** Creates new map from the database */
bool ReadJSON(const QJsonObject& json_data, bool after_download);
bool handle_json(const QByteArray& data, bool after_download);
public:
/** Handles reads, writes and downloads for the compatibility database */

View file

@ -637,6 +637,12 @@ void game_list_frame::OnParsingFinished()
game.has_hover_pam = true;
}
if (std::string audio_path = sfo_dir + "/SND0.AT3"; file_exists(audio_path))
{
game.info.audio_path = std::move(audio_path);
game.has_audio_file = true;
}
const QString serial = QString::fromStdString(game.info.serial);
m_games_mutex.lock();

View file

@ -109,11 +109,23 @@ void game_list_grid::populate(
}
});
if (play_hover_movies && (game->has_hover_gif || game->has_hover_pam))
if (play_hover_movies && (game->has_hover_gif || game->has_hover_pam || game->has_audio_file))
{
item->set_video_path(game->info.movie_path);
bool check_iso = false;
if (!fs::exists(game->info.movie_path) && is_file_iso(game->info.path))
if (game->has_hover_gif || game->has_hover_pam)
{
item->set_video_path(game->info.movie_path);
check_iso |= !fs::exists(game->info.movie_path);
}
if (game->has_audio_file)
{
item->set_audio_path(game->info.audio_path);
check_iso |= !fs::exists(game->info.audio_path);
}
if (check_iso && is_file_iso(game->info.path))
{
item->set_iso_path(game->info.path);
}

View file

@ -299,11 +299,23 @@ void game_list_table::populate(
}
});
if (play_hover_movies && (game->has_hover_gif || game->has_hover_pam))
if (play_hover_movies && (game->has_hover_gif || game->has_hover_pam || game->has_audio_file))
{
icon_item->set_video_path(game->info.movie_path);
bool check_iso = false;
if (!fs::exists(game->info.movie_path) && is_file_iso(game->info.path))
if (game->has_hover_gif || game->has_hover_pam)
{
icon_item->set_video_path(game->info.movie_path);
check_iso |= !fs::exists(game->info.movie_path);
}
if (game->has_audio_file)
{
icon_item->set_audio_path(game->info.audio_path);
check_iso |= !fs::exists(game->info.audio_path);
}
if (check_iso && is_file_iso(game->info.path))
{
icon_item->set_iso_path(game->info.path);
}

View file

@ -21,6 +21,7 @@ struct gui_game_info
bool has_custom_icon = false;
bool has_hover_gif = false;
bool has_hover_pam = false;
bool has_audio_file = false;
bool icon_in_archive = false;
movie_item_base* item = nullptr;

View file

@ -0,0 +1,155 @@
#include "stdafx.h"
#include "log_level_dialog.h"
#include "emu_settings.h"
#include <QComboBox>
#include <QDialogButtonBox>
#include <QHeaderView>
#include <QLineEdit>
#include <QPushButton>
#include <QVBoxLayout>
LOG_CHANNEL(cfg_log, "CFG");
log_level_dialog::log_level_dialog(QWidget* parent, std::shared_ptr<emu_settings> emu_settings)
: QDialog(parent), m_emu_settings(emu_settings)
{
setWindowTitle(tr("Configure minimum log levels"));
setObjectName("log_level_dialog");
setAttribute(Qt::WA_DeleteOnClose);
setMinimumSize(QSize(700, 400));
const std::set<std::string> channels = logs::get_channels();
std::vector<std::pair<std::string, QString>> levels;
const auto add_level = [&levels](logs::level level, const QString& localized)
{
levels.push_back(std::pair<std::string, QString>(fmt::format("%s", level), localized));
};
add_level(logs::level::always, tr("Always"));
add_level(logs::level::fatal, tr("Fatal"));
add_level(logs::level::error, tr("Error"));
add_level(logs::level::todo, tr("Todo"));
add_level(logs::level::success, tr("Success"));
add_level(logs::level::warning, tr("Warning"));
add_level(logs::level::notice, tr("Notice"));
add_level(logs::level::trace, tr("Trace"));
const std::map<std::string, std::string> current_settings = m_emu_settings->GetMapSetting(emu_settings_type::Log);
for (const auto& [channel, level] : current_settings)
{
if (!channels.contains(channel))
{
cfg_log.warning("log_level_dialog: Ignoring unknown channel '%s' found in config file.", channel);
}
}
m_table = new QTableWidget(static_cast<int>(channels.size()), 2, this);
m_table->setHorizontalHeaderLabels({ tr("Channel"), tr("Level") });
int i = 0;
for (const std::string& channel : channels)
{
QComboBox* combo = new QComboBox();
for (const auto& [level, localized] : levels)
{
combo->addItem(localized, QString::fromStdString(level));
}
connect(combo, &QComboBox::currentIndexChanged, combo, [this, combo, ch = channel](int index)
{
if (index < 0) return;
const QVariant var = combo->itemData(index);
if (!var.canConvert<QString>()) return;
std::map<std::string, std::string> settings = m_emu_settings->GetMapSetting(emu_settings_type::Log);
settings[ch] = var.toString().toStdString();
m_emu_settings->SetMapSetting(emu_settings_type::Log, settings);
});
m_table->setItem(i, 0, new QTableWidgetItem(QString::fromStdString(channel)));
m_table->setCellWidget(i, 1, combo);
i++;
}
QLineEdit* filter_edit = new QLineEdit(this);
filter_edit->setPlaceholderText(tr("Filter channels"));
connect(filter_edit, &QLineEdit::textChanged, this, [this](const QString& text)
{
for (int i = 0; i < m_table->rowCount(); i++)
{
if (QTableWidgetItem* item = m_table->item(i, 0))
{
m_table->setRowHidden(i, !text.isEmpty() && !item->text().contains(text, Qt::CaseInsensitive));
}
}
});
QDialogButtonBox* button_box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::RestoreDefaults);
connect(button_box, &QDialogButtonBox::clicked, this, [this, button_box, old_settings = m_emu_settings->GetMapSetting(emu_settings_type::Log)](QAbstractButton* button)
{
if (button == button_box->button(QDialogButtonBox::Ok))
{
accept();
}
else if (button == button_box->button(QDialogButtonBox::Cancel))
{
m_emu_settings->SetMapSetting(emu_settings_type::Log, old_settings);
reject();
}
else if (button == button_box->button(QDialogButtonBox::RestoreDefaults))
{
m_emu_settings->SetMapSetting(emu_settings_type::Log, m_emu_settings->GetMapSettingDefault(emu_settings_type::Log));
reload_page();
}
});
reload_page();
m_table->resizeColumnsToContents();
m_table->horizontalHeader()->stretchLastSection();
QVBoxLayout* layout = new QVBoxLayout();
layout->addWidget(filter_edit);
layout->addWidget(m_table);
layout->addWidget(button_box);
setLayout(layout);
}
log_level_dialog::~log_level_dialog()
{
}
void log_level_dialog::reload_page()
{
const std::map<std::string, std::string> settings = m_emu_settings->GetMapSetting(emu_settings_type::Log);
const QString def_str = QString::fromStdString(fmt::format("%s", logs::level::_default));
for (int i = 0; i < m_table->rowCount(); i++)
{
QTableWidgetItem* item = m_table->item(i, 0);
if (!item) continue;
const std::string channel = item->text().toStdString();
if (QComboBox* combo = static_cast<QComboBox*>(m_table->cellWidget(i, 1)))
{
combo->blockSignals(true);
combo->setCurrentIndex(combo->findData(def_str));
if (settings.contains(channel))
{
if (const int index = combo->findData(QString::fromStdString(settings.at(channel))); index >= 0)
{
combo->setCurrentIndex(index);
}
}
combo->blockSignals(false);
}
}
}

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