Merge branch 'master' into alcGetString

This commit is contained in:
Megamouse 2025-04-07 15:44:39 +02:00 committed by GitHub
commit 0dd74675f2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
92 changed files with 879 additions and 848 deletions

View file

@ -145,6 +145,8 @@ export MACOSX_DEPLOYMENT_TARGET=14.0
-DCMAKE_SYSTEM_PROCESSOR=arm64 \ -DCMAKE_SYSTEM_PROCESSOR=arm64 \
-DCMAKE_TOOLCHAIN_FILE=buildfiles/cmake/TCDarwinARM64.cmake \ -DCMAKE_TOOLCHAIN_FILE=buildfiles/cmake/TCDarwinARM64.cmake \
-DCMAKE_CXX_FLAGS="-D__MAC_OS_X_VERSION_MIN_REQUIRED=140000" \ -DCMAKE_CXX_FLAGS="-D__MAC_OS_X_VERSION_MIN_REQUIRED=140000" \
-DCMAKE_POLICY_VERSION_MINIMUM=3.5 \
-DCMAKE_OSX_SYSROOT="$(xcrun --sdk macosx --show-sdk-path)" \
-G Ninja -G Ninja
"$BREW_PATH/bin/ninja"; build_status=$?; "$BREW_PATH/bin/ninja"; build_status=$?;

View file

@ -108,6 +108,8 @@ export MACOSX_DEPLOYMENT_TARGET=14.0
-DCMAKE_OSX_ARCHITECTURES=x86_64 \ -DCMAKE_OSX_ARCHITECTURES=x86_64 \
-DCMAKE_IGNORE_PATH="$BREW_PATH/lib" \ -DCMAKE_IGNORE_PATH="$BREW_PATH/lib" \
-DCMAKE_CXX_FLAGS="-D__MAC_OS_X_VERSION_MIN_REQUIRED=140000" \ -DCMAKE_CXX_FLAGS="-D__MAC_OS_X_VERSION_MIN_REQUIRED=140000" \
-DCMAKE_POLICY_VERSION_MINIMUM=3.5 \
-DCMAKE_OSX_SYSROOT="$(xcrun --sdk macosx --show-sdk-path)" \
-G Ninja -G Ninja
"$BREW_PATH/bin/ninja"; build_status=$?; "$BREW_PATH/bin/ninja"; build_status=$?;

View file

@ -25,6 +25,13 @@ if [ "$DEPLOY_APPIMAGE" = "true" ]; then
# Remove libvulkan because it causes issues with gamescope # Remove libvulkan because it causes issues with gamescope
rm -f ./AppDir/usr/lib/libvulkan.so* rm -f ./AppDir/usr/lib/libvulkan.so*
# Remove unused Qt6 libraries
rm -f ./AppDir/usr/lib/libQt6OpenGL.so*
rm -f ./AppDir/usr/lib/libQt6Qml*.so*
rm -f ./AppDir/usr/lib/libQt6Quick.so*
rm -f ./AppDir/usr/lib/libQt6VirtualKeyboard.so*
rm -f ./AppDir/usr/plugins/platforminputcontexts/libqtvirtualkeyboardplugin.so*
# Remove git directory containing local commit history file # Remove git directory containing local commit history file
rm -rf ./AppDir/usr/share/rpcs3/git rm -rf ./AppDir/usr/share/rpcs3/git

View file

@ -22,7 +22,7 @@ QT_SVG_URL="${QT_HOST}${QT_PREFIX}${QT_PREFIX_2}qtsvg${QT_SUFFIX}"
LLVMLIBS_URL="https://github.com/RPCS3/llvm-mirror/releases/download/custom-build-win-${LLVM_VER}/llvmlibs_mt.7z" LLVMLIBS_URL="https://github.com/RPCS3/llvm-mirror/releases/download/custom-build-win-${LLVM_VER}/llvmlibs_mt.7z"
GLSLANG_URL='https://github.com/RPCS3/glslang/releases/latest/download/glslanglibs_mt.7z' GLSLANG_URL='https://github.com/RPCS3/glslang/releases/latest/download/glslanglibs_mt.7z'
VULKAN_SDK_URL="https://www.dropbox.com/scl/fi/sjjh0fc4ld281pjbl2xzu/VulkanSDK-${VULKAN_VER}-Installer.exe?rlkey=f6wzc0lvms5vwkt2z3qabfv9d&dl=1" VULKAN_SDK_URL="https://www.dropbox.com/scl/fi/sjjh0fc4ld281pjbl2xzu/VulkanSDK-${VULKAN_VER}-Installer.exe?rlkey=f6wzc0lvms5vwkt2z3qabfv9d&dl=1"
CCACHE_URL="https://github.com/ccache/ccache/releases/download/v4.10.2/ccache-4.10.2-windows-x86_64.zip" CCACHE_URL="https://github.com/ccache/ccache/releases/download/v4.11.2/ccache-4.11.2-windows-x86_64.zip"
DEP_URLS=" \ DEP_URLS=" \
$QT_BASE_URL \ $QT_BASE_URL \

View file

@ -16,4 +16,4 @@ Submitting your test results for Commercial Games must be done on our forums. Pl
# Contributing # Contributing
Check the [Coding Style Guidelines](https://github.com/RPCS3/rpcs3/wiki/Coding-Style) and [Developer Information](https://github.com/RPCS3/rpcs3/wiki/Developer-Information). If you have any questions, hit us up on our [Discord Server](https://discord.me/RPCS3) in the **#development** channel. Check the [Coding Style Guidelines](https://github.com/RPCS3/rpcs3/wiki/Coding-Style) and [Developer Information](https://github.com/RPCS3/rpcs3/wiki/Developer-Information). If you have any questions, hit us up on our [Discord Server](https://discord.gg/rpcs3) in the **#development** channel.

View file

@ -7,7 +7,7 @@ body:
attributes: attributes:
value: | value: |
# Summary # Summary
Please do not ask for help or report compatibility regressions here, use [RPCS3 Discord server](https://discord.me/RPCS3) or [forums](https://forums.rpcs3.net/) instead. Please do not ask for help or report compatibility regressions here, use [RPCS3 Discord server](https://discord.gg/rpcs3) or [forums](https://forums.rpcs3.net/) instead.
- type: textarea - type: textarea
id: quick-summary id: quick-summary
attributes: attributes:
@ -50,7 +50,7 @@ body:
* Completely close RPCS3 and locate the log file. * Completely close RPCS3 and locate the log file.
RPCS3's Log file will be ```RPCS3.log.gz``` (sometimes shows as RPCS3.log with zip icon) or ```RPCS3.log``` (sometimes shows as RPCS3 wtih notepad icon). RPCS3's Log file will be ```RPCS3.log.gz``` (sometimes shows as RPCS3.log with zip icon) or ```RPCS3.log``` (sometimes shows as RPCS3 wtih notepad icon).
* On Windows it will be in the RPCS3 directory near the executable * On Windows it will be in the ```log``` folder inside your RPCS3 folder.
* On Linux it will be in ```~/.cache/rpcs3/``` * On Linux it will be in ```~/.cache/rpcs3/```
* On MacOS it will be in ```~/Library/Caches/rpcs3```. If you're unable to locate it copy paste the path in Spotlight and hit enter. * On MacOS it will be in ```~/Library/Caches/rpcs3```. If you're unable to locate it copy paste the path in Spotlight and hit enter.
- type: textarea - type: textarea

View file

@ -7,7 +7,7 @@ body:
attributes: attributes:
value: | value: |
# Summary # Summary
Please do not ask for help or report compatibility regressions here, use [RPCS3 Discord server](https://discord.me/RPCS3) or [forums](https://forums.rpcs3.net/) instead. Please do not ask for help or report compatibility regressions here, use [RPCS3 Discord server](https://discord.gg/rpcs3) or [forums](https://forums.rpcs3.net/) instead.
- type: textarea - type: textarea
id: quick-summary id: quick-summary
attributes: attributes:
@ -36,7 +36,7 @@ body:
* Completely close RPCS3 and locate the log file. * Completely close RPCS3 and locate the log file.
RPCS3's Log file will be ```RPCS3.log.gz``` (sometimes shows as RPCS3.log with zip icon) or ```RPCS3.log``` (sometimes shows as RPCS3 wtih notepad icon). RPCS3's Log file will be ```RPCS3.log.gz``` (sometimes shows as RPCS3.log with zip icon) or ```RPCS3.log``` (sometimes shows as RPCS3 wtih notepad icon).
* On Windows it will be in the RPCS3 directory near the executable * On Windows it will be in the ```log``` folder inside your RPCS3 folder.
* On Linux it will be in ```~/.cache/rpcs3/``` * On Linux it will be in ```~/.cache/rpcs3/```
* On MacOS it will be in ```~/Library/Caches/rpcs3```. If you're unable to locate it copy paste the path in Spotlight and hit enter. * On MacOS it will be in ```~/Library/Caches/rpcs3```. If you're unable to locate it copy paste the path in Spotlight and hit enter.
- type: textarea - type: textarea

View file

@ -6,7 +6,7 @@ body:
- type: markdown - type: markdown
attributes: attributes:
value: | value: |
Please do not ask for help or report compatibility regressions here, use [RPCS3 Discord server](https://discord.me/RPCS3) or [forums](https://forums.rpcs3.net/) instead. Please do not ask for help or report compatibility regressions here, use [RPCS3 Discord server](https://discord.gg/rpcs3) or [forums](https://forums.rpcs3.net/) instead.
- type: textarea - type: textarea
id: quick-summary id: quick-summary
attributes: attributes:
@ -31,6 +31,6 @@ body:
* If this feature is something that a game is trying to use, upload a log file for it. * If this feature is something that a game is trying to use, upload a log file for it.
RPCS3's Log file will be ```RPCS3.log.gz``` (sometimes shows as RPCS3.log with zip icon) or ```RPCS3.log``` (sometimes shows as RPCS3 wtih notepad icon). RPCS3's Log file will be ```RPCS3.log.gz``` (sometimes shows as RPCS3.log with zip icon) or ```RPCS3.log``` (sometimes shows as RPCS3 wtih notepad icon).
* On Windows it will be in the RPCS3 directory near the executable * On Windows it will be in the ```log``` folder inside your RPCS3 folder.
* On Linux it will be in ```~/.cache/rpcs3/``` * On Linux it will be in ```~/.cache/rpcs3/```
* On MacOS it will be in ```~/Library/Caches/rpcs3```. If you're unable to locate it copy paste the path in Spotlight and hit enter. * On MacOS it will be in ```~/Library/Caches/rpcs3```. If you're unable to locate it copy paste the path in Spotlight and hit enter.

View file

@ -7,7 +7,7 @@ assignees: ''
--- ---
## Please do not ask for help or report compatibility regressions here, use [RPCS3 Discord server](https://discord.me/RPCS3) or [forums](https://forums.rpcs3.net/) instead. ## Please do not ask for help or report compatibility regressions here, use [RPCS3 Discord server](https://discord.gg/rpcs3) or [forums](https://forums.rpcs3.net/) instead.
You're using the advanced template. You're expected to know what to write in order to fill in all the required information for proper report. You're using the advanced template. You're expected to know what to write in order to fill in all the required information for proper report.

View file

@ -4,7 +4,7 @@ contact_links:
url: https://rpcs3.net/quickstart url: https://rpcs3.net/quickstart
about: Everything you need to know to install and configure emulator, and add games about: Everything you need to know to install and configure emulator, and add games
- name: Ask for help - name: Ask for help
url: https://discord.me/RPCS3 url: https://discord.gg/rpcs3
about: If you have some questions or need help, please use our Discord server instead of GitHub about: If you have some questions or need help, please use our Discord server instead of GitHub
- name: Report game compatibility - name: Report game compatibility
url: https://forums.rpcs3.net/thread-196671.html url: https://forums.rpcs3.net/thread-196671.html

18
.github/PR-BUILD.md vendored
View file

@ -1,18 +0,0 @@
## How to test a PR build
Please take into account, that RPCS3 build usually takes some time (about 15 mins), so you can't access a build if a PR was just submitted.
- Open a PR you want to test
- Scroll to the very bottom and locate the **Checks** section
- Click on **Show all checks**
You are supposed to see something like this
![image](https://user-images.githubusercontent.com/10283761/116630952-2cd99e00-a94c-11eb-933e-986d6020ca92.png)
- Click on __Details__ on either **Cirrus Linux GCC** or **Cirrus Windows**
- Click **View more details on Cirrus CI** at the very bottom
![image](https://user-images.githubusercontent.com/10283761/116631111-5e526980-a94c-11eb-95f7-751e6f15e1ea.png)
- Click on the download button for **Artifact** on the **Artifacts** block
![image](https://user-images.githubusercontent.com/10283761/116631322-bee1a680-a94c-11eb-89a3-be365783582e.png)
- Congratulations! You are now downloading an RPCS3 build for that specific PR.
__Please note that PR builds are not supposed to be stable because they contain new changesets.__

View file

@ -1,3 +0,0 @@
<!-- Please include a summary of the change and which issue is fixed. -->
[How to test this PR](.github/PR-BUILD.md)

View file

@ -25,17 +25,17 @@ jobs:
matrix: matrix:
include: include:
- os: ubuntu-24.04 - os: ubuntu-24.04
docker_img: "rpcs3/rpcs3-ci-jammy:1.3" docker_img: "rpcs3/rpcs3-ci-jammy:1.4"
build_sh: "/rpcs3/.ci/build-linux.sh" build_sh: "/rpcs3/.ci/build-linux.sh"
compiler: clang compiler: clang
UPLOAD_COMMIT_HASH: d812f1254a1157c80fd402f94446310560f54e5f UPLOAD_COMMIT_HASH: d812f1254a1157c80fd402f94446310560f54e5f
UPLOAD_REPO_FULL_NAME: "rpcs3/rpcs3-binaries-linux" UPLOAD_REPO_FULL_NAME: "rpcs3/rpcs3-binaries-linux"
- os: ubuntu-24.04 - os: ubuntu-24.04
docker_img: "rpcs3/rpcs3-ci-jammy:1.3" docker_img: "rpcs3/rpcs3-ci-jammy:1.4"
build_sh: "/rpcs3/.ci/build-linux.sh" build_sh: "/rpcs3/.ci/build-linux.sh"
compiler: gcc compiler: gcc
- os: ubuntu-24.04-arm - os: ubuntu-24.04-arm
docker_img: "rpcs3/rpcs3-ci-jammy-aarch64:1.3" docker_img: "rpcs3/rpcs3-ci-jammy-aarch64:1.4"
build_sh: "/rpcs3/.ci/build-linux-aarch64.sh" build_sh: "/rpcs3/.ci/build-linux-aarch64.sh"
compiler: clang compiler: clang
UPLOAD_COMMIT_HASH: a1d35836e8d45bfc6f63c26f0a3e5d46ef622fe1 UPLOAD_COMMIT_HASH: a1d35836e8d45bfc6f63c26f0a3e5d46ef622fe1
@ -111,7 +111,7 @@ jobs:
LLVM_VER: '19.1.7' LLVM_VER: '19.1.7'
VULKAN_VER: '1.3.268.0' VULKAN_VER: '1.3.268.0'
VULKAN_SDK_SHA: '8459ef49bd06b697115ddd3d97c9aec729e849cd775f5be70897718a9b3b9db5' VULKAN_SDK_SHA: '8459ef49bd06b697115ddd3d97c9aec729e849cd775f5be70897718a9b3b9db5'
CCACHE_SHA: '6252f081876a9a9f700fae13a5aec5d0d486b28261d7f1f72ac11c7ad9df4da9' CCACHE_SHA: '1f39f3ad5aae3fe915e99ad1302633bc8f6718e58fa7c0de2b0ba7e080f0f08c'
CCACHE_BIN_DIR: 'C:\ccache_bin' CCACHE_BIN_DIR: 'C:\ccache_bin'
CCACHE_DIR: 'C:\ccache' CCACHE_DIR: 'C:\ccache'
CCACHE_INODECACHE: 'true' CCACHE_INODECACHE: 'true'

2
3rdparty/FAudio vendored

@ -1 +1 @@
Subproject commit 486e33eef3f282e4ce3d29f32ded3e67bacdbe5c Subproject commit 091c6b4693ce507ac48037836a5a884e35cd2860

View file

@ -1,4 +1,3 @@
cmake_minimum_required(VERSION 2.8.12)
project(moltenvk NONE) project(moltenvk NONE)
include(ExternalProject) include(ExternalProject)

@ -1 +1 @@
Subproject commit 90191edd20bb877c5cbddfdac7ec0fe49ad93727 Subproject commit dc7d7054a5b4f3bec1dc23a42fd616a0847af948

View file

@ -9,5 +9,7 @@ if (USE_DISCORD_RPC AND (WIN32 OR CMAKE_SYSTEM MATCHES "Linux" OR APPLE))
set(WARNINGS_AS_ERRORS FALSE CACHE BOOL "When enabled, compiles with `-Werror` (on *nix platforms).") set(WARNINGS_AS_ERRORS FALSE CACHE BOOL "When enabled, compiles with `-Werror` (on *nix platforms).")
add_subdirectory(discord-rpc EXCLUDE_FROM_ALL) add_subdirectory(discord-rpc EXCLUDE_FROM_ALL)
target_include_directories(3rdparty_discordRPC INTERFACE discord-rpc/include)
target_compile_definitions(3rdparty_discordRPC INTERFACE -DWITH_DISCORD_RPC)
target_link_libraries(3rdparty_discordRPC INTERFACE discord-rpc) target_link_libraries(3rdparty_discordRPC INTERFACE discord-rpc)
endif() endif()

@ -1 +1 @@
Subproject commit 171b2142ac8acdf016c231e36dc7a8d48daff19c Subproject commit 3dc2c326cb4dc5815c6069970c13154898f58d48

@ -1 +1 @@
Subproject commit f6864924f76e1a0b4abaefc76ae2ed22b1a8916e Subproject commit 877399b2b2cf21e67554ed9046410f268ce1d1b2

View file

@ -1,5 +1,3 @@
cmake_minimum_required(VERSION 3.0)
project(libusb) project(libusb)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules")

View file

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.16.9) cmake_minimum_required(VERSION 3.28)
project(rpcs3 LANGUAGES C CXX) project(rpcs3 LANGUAGES C CXX)

View file

@ -4,7 +4,7 @@ RPCS3
[![Azure Build Status](https://dev.azure.com/nekotekina/nekotekina/_apis/build/status/RPCS3.rpcs3?branchName=master)](https://dev.azure.com/nekotekina/nekotekina/_build?definitionId=8&_a=summary&repositoryFilter=4) [![Azure Build Status](https://dev.azure.com/nekotekina/nekotekina/_apis/build/status/RPCS3.rpcs3?branchName=master)](https://dev.azure.com/nekotekina/nekotekina/_build?definitionId=8&_a=summary&repositoryFilter=4)
[![Cirrus CI - Base Branch Build Status](https://img.shields.io/cirrus/github/RPCS3/rpcs3/master?label=Cirrus%20CI&logo=cirrus-ci)](https://cirrus-ci.com/github/RPCS3/rpcs3) [![Cirrus CI - Base Branch Build Status](https://img.shields.io/cirrus/github/RPCS3/rpcs3/master?label=Cirrus%20CI&logo=cirrus-ci)](https://cirrus-ci.com/github/RPCS3/rpcs3)
[![GitHub Actions](https://img.shields.io/github/actions/workflow/status/RPCS3/rpcs3/rpcs3.yml?branch=master&logo=github&label=Actions)](https://github.com/RPCS3/rpcs3/actions/workflows/rpcs3.yml) [![GitHub Actions](https://img.shields.io/github/actions/workflow/status/RPCS3/rpcs3/rpcs3.yml?branch=master&logo=github&label=Actions)](https://github.com/RPCS3/rpcs3/actions/workflows/rpcs3.yml)
[![RPCS3 Discord Server](https://img.shields.io/discord/272035812277878785?color=5865F2&label=RPCS3%20Discord&logo=discord&logoColor=white)](https://discord.me/rpcs3) [![RPCS3 Discord Server](https://img.shields.io/discord/272035812277878785?color=5865F2&label=RPCS3%20Discord&logo=discord&logoColor=white)](https://discord.gg/rpcs3)
The world's first free and open-source PlayStation 3 emulator/debugger, written in C++ for Windows, Linux, macOS and FreeBSD. The world's first free and open-source PlayStation 3 emulator/debugger, written in C++ for Windows, Linux, macOS and FreeBSD.
@ -34,7 +34,7 @@ See [BUILDING.md](BUILDING.md) for more information about how to setup an enviro
Check our friendly [quickstart](https://rpcs3.net/quickstart) guide to make sure your computer meets the minimum system requirements to run RPCS3. Check our friendly [quickstart](https://rpcs3.net/quickstart) guide to make sure your computer meets the minimum system requirements to run RPCS3.
Don't forget to have your graphics driver up to date and to install the [Visual C++ Redistributable Packages for Visual Studio 2019](https://aka.ms/vs/16/release/VC_redist.x64.exe) if you are a Windows user. Don't forget to have your graphics driver up to date and to install the [Visual C++ Redistributable Packages for Visual Studio 2022](https://aka.ms/vs/17/release/VC_redist.x64.exe) if you are a Windows user.
## License ## License

View file

@ -40,13 +40,13 @@ jobs:
# displayName: ccache # displayName: ccache
# - bash: | # - bash: |
# docker pull --quiet rpcs3/rpcs3-ci-jammy:1.3 # docker pull --quiet rpcs3/rpcs3-ci-jammy:1.4
# docker run \ # docker run \
# -v $(pwd):/rpcs3 \ # -v $(pwd):/rpcs3 \
# --env-file .ci/docker.env \ # --env-file .ci/docker.env \
# -v $CCACHE_DIR:/root/.ccache \ # -v $CCACHE_DIR:/root/.ccache \
# -v $BUILD_ARTIFACTSTAGINGDIRECTORY:/root/artifacts \ # -v $BUILD_ARTIFACTSTAGINGDIRECTORY:/root/artifacts \
# rpcs3/rpcs3-ci-jammy:1.3 \ # rpcs3/rpcs3-ci-jammy:1.4 \
# /rpcs3/.ci/build-linux.sh # /rpcs3/.ci/build-linux.sh
# displayName: Docker setup and build # displayName: Docker setup and build

View file

@ -546,6 +546,7 @@ target_sources(rpcs3_emu PRIVATE
RSX/Overlays/overlay_trophy_notification.cpp RSX/Overlays/overlay_trophy_notification.cpp
RSX/Overlays/overlay_user_list_dialog.cpp RSX/Overlays/overlay_user_list_dialog.cpp
RSX/Overlays/overlay_utils.cpp RSX/Overlays/overlay_utils.cpp
RSX/Overlays/overlay_video.cpp
RSX/Overlays/Shaders/shader_loading_dialog.cpp RSX/Overlays/Shaders/shader_loading_dialog.cpp
RSX/Overlays/Shaders/shader_loading_dialog_native.cpp RSX/Overlays/Shaders/shader_loading_dialog_native.cpp
RSX/Program/CgBinaryFragmentProgram.cpp RSX/Program/CgBinaryFragmentProgram.cpp

View file

@ -195,7 +195,7 @@ struct audio_port
// Handle copy ctor of atomic var // Handle copy ctor of atomic var
audio_port(const audio_port& r) audio_port(const audio_port& r)
{ {
std::memcpy(this, &r, sizeof(r)); std::memcpy(static_cast<void*>(this), &r, sizeof(r));
} }
ENABLE_BITWISE_SERIALIZATION; ENABLE_BITWISE_SERIALIZATION;

View file

@ -244,7 +244,7 @@ static std::vector<SaveDataEntry> get_save_entries(const std::string& base_dir,
continue; continue;
} }
SaveDataEntry save_entry; SaveDataEntry save_entry {};
save_entry.dirName = psf::get_string(psf, "SAVEDATA_DIRECTORY"); save_entry.dirName = psf::get_string(psf, "SAVEDATA_DIRECTORY");
save_entry.listParam = psf::get_string(psf, "SAVEDATA_LIST_PARAM"); save_entry.listParam = psf::get_string(psf, "SAVEDATA_LIST_PARAM");
save_entry.title = psf::get_string(psf, "TITLE"); save_entry.title = psf::get_string(psf, "TITLE");
@ -307,7 +307,7 @@ static error_code select_and_delete(ppu_thread& ppu)
// Display a blocking Save Data List asynchronously in the GUI thread. // Display a blocking Save Data List asynchronously in the GUI thread.
if (auto save_dialog = Emu.GetCallbacks().get_save_dialog()) if (auto save_dialog = Emu.GetCallbacks().get_save_dialog())
{ {
selected = save_dialog->ShowSaveDataList(save_entries, focused, SAVEDATA_OP_LIST_DELETE, vm::null, g_fxo->get<savedata_manager>().enable_overlay); selected = save_dialog->ShowSaveDataList(base_dir, save_entries, focused, SAVEDATA_OP_LIST_DELETE, vm::null, g_fxo->get<savedata_manager>().enable_overlay);
} }
// Reschedule after a blocking dialog returns // Reschedule after a blocking dialog returns
@ -326,7 +326,7 @@ static error_code select_and_delete(ppu_thread& ppu)
focused = save_entries.empty() ? -1 : selected; focused = save_entries.empty() ? -1 : selected;
// Get information from the selected entry // Get information from the selected entry
SaveDataEntry entry = save_entries[selected]; const SaveDataEntry& entry = ::at32(save_entries, selected);
const std::string info = entry.title + "\n" + entry.subtitle + "\n" + entry.details; const std::string info = entry.title + "\n" + entry.subtitle + "\n" + entry.details;
// Reusable display message string // Reusable display message string
@ -760,7 +760,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
result->userdata = userdata; // probably should be assigned only once (allows the callback to change it) result->userdata = userdata; // probably should be assigned only once (allows the callback to change it)
SaveDataEntry save_entry; SaveDataEntry save_entry {};
if (setList) if (setList)
{ {
@ -820,7 +820,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
break; break;
} }
SaveDataEntry save_entry2; SaveDataEntry save_entry2 {};
save_entry2.dirName = psf::get_string(psf, "SAVEDATA_DIRECTORY"); save_entry2.dirName = psf::get_string(psf, "SAVEDATA_DIRECTORY");
save_entry2.listParam = psf::get_string(psf, "SAVEDATA_LIST_PARAM"); save_entry2.listParam = psf::get_string(psf, "SAVEDATA_LIST_PARAM");
save_entry2.title = psf::get_string(psf, "TITLE"); save_entry2.title = psf::get_string(psf, "TITLE");
@ -1183,7 +1183,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
// Display a blocking Save Data List asynchronously in the GUI thread. // Display a blocking Save Data List asynchronously in the GUI thread.
if (auto save_dialog = Emu.GetCallbacks().get_save_dialog()) if (auto save_dialog = Emu.GetCallbacks().get_save_dialog())
{ {
selected = save_dialog->ShowSaveDataList(save_entries, focused, operation, listSet, g_fxo->get<savedata_manager>().enable_overlay); selected = save_dialog->ShowSaveDataList(base_dir, save_entries, focused, operation, listSet, g_fxo->get<savedata_manager>().enable_overlay);
} }
else else
{ {
@ -1214,8 +1214,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
else else
{ {
// Get information from the selected entry // Get information from the selected entry
SaveDataEntry entry = save_entries[selected]; message = get_confirmation_message(operation, ::at32(save_entries, selected));
message = get_confirmation_message(operation, entry);
} }
// Yield before a blocking dialog is being spawned // Yield before a blocking dialog is being spawned
@ -1345,14 +1344,14 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
else else
{ {
// Get information from the selected entry // Get information from the selected entry
SaveDataEntry entry = save_entries[selected]; message = get_confirmation_message(operation, ::at32(save_entries, selected));
message = get_confirmation_message(operation, entry);
} }
// Yield before a blocking dialog is being spawned // Yield before a blocking dialog is being spawned
lv2_obj::sleep(ppu); lv2_obj::sleep(ppu);
// Get user confirmation by opening a blocking dialog // Get user confirmation by opening a blocking dialog
// TODO: show fixedSet->newIcon
s32 return_code = CELL_MSGDIALOG_BUTTON_NONE; s32 return_code = CELL_MSGDIALOG_BUTTON_NONE;
error_code res = open_msg_dialog(true, CELL_MSGDIALOG_TYPE_SE_TYPE_NORMAL | CELL_MSGDIALOG_TYPE_BUTTON_TYPE_YESNO, vm::make_str(message), msg_dialog_source::_cellSaveData, vm::null, vm::null, vm::null, &return_code); error_code res = open_msg_dialog(true, CELL_MSGDIALOG_TYPE_SE_TYPE_NORMAL | CELL_MSGDIALOG_TYPE_BUTTON_TYPE_YESNO, vm::make_str(message), msg_dialog_source::_cellSaveData, vm::null, vm::null, vm::null, &return_code);

View file

@ -361,5 +361,5 @@ class SaveDialogBase
public: public:
virtual ~SaveDialogBase(); virtual ~SaveDialogBase();
virtual s32 ShowSaveDataList(std::vector<SaveDataEntry>& save_entries, s32 focused, u32 op, vm::ptr<CellSaveDataListSet> listSet, bool enable_overlay) = 0; virtual s32 ShowSaveDataList(const std::string& base_dir, std::vector<SaveDataEntry>& save_entries, s32 focused, u32 op, vm::ptr<CellSaveDataListSet> listSet, bool enable_overlay) = 0;
}; };

View file

@ -4956,9 +4956,9 @@ bool ppu_initialize(const ppu_module<lv2_obj>& info, bool check_only, u64 file_s
return +code_ptr; return +code_ptr;
} }
constexpr auto abs_diff = [](u64 a, u64 b) { return a <= b ? b - a : a - b; }; [[maybe_unused]] constexpr auto abs_diff = [](u64 a, u64 b) { return a <= b ? b - a : a - b; };
auto write_le = [](u8*& code, auto value) [[maybe_unused]] auto write_le = [](u8*& code, auto value)
{ {
write_to_ptr<le_t<std::remove_cvref_t<decltype(value)>>>(code, value); write_to_ptr<le_t<std::remove_cvref_t<decltype(value)>>>(code, value);
code += sizeof(value); code += sizeof(value);
@ -5823,7 +5823,7 @@ static void ppu_initialize2(jit_compiler& jit, const ppu_module<lv2_obj>& module
min_addr = std::min<u32>(min_addr, mod_func.addr); min_addr = std::min<u32>(min_addr, mod_func.addr);
// Translate // Translate
if (const auto func = translator.Translate(mod_func)) if ([[maybe_unused]] const auto func = translator.Translate(mod_func))
{ {
#ifdef ARCH_X64 // TODO #ifdef ARCH_X64 // TODO
// Run optimization passes // Run optimization passes
@ -5841,7 +5841,7 @@ static void ppu_initialize2(jit_compiler& jit, const ppu_module<lv2_obj>& module
// Run this only in one module for all functions compiled // Run this only in one module for all functions compiled
if (module_part.jit_bounds) if (module_part.jit_bounds)
{ {
if (const auto func = translator.GetSymbolResolver(module_part)) if ([[maybe_unused]] const auto func = translator.GetSymbolResolver(module_part))
{ {
#ifdef ARCH_X64 // TODO #ifdef ARCH_X64 // TODO
// Run optimization passes // Run optimization passes

View file

@ -1290,7 +1290,7 @@ void PPUTranslator::VMADDFP(ppu_opcode_t op)
void PPUTranslator::VMAXFP(ppu_opcode_t op) void PPUTranslator::VMAXFP(ppu_opcode_t op)
{ {
const auto [a, b] = get_vrs<f32[4]>(op.va, op.vb); const auto [a, b] = get_vrs<f32[4]>(op.va, op.vb);
set_vr(op.vd, vec_handle_result(bitcast<f32[4]>(bitcast<u32[4]>(fmax(a, b)) & bitcast<u32[4]>(fmax(b, a))))); set_vr(op.vd, vec_handle_result(select(fcmp_ord(a < b) | fcmp_uno(b != b), b, a)));
} }
void PPUTranslator::VMAXSB(ppu_opcode_t op) void PPUTranslator::VMAXSB(ppu_opcode_t op)
@ -1352,7 +1352,7 @@ void PPUTranslator::VMHRADDSHS(ppu_opcode_t op)
void PPUTranslator::VMINFP(ppu_opcode_t op) void PPUTranslator::VMINFP(ppu_opcode_t op)
{ {
const auto [a, b] = get_vrs<f32[4]>(op.va, op.vb); const auto [a, b] = get_vrs<f32[4]>(op.va, op.vb);
set_vr(op.vd, vec_handle_result(bitcast<f32[4]>(bitcast<u32[4]>(fmin(a, b)) | bitcast<u32[4]>(fmin(b, a))))); set_vr(op.vd, vec_handle_result(select(fcmp_ord(a > b) | fcmp_uno(b != b), b, a)));
} }
void PPUTranslator::VMINSB(ppu_opcode_t op) void PPUTranslator::VMINSB(ppu_opcode_t op)

View file

@ -1237,7 +1237,7 @@ void spu_thread::dump_regs(std::string& ret, std::any& /*custom_data*/) const
if (const_value != r) if (const_value != r)
{ {
// Expectation of pretictable code path has not been met (such as a branch directly to the instruction) // Expectation of predictable code path has not been met (such as a branch directly to the instruction)
is_const = false; is_const = false;
} }
@ -1447,7 +1447,7 @@ std::vector<std::pair<u32, u32>> spu_thread::dump_callstack_list() const
if (v != v128::from32r(addr)) if (v != v128::from32r(addr))
{ {
// 1) Non-zero lower words are invalid (because BRSL-like instructions generate only zeroes) // 1) Non-zero lower words are invalid (because BRSL-like instructions generate only zeroes)
// 2) Bits normally masked out by indirect braches are considered invalid // 2) Bits normally masked out by indirect branches are considered invalid
return true; return true;
} }

View file

@ -752,6 +752,22 @@ void PadHandlerBase::process()
pad->move_data.orientation_enabled = b_has_orientation && device->config && device->config->orientation_enabled.get(); pad->move_data.orientation_enabled = b_has_orientation && device->config && device->config->orientation_enabled.get();
// Disable pad vibration if no new data was sent for 3 seconds
if (pad->m_last_rumble_time_us > 0)
{
std::lock_guard lock(pad::g_pad_mutex);
if ((get_system_time() - pad->m_last_rumble_time_us) > 3'000'000)
{
for (VibrateMotor& motor : pad->m_vibrateMotors)
{
motor.m_value = 0;
}
pad->m_last_rumble_time_us = 0;
}
}
const connection status = update_connection(device); const connection status = update_connection(device);
switch (status) switch (status)

View file

@ -522,6 +522,8 @@ struct Pad
s32 m_orientation_reset_button_index{-1}; // Special button index. -1 if not set. s32 m_orientation_reset_button_index{-1}; // Special button index. -1 if not set.
bool get_orientation_reset_button_active(); bool get_orientation_reset_button_active();
u64 m_last_rumble_time_us{0};
// Cable State: 0 - 1 plugged in ? // Cable State: 0 - 1 plugged in ?
u8 m_cable_state{0}; u8 m_cable_state{0};

View file

@ -483,8 +483,6 @@ namespace vm
} }
} }
bool to_prepare_memory = true;
for (u64 i = 0;; i++) for (u64 i = 0;; i++)
{ {
auto& bits = get_range_lock_bits(true); auto& bits = get_range_lock_bits(true);
@ -512,22 +510,11 @@ namespace vm
if (i < 100) if (i < 100)
{ {
if (to_prepare_memory)
{
// We have some spare time, prepare cache lines (todo: reservation tests here)
utils::prefetch_write(vm::get_super_ptr(addr));
utils::prefetch_write(vm::get_super_ptr(addr) + 64);
to_prepare_memory = false;
}
busy_wait(200); busy_wait(200);
} }
else else
{ {
std::this_thread::yield(); std::this_thread::yield();
// Thread may have been switched or the cache clue has been undermined, cache needs to be prapred again
to_prepare_memory = true;
} }
} }
@ -591,13 +578,6 @@ namespace vm
break; break;
} }
if (to_prepare_memory)
{
utils::prefetch_write(vm::get_super_ptr(addr));
utils::prefetch_write(vm::get_super_ptr(addr) + 64);
to_prepare_memory = false;
}
utils::pause(); utils::pause();
} }
@ -607,13 +587,6 @@ namespace vm
{ {
while (!(ptr->state & cpu_flag::wait)) while (!(ptr->state & cpu_flag::wait))
{ {
if (to_prepare_memory)
{
utils::prefetch_write(vm::get_super_ptr(addr));
utils::prefetch_write(vm::get_super_ptr(addr) + 64);
to_prepare_memory = false;
}
utils::pause(); utils::pause();
} }
} }

View file

@ -218,12 +218,12 @@ namespace gl
m_input_filter = gl::filter::linear; m_input_filter = gl::filter::linear;
} }
gl::texture_view* ui_overlay_renderer::load_simple_image(rsx::overlays::image_info* desc, bool temp_resource, u32 owner_uid) 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); 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->get_data(), gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
GLenum remap[] = { GL_RED, GL_ALPHA, GL_BLUE, GL_GREEN }; const GLenum remap[] = { GL_RED, GL_ALPHA, GL_BLUE, GL_GREEN };
auto view = std::make_unique<gl::texture_view>(tex.get(), remap); auto view = std::make_unique<gl::texture_view>(tex.get(), remap);
auto result = view.get(); auto result = view.get();
@ -234,7 +234,7 @@ namespace gl
} }
else else
{ {
u64 key = reinterpret_cast<u64>(desc); const u64 key = reinterpret_cast<u64>(desc);
temp_image_cache[key] = std::make_pair(owner_uid, std::move(tex)); temp_image_cache[key] = std::make_pair(owner_uid, std::move(tex));
temp_view_cache[key] = std::move(view); temp_view_cache[key] = std::move(view);
} }
@ -318,13 +318,22 @@ namespace gl
return result; return result;
} }
gl::texture_view* ui_overlay_renderer::find_temp_image(rsx::overlays::image_info* desc, u32 owner_uid) gl::texture_view* ui_overlay_renderer::find_temp_image(rsx::overlays::image_info_base* desc, u32 owner_uid)
{ {
auto key = reinterpret_cast<u64>(desc); const bool dirty = std::exchange(desc->dirty, false);
const u64 key = reinterpret_cast<u64>(desc);
auto cached = temp_view_cache.find(key); auto cached = temp_view_cache.find(key);
if (cached != temp_view_cache.end()) if (cached != temp_view_cache.end())
{ {
return cached->second.get(); gl::texture_view* view = cached->second.get();
if (dirty)
{
view->image()->copy_from(desc->get_data(), gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
}
return view;
} }
return load_simple_image(desc, true, owner_uid); return load_simple_image(desc, true, owner_uid);
@ -420,7 +429,7 @@ namespace gl
} }
case rsx::overlays::image_resource_id::raw_image: case rsx::overlays::image_resource_id::raw_image:
{ {
cmd_->bind_texture(31, GL_TEXTURE_2D, find_temp_image(static_cast<rsx::overlays::image_info*>(cmd.config.external_data_ref), ui.uid)->id()); cmd_->bind_texture(31, GL_TEXTURE_2D, find_temp_image(static_cast<rsx::overlays::image_info_base*>(cmd.config.external_data_ref), ui.uid)->id());
break; break;
} }
case rsx::overlays::image_resource_id::font_file: case rsx::overlays::image_resource_id::font_file:

View file

@ -75,7 +75,7 @@ namespace gl
ui_overlay_renderer(); ui_overlay_renderer();
gl::texture_view* load_simple_image(rsx::overlays::image_info* desc, bool temp_resource, u32 owner_uid); gl::texture_view* load_simple_image(rsx::overlays::image_info_base* desc, bool temp_resource, u32 owner_uid);
void create(); void create();
void destroy(); void destroy();
@ -84,7 +84,7 @@ namespace gl
gl::texture_view* find_font(rsx::overlays::font* font); gl::texture_view* find_font(rsx::overlays::font* font);
gl::texture_view* find_temp_image(rsx::overlays::image_info* desc, u32 owner_uid); gl::texture_view* find_temp_image(rsx::overlays::image_info_base* desc, u32 owner_uid);
void set_primitive_type(rsx::overlays::primitive_type type); void set_primitive_type(rsx::overlays::primitive_type type);

View file

@ -40,7 +40,7 @@ namespace rsx
{ {
update_value(); update_value();
if (!is_compiled) if (!is_compiled())
{ {
const f32 col = m_last_value ? 1.0f : 0.3f; const f32 col = m_last_value ? 1.0f : 0.3f;
const f32 bkg = m_last_value ? 0.3f : 1.0f; const f32 bkg = m_last_value ? 0.3f : 1.0f;

View file

@ -64,7 +64,7 @@ namespace rsx
if (const T new_value = m_setting->get(); new_value != m_last_value || initializing) if (const T new_value = m_setting->get(); new_value != m_last_value || initializing)
{ {
m_last_value = new_value; m_last_value = new_value;
is_compiled = false; m_is_compiled = false;
} }
} }
} }
@ -101,7 +101,7 @@ namespace rsx
{ {
this->update_value(); this->update_value();
if (!this->is_compiled) if (!this->is_compiled())
{ {
const std::string value_text = Emu.GetCallbacks().get_localized_setting(home_menu_setting<T, cfg::_enum<T>>::m_setting, static_cast<u32>(this->m_last_value)); const std::string value_text = Emu.GetCallbacks().get_localized_setting(home_menu_setting<T, cfg::_enum<T>>::m_setting, static_cast<u32>(this->m_last_value));
m_dropdown.set_text(value_text); m_dropdown.set_text(value_text);
@ -145,7 +145,7 @@ namespace rsx
{ {
this->update_value(); this->update_value();
if (!this->is_compiled) if (!this->is_compiled())
{ {
const f64 percentage = std::clamp((this->m_last_value - static_cast<T>(m_minimum)) / std::fabs(m_maximum - m_minimum), 0.0, 1.0); const f64 percentage = std::clamp((this->m_last_value - static_cast<T>(m_minimum)) / std::fabs(m_maximum - m_minimum), 0.0, 1.0);
m_slider.set_pos(m_slider.x, this->y + (this->h - m_slider.h) / 2); m_slider.set_pos(m_slider.x, this->y + (this->h - m_slider.h) / 2);

View file

@ -44,7 +44,7 @@ namespace rsx
compiled_resource& home_menu_message_box::get_compiled() compiled_resource& home_menu_message_box::get_compiled()
{ {
if (!is_compiled) if (!is_compiled())
{ {
compiled_resource& compiled = overlay_element::get_compiled(); compiled_resource& compiled = overlay_element::get_compiled();
compiled.add(m_label.get_compiled()); compiled.add(m_label.get_compiled());

View file

@ -258,9 +258,9 @@ namespace rsx
compiled_resource& home_menu_page::get_compiled() compiled_resource& home_menu_page::get_compiled()
{ {
if (!is_compiled || (m_message_box && !m_message_box->is_compiled)) if (!is_compiled() || (m_message_box && !m_message_box->is_compiled()))
{ {
is_compiled = false; m_is_compiled = false;
if (home_menu_page* page = get_current_page(false)) if (home_menu_page* page = get_current_page(false))
{ {
@ -281,7 +281,7 @@ namespace rsx
} }
} }
is_compiled = true; m_is_compiled = true;
} }
return compiled_resources; return compiled_resources;

View file

@ -58,7 +58,7 @@ namespace rsx
compiled_resource& animated_icon::get_compiled() compiled_resource& animated_icon::get_compiled()
{ {
if (!is_compiled) if (!is_compiled())
{ {
compiled_resources = image_view::get_compiled(); compiled_resources = image_view::get_compiled();
} }

View file

@ -302,7 +302,7 @@ namespace rsx
void overlay_element::refresh() void overlay_element::refresh()
{ {
// Just invalidate for draw when get_compiled() is called // Just invalidate for draw when get_compiled() is called
is_compiled = false; m_is_compiled = false;
} }
void overlay_element::translate(s16 _x, s16 _y) void overlay_element::translate(s16 _x, s16 _y)
@ -310,7 +310,7 @@ namespace rsx
x += _x; x += _x;
y += _y; y += _y;
is_compiled = false; m_is_compiled = false;
} }
void overlay_element::scale(f32 _x, f32 _y, bool origin_scaling) void overlay_element::scale(f32 _x, f32 _y, bool origin_scaling)
@ -324,7 +324,7 @@ namespace rsx
w = static_cast<u16>(_x * w); w = static_cast<u16>(_x * w);
h = static_cast<u16>(_y * h); h = static_cast<u16>(_y * h);
is_compiled = false; m_is_compiled = false;
} }
void overlay_element::set_pos(s16 _x, s16 _y) void overlay_element::set_pos(s16 _x, s16 _y)
@ -332,7 +332,7 @@ namespace rsx
x = _x; x = _x;
y = _y; y = _y;
is_compiled = false; m_is_compiled = false;
} }
void overlay_element::set_size(u16 _w, u16 _h) void overlay_element::set_size(u16 _w, u16 _h)
@ -340,7 +340,7 @@ namespace rsx
w = _w; w = _w;
h = _h; h = _h;
is_compiled = false; m_is_compiled = false;
} }
void overlay_element::set_padding(u16 left, u16 right, u16 top, u16 bottom) void overlay_element::set_padding(u16 left, u16 right, u16 top, u16 bottom)
@ -350,13 +350,13 @@ namespace rsx
padding_top = top; padding_top = top;
padding_bottom = bottom; padding_bottom = bottom;
is_compiled = false; m_is_compiled = false;
} }
void overlay_element::set_padding(u16 padding) void overlay_element::set_padding(u16 padding)
{ {
padding_left = padding_right = padding_top = padding_bottom = padding; padding_left = padding_right = padding_top = padding_bottom = padding;
is_compiled = false; m_is_compiled = false;
} }
// NOTE: Functions as a simple position offset. Top left corner is the anchor. // NOTE: Functions as a simple position offset. Top left corner is the anchor.
@ -365,25 +365,36 @@ namespace rsx
margin_left = left; margin_left = left;
margin_top = top; margin_top = top;
is_compiled = false; m_is_compiled = false;
} }
void overlay_element::set_margin(u16 margin) void overlay_element::set_margin(u16 margin)
{ {
margin_left = margin_top = margin; margin_left = margin_top = margin;
is_compiled = false; m_is_compiled = false;
} }
void overlay_element::set_text(const std::string& text) void overlay_element::set_text(const std::string& text)
{ {
this->text = utf8_to_u32string(text); std::u32string new_text = utf8_to_u32string(text);
is_compiled = false; const bool is_dirty = this->text != new_text;
this->text = std::move(new_text);
if (is_dirty)
{
m_is_compiled = false;
}
} }
void overlay_element::set_unicode_text(const std::u32string& text) void overlay_element::set_unicode_text(const std::u32string& text)
{ {
const bool is_dirty = this->text != text;
this->text = text; this->text = text;
is_compiled = false;
if (is_dirty)
{
m_is_compiled = false;
}
} }
void overlay_element::set_text(localized_string_id id) void overlay_element::set_text(localized_string_id id)
@ -394,19 +405,19 @@ namespace rsx
void overlay_element::set_font(const char* font_name, u16 font_size) void overlay_element::set_font(const char* font_name, u16 font_size)
{ {
font_ref = fontmgr::get(font_name, font_size); font_ref = fontmgr::get(font_name, font_size);
is_compiled = false; m_is_compiled = false;
} }
void overlay_element::align_text(text_align align) void overlay_element::align_text(text_align align)
{ {
alignment = align; alignment = align;
is_compiled = false; m_is_compiled = false;
} }
void overlay_element::set_wrap_text(bool state) void overlay_element::set_wrap_text(bool state)
{ {
wrap_text = state; wrap_text = state;
is_compiled = false; m_is_compiled = false;
} }
font* overlay_element::get_font() const font* overlay_element::get_font() const
@ -563,7 +574,7 @@ namespace rsx
compiled_resource& overlay_element::get_compiled() compiled_resource& overlay_element::get_compiled()
{ {
if (!is_compiled) if (!is_compiled())
{ {
compiled_resources.clear(); compiled_resources.clear();
@ -599,7 +610,7 @@ namespace rsx
compiled_resources.add(std::move(compiled_resources_temp), margin_left - horizontal_scroll_offset, margin_top - vertical_scroll_offset); compiled_resources.add(std::move(compiled_resources_temp), margin_left - horizontal_scroll_offset, margin_top - vertical_scroll_offset);
} }
is_compiled = true; m_is_compiled = true;
} }
return compiled_resources; return compiled_resources;
@ -675,9 +686,19 @@ namespace rsx
translate(dx, dy); translate(dx, dy);
} }
bool layout_container::is_compiled()
{
if (m_is_compiled && std::any_of(m_items.cbegin(), m_items.cend(), [](const auto& item){ return item && !item->is_compiled(); }))
{
m_is_compiled = false;
}
return m_is_compiled;
}
compiled_resource& layout_container::get_compiled() compiled_resource& layout_container::get_compiled()
{ {
if (!is_compiled) if (!is_compiled())
{ {
compiled_resource result = overlay_element::get_compiled(); compiled_resource result = overlay_element::get_compiled();
@ -716,7 +737,7 @@ namespace rsx
return m_items.back().get(); return m_items.back().get();
} }
auto result = item.get(); overlay_element* result = item.get();
m_items.insert(m_items.begin() + offset, std::move(item)); m_items.insert(m_items.begin() + offset, std::move(item));
return result; return result;
} }
@ -726,7 +747,7 @@ namespace rsx
if (scroll_offset_value == 0 && auto_resize) if (scroll_offset_value == 0 && auto_resize)
return layout_container::get_compiled(); return layout_container::get_compiled();
if (!is_compiled) if (!is_compiled())
{ {
compiled_resource result = overlay_element::get_compiled(); compiled_resource result = overlay_element::get_compiled();
const f32 global_y_offset = static_cast<f32>(-scroll_offset_value); const f32 global_y_offset = static_cast<f32>(-scroll_offset_value);
@ -808,7 +829,7 @@ namespace rsx
if (scroll_offset_value == 0 && auto_resize) if (scroll_offset_value == 0 && auto_resize)
return layout_container::get_compiled(); return layout_container::get_compiled();
if (!is_compiled) if (!is_compiled())
{ {
compiled_resource result = overlay_element::get_compiled(); compiled_resource result = overlay_element::get_compiled();
const f32 global_x_offset = static_cast<f32>(-scroll_offset_value); const f32 global_x_offset = static_cast<f32>(-scroll_offset_value);
@ -862,7 +883,7 @@ namespace rsx
compiled_resource& image_view::get_compiled() compiled_resource& image_view::get_compiled()
{ {
if (!is_compiled) if (!is_compiled())
{ {
auto& result = overlay_element::get_compiled(); auto& result = overlay_element::get_compiled();
auto& cmd_img = result.draw_commands.front(); auto& cmd_img = result.draw_commands.front();
@ -880,7 +901,7 @@ namespace rsx
verts[2] += vertex(padding_left, -padding_top, 0, 0); verts[2] += vertex(padding_left, -padding_top, 0, 0);
verts[3] += vertex(-padding_right, -padding_top, 0, 0); verts[3] += vertex(-padding_right, -padding_top, 0, 0);
is_compiled = true; m_is_compiled = true;
} }
return compiled_resources; return compiled_resources;
@ -892,7 +913,7 @@ namespace rsx
external_ref = nullptr; external_ref = nullptr;
} }
void image_view::set_raw_image(image_info* raw_image) void image_view::set_raw_image(image_info_base* raw_image)
{ {
image_resource_ref = image_resource_id::raw_image; image_resource_ref = image_resource_id::raw_image;
external_ref = raw_image; external_ref = raw_image;
@ -935,7 +956,7 @@ namespace rsx
compiled_resource& image_button::get_compiled() compiled_resource& image_button::get_compiled()
{ {
if (!is_compiled) if (!is_compiled())
{ {
auto& compiled = image_view::get_compiled(); auto& compiled = image_view::get_compiled();
for (auto& cmd : compiled.draw_commands) for (auto& cmd : compiled.draw_commands)
@ -987,7 +1008,7 @@ namespace rsx
compiled_resource& rounded_rect::get_compiled() compiled_resource& rounded_rect::get_compiled()
{ {
if (!is_compiled) if (!is_compiled())
{ {
compiled_resources.clear(); compiled_resources.clear();
@ -1068,7 +1089,7 @@ namespace rsx
compiled_resources.add(std::move(compiled_resources_temp), margin_left, margin_top); compiled_resources.add(std::move(compiled_resources_temp), margin_left, margin_top);
} }
is_compiled = true; m_is_compiled = true;
} }
return compiled_resources; return compiled_resources;

View file

@ -30,23 +30,32 @@ namespace rsx
triangle_fan = 4 triangle_fan = 4
}; };
struct image_info struct image_info_base
{
int w = 0, h = 0, channels = 0;
int bpp = 0;
bool dirty = false;
image_info_base() {}
virtual ~image_info_base() {}
virtual const u8* get_data() const = 0;
};
struct image_info : public image_info_base
{ {
private: private:
u8* data = nullptr; u8* data = nullptr;
std::vector<u8> data_grey; std::vector<u8> data_grey;
public: public:
int w = 0, h = 0, channels = 0; using image_info_base::image_info_base;
int bpp = 0;
image_info(image_info&) = delete; image_info(image_info&) = delete;
image_info(const std::string& filename, bool grayscaled = false); image_info(const std::string& filename, bool grayscaled = false);
image_info(const std::vector<u8>& bytes, bool grayscaled = false); image_info(const std::vector<u8>& bytes, bool grayscaled = false);
~image_info(); virtual ~image_info();
void load_data(const std::vector<u8>& bytes, bool grayscaled = false); void load_data(const std::vector<u8>& bytes, bool grayscaled = false);
const u8* get_data() const { return channels == 4 ? data : data_grey.empty() ? nullptr : data_grey.data(); } const u8* get_data() const override { return channels == 4 ? data : data_grey.empty() ? nullptr : data_grey.data(); }
}; };
struct resource_config struct resource_config
@ -165,7 +174,6 @@ namespace rsx
void set_sinus_offset(f32 sinus_modifier); void set_sinus_offset(f32 sinus_modifier);
compiled_resource compiled_resources; compiled_resource compiled_resources;
bool is_compiled = false;
bool visible = true; bool visible = true;
@ -185,6 +193,7 @@ namespace rsx
virtual ~overlay_element() = default; virtual ~overlay_element() = default;
virtual void refresh(); virtual void refresh();
virtual bool is_compiled() { return m_is_compiled; }
virtual void translate(s16 _x, s16 _y); virtual void translate(s16 _x, s16 _y);
virtual void scale(f32 _x, f32 _y, bool origin_scaling); virtual void scale(f32 _x, f32 _y, bool origin_scaling);
virtual void set_pos(s16 _x, s16 _y); virtual void set_pos(s16 _x, s16 _y);
@ -204,6 +213,10 @@ namespace rsx
virtual std::vector<vertex> render_text(const char32_t* string, f32 x, f32 y); virtual std::vector<vertex> render_text(const char32_t* string, f32 x, f32 y);
virtual compiled_resource& get_compiled(); virtual compiled_resource& get_compiled();
void measure_text(u16& width, u16& height, bool ignore_word_wrap = false) const; void measure_text(u16& width, u16& height, bool ignore_word_wrap = false) const;
virtual void set_selected(bool selected) { static_cast<void>(selected); }
protected:
bool m_is_compiled = false; // Only use m_is_compiled as a getter in is_compiled() if possible
}; };
struct layout_container : public overlay_element struct layout_container : public overlay_element
@ -221,6 +234,8 @@ namespace rsx
void translate(s16 _x, s16 _y) override; void translate(s16 _x, s16 _y) override;
void set_pos(s16 _x, s16 _y) override; void set_pos(s16 _x, s16 _y) override;
bool is_compiled() override;
compiled_resource& get_compiled() override; compiled_resource& get_compiled() override;
virtual u16 get_scroll_offset_px() = 0; virtual u16 get_scroll_offset_px() = 0;
@ -248,6 +263,7 @@ namespace rsx
compiled_resource& get_compiled() override compiled_resource& get_compiled() override
{ {
// No draw // No draw
m_is_compiled = true;
return compiled_resources; return compiled_resources;
} }
}; };
@ -263,7 +279,7 @@ namespace rsx
struct image_view : public overlay_element struct image_view : public overlay_element
{ {
private: protected:
u8 image_resource_ref = image_resource_id::none; u8 image_resource_ref = image_resource_id::none;
void* external_ref = nullptr; void* external_ref = nullptr;
@ -276,7 +292,7 @@ namespace rsx
compiled_resource& get_compiled() override; compiled_resource& get_compiled() override;
void set_image_resource(u8 resource_id); void set_image_resource(u8 resource_id);
void set_raw_image(image_info* raw_image); void set_raw_image(image_info_base* raw_image);
void clear_image(); void clear_image();
void set_blur_strength(u8 strength); void set_blur_strength(u8 strength);
}; };

View file

@ -196,7 +196,7 @@ namespace rsx
compiled_resource& edit_text::get_compiled() compiled_resource& edit_text::get_compiled()
{ {
if (!is_compiled) if (!is_compiled())
{ {
auto renderer = get_font(); auto renderer = get_font();
const auto [caret_x, caret_y] = renderer->get_char_offset(text.c_str(), caret_position, clip_text ? w : -1, wrap_text); const auto [caret_x, caret_y] = renderer->get_char_offset(text.c_str(), caret_position, clip_text ? w : -1, wrap_text);
@ -252,7 +252,7 @@ namespace rsx
cmd.config.clip_rect = {static_cast<f32>(x), static_cast<f32>(y), static_cast<f32>(x + w), static_cast<f32>(y + h)}; cmd.config.clip_rect = {static_cast<f32>(x), static_cast<f32>(y), static_cast<f32>(x + w), static_cast<f32>(y + h)};
} }
is_compiled = true; m_is_compiled = true;
} }
return compiled_resources; return compiled_resources;

View file

@ -91,6 +91,15 @@ namespace rsx
void list_view::update_selection() void list_view::update_selection()
{ {
const overlay_element* current_element = get_selected_entry(); const overlay_element* current_element = get_selected_entry();
for (auto& item : m_items)
{
if (item)
{
item->set_selected(item.get() == current_element);
}
}
if (!current_element) if (!current_element)
{ {
return; // Ideally unreachable but it should still be possible to recover by user interaction. return; // Ideally unreachable but it should still be possible to recover by user interaction.
@ -195,7 +204,7 @@ namespace rsx
m_cancel_btn->set_pos(x + 180, y + h + 20); m_cancel_btn->set_pos(x + 180, y + h + 20);
m_cancel_only = cancel_only; m_cancel_only = cancel_only;
is_compiled = false; m_is_compiled = false;
} }
bool list_view::get_cancel_only() const bool list_view::get_cancel_only() const
@ -219,7 +228,7 @@ namespace rsx
compiled_resource& list_view::get_compiled() compiled_resource& list_view::get_compiled()
{ {
if (!is_compiled) if (!is_compiled())
{ {
auto& compiled = vertical_layout::get_compiled(); auto& compiled = vertical_layout::get_compiled();
compiled.add(m_highlight_box->get_compiled()); compiled.add(m_highlight_box->get_compiled());

View file

@ -100,7 +100,7 @@ namespace rsx
} }
// Disable caching // Disable caching
is_compiled = false; m_is_compiled = false;
compiled_resources = rounded_rect::get_compiled(); compiled_resources = rounded_rect::get_compiled();
compiled_resources.add(m_text.get_compiled()); compiled_resources.add(m_text.get_compiled());

View file

@ -814,7 +814,7 @@ namespace rsx
compiled_resource& graph::get_compiled() compiled_resource& graph::get_compiled()
{ {
if (is_compiled) if (is_compiled())
{ {
return compiled_resources; return compiled_resources;
} }

View file

@ -23,7 +23,7 @@ namespace rsx
void progress_bar::set_limit(f32 limit) void progress_bar::set_limit(f32 limit)
{ {
m_limit = limit; m_limit = limit;
is_compiled = false; m_is_compiled = false;
} }
void progress_bar::set_value(f32 value) void progress_bar::set_value(f32 value)
@ -32,7 +32,7 @@ namespace rsx
f32 indicator_width = (w * m_value) / m_limit; f32 indicator_width = (w * m_value) / m_limit;
indicator.set_size(static_cast<u16>(indicator_width), h); indicator.set_size(static_cast<u16>(indicator_width), h);
is_compiled = false; m_is_compiled = false;
} }
void progress_bar::set_pos(s16 _x, s16 _y) void progress_bar::set_pos(s16 _x, s16 _y)
@ -68,12 +68,12 @@ namespace rsx
text_view.set_size(w, text_h); text_view.set_size(w, text_h);
set_pos(text_view.x, text_view.y); set_pos(text_view.x, text_view.y);
is_compiled = false; m_is_compiled = false;
} }
compiled_resource& progress_bar::get_compiled() compiled_resource& progress_bar::get_compiled()
{ {
if (!is_compiled) if (!is_compiled())
{ {
auto& compiled = overlay_element::get_compiled(); auto& compiled = overlay_element::get_compiled();
compiled.add(text_view.get_compiled()); compiled.add(text_view.get_compiled());

View file

@ -1,5 +1,6 @@
#include "stdafx.h" #include "stdafx.h"
#include "overlay_save_dialog.h" #include "overlay_save_dialog.h"
#include "overlay_video.h"
#include "Utilities/date_time.h" #include "Utilities/date_time.h"
#include "Emu/System.h" #include "Emu/System.h"
@ -7,26 +8,18 @@ namespace rsx
{ {
namespace overlays namespace overlays
{ {
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) 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)
{ {
std::unique_ptr<overlay_element> image = std::make_unique<image_view>(); 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
image->set_size(160, 110); image->set_size(160, 110);
image->set_padding(36, 36, 11, 11); // Square image, 88x88 image->set_padding(36, 36, 11, 11); // Square image, 88x88
if (resource_id != image_resource_id::raw_image) if (resource_id == image_resource_id::raw_image && !icon_buf.empty())
{
static_cast<image_view*>(image.get())->set_image_resource(resource_id);
}
else if (!icon_buf.empty())
{ {
image->set_padding(0, 0, 11, 11); // Half sized icon, 320x176->160x88 image->set_padding(0, 0, 11, 11); // Half sized icon, 320x176->160x88
icon_data = std::make_unique<image_info>(icon_buf);
static_cast<image_view*>(image.get())->set_raw_image(icon_data.get());
}
else
{
// Fallback
static_cast<image_view*>(image.get())->set_image_resource(resource_config::standard_image_resource::save);
} }
std::unique_ptr<overlay_element> text_stack = std::make_unique<vertical_layout>(); std::unique_ptr<overlay_element> text_stack = std::make_unique<vertical_layout>();
@ -74,10 +67,18 @@ namespace rsx
// Pack // Pack
this->pack_padding = 15; this->pack_padding = 15;
add_element(image); m_image = add_element(image);
add_element(text_stack); add_element(text_stack);
} }
void save_dialog::save_dialog_entry::set_selected(bool selected)
{
if (m_image)
{
static_cast<video_view*>(m_image)->set_active(selected);
}
}
save_dialog::save_dialog() save_dialog::save_dialog()
{ {
m_dim_background = std::make_unique<overlay_element>(); m_dim_background = std::make_unique<overlay_element>();
@ -197,7 +198,7 @@ namespace rsx
return result; return result;
} }
s32 save_dialog::show(std::vector<SaveDataEntry>& save_entries, u32 focused, u32 op, vm::ptr<CellSaveDataListSet> listSet, bool enable_overlay) s32 save_dialog::show(const std::string& base_dir, std::vector<SaveDataEntry>& save_entries, u32 focused, u32 op, vm::ptr<CellSaveDataListSet> listSet, bool enable_overlay)
{ {
rsx_log.notice("Showing native UI save_dialog (save_entries=%d, focused=%d, op=0x%x, listSet=*0x%x, enable_overlay=%d)", save_entries.size(), focused, op, listSet, enable_overlay); rsx_log.notice("Showing native UI save_dialog (save_entries=%d, focused=%d, op=0x%x, listSet=*0x%x, enable_overlay=%d)", save_entries.size(), focused, op, listSet, enable_overlay);
@ -218,7 +219,7 @@ namespace rsx
{ {
const std::string date_and_size = fmt::format("%s %s", entry.date(), entry.data_size()); const std::string date_and_size = fmt::format("%s %s", entry.date(), entry.data_size());
std::unique_ptr<overlay_element> e; std::unique_ptr<overlay_element> e;
e = std::make_unique<save_dialog_entry>(entry.subtitle, date_and_size, entry.details, image_resource_id::raw_image, entry.iconBuf); e = std::make_unique<save_dialog_entry>(entry.subtitle, date_and_size, entry.details, image_resource_id::raw_image, entry.iconBuf, base_dir + entry.dirName + "/ICON1.PAM");
entries.emplace_back(std::move(e)); entries.emplace_back(std::move(e));
} }
@ -270,7 +271,7 @@ namespace rsx
id = image_resource_id::raw_image; id = image_resource_id::raw_image;
} }
std::unique_ptr<overlay_element> new_stub = std::make_unique<save_dialog_entry>(title, get_localized_string(localized_string_id::CELL_SAVEDATA_NEW_SAVED_DATA_SUB_TITLE), "", id, icon); std::unique_ptr<overlay_element> new_stub = std::make_unique<save_dialog_entry>(title, get_localized_string(localized_string_id::CELL_SAVEDATA_NEW_SAVED_DATA_SUB_TITLE), "", id, icon, "");
m_list->add_entry(new_stub); m_list->add_entry(new_stub);
} }

View file

@ -13,11 +13,12 @@ namespace rsx
private: private:
struct save_dialog_entry : horizontal_layout struct save_dialog_entry : horizontal_layout
{ {
private:
std::unique_ptr<image_info> icon_data;
public: public:
save_dialog_entry(const std::string& text1, const std::string& text2, const std::string& text3, u8 resource_id, const std::vector<u8>& icon_buf); 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);
void set_selected(bool selected) override;
private:
overlay_element* m_image = nullptr;
}; };
std::unique_ptr<overlay_element> m_dim_background; std::unique_ptr<overlay_element> m_dim_background;
@ -38,7 +39,7 @@ namespace rsx
compiled_resource get_compiled() override; compiled_resource get_compiled() override;
s32 show(std::vector<SaveDataEntry>& save_entries, u32 focused, u32 op, vm::ptr<CellSaveDataListSet> listSet, bool enable_overlay); s32 show(const std::string& base_dir, std::vector<SaveDataEntry>& save_entries, u32 focused, u32 op, vm::ptr<CellSaveDataListSet> listSet, bool enable_overlay);
}; };
} }
} }

View file

@ -0,0 +1,116 @@
#include "stdafx.h"
#include "overlay_video.h"
#include "Emu/System.h"
namespace rsx
{
namespace overlays
{
video_view::video_view(const std::string& video_path, const std::string& thumbnail_path)
{
init_video(video_path);
if (!thumbnail_path.empty())
{
m_thumbnail_info = std::make_unique<image_info>(thumbnail_path);
set_raw_image(m_thumbnail_info.get());
}
}
video_view::video_view(const std::string& video_path, const std::vector<u8>& thumbnail_buf)
{
init_video(video_path);
if (!thumbnail_buf.empty())
{
m_thumbnail_info = std::make_unique<image_info>(thumbnail_buf);
set_raw_image(m_thumbnail_info.get());
}
}
video_view::video_view(const std::string& video_path, u8 thumbnail_id)
: m_thumbnail_id(thumbnail_id)
{
init_video(video_path);
set_image_resource(thumbnail_id);
}
video_view::~video_view()
{
}
void video_view::init_video(const std::string& video_path)
{
if (video_path.empty()) return;
m_video_source = Emu.GetCallbacks().make_video_source();
ensure(!!m_video_source);
m_video_source->set_update_callback([this]()
{
if (m_video_active)
{
m_is_compiled = false;
}
});
m_video_source->set_video_path(video_path);
}
void video_view::set_active(bool active)
{
if (m_video_source)
{
m_video_source->set_active(active);
m_video_active = active;
m_is_compiled = false;
}
}
void video_view::update()
{
if (m_video_active && m_video_source && m_video_source->get_active())
{
if (!m_video_source->has_new())
{
return;
}
m_buffer_index = (m_buffer_index + 1) % m_video_info.size();
auto& info = m_video_info.at(m_buffer_index);
if (!info)
{
info = std::make_unique<video_info>();
}
m_video_source->get_image(info->data, info->w, info->h, info->channels, info->bpp);
info->dirty = true;
set_raw_image(info.get());
m_is_compiled = false;
return;
}
if (m_thumbnail_info && m_thumbnail_info.get() != external_ref)
{
set_raw_image(m_thumbnail_info.get());
m_is_compiled = false;
return;
}
if (m_thumbnail_id != image_resource_id::none && m_thumbnail_id != image_resource_ref)
{
set_image_resource(m_thumbnail_id);
m_is_compiled = false;
return;
}
}
compiled_resource& video_view::get_compiled()
{
update();
return external_ref ? image_view::get_compiled() : overlay_element::get_compiled();
}
}
}

View file

@ -0,0 +1,43 @@
#pragma once
#include "overlay_controls.h"
#include "util/video_source.h"
namespace rsx
{
namespace overlays
{
struct video_info : public image_info_base
{
using image_info_base::image_info_base;
virtual ~video_info() {}
const u8* get_data() const override { return data.empty() ? nullptr : data.data(); }
std::vector<u8> data;
};
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);
virtual ~video_view();
void set_active(bool active);
void update();
compiled_resource& get_compiled() override;
private:
void init_video(const std::string& video_path);
usz m_buffer_index = 0;
std::array<std::unique_ptr<video_info>, 2> m_video_info; // double buffer
std::unique_ptr<video_source> m_video_source;
std::unique_ptr<image_info> m_thumbnail_info;
u8 m_thumbnail_id = image_resource_id::none;
bool m_video_active = false; // This is the expected state. The actual state is found in the video source.
};
}
}

View file

@ -76,6 +76,8 @@ vec4 _fetch_constant(const in uint base_offset)
// uint override // uint override
return _fetch_constant(int(base_offset)); return _fetch_constant(int(base_offset));
} }
#elif defined(VULKAN)
#define _fetch_constant(x) vc[x + xform_constants_offset]
#else #else
#define _fetch_constant(x) vc[x] #define _fetch_constant(x) vc[x]
#endif #endif

View file

@ -23,10 +23,6 @@
#endif #endif
#endif #endif
#ifdef ARCH_ARM64
#define AVX512_ICL_FUNC
#endif
#ifdef _MSC_VER #ifdef _MSC_VER
#define AVX512_ICL_FUNC #define AVX512_ICL_FUNC
#else #else

View file

@ -50,7 +50,7 @@ namespace vk
idx++; idx++;
bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
bindings[idx].descriptorCount = 1; bindings[idx].descriptorCount = 1;
bindings[idx].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; bindings[idx].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
bindings[idx].binding = binding_table.vertex_constant_buffers_bind_slot; bindings[idx].binding = binding_table.vertex_constant_buffers_bind_slot;
@ -101,7 +101,8 @@ namespace vk
return bindings; return bindings;
} }
std::tuple<VkPipelineLayout, VkDescriptorSetLayout> get_common_pipeline_layout(VkDevice dev) std::tuple<VkPipelineLayout, VkDescriptorSetLayout, rsx::simple_array<VkDescriptorSetLayoutBinding>>
get_common_pipeline_layout(VkDevice dev)
{ {
const auto& binding_table = vk::get_current_renderer()->get_pipeline_binding_table(); const auto& binding_table = vk::get_current_renderer()->get_pipeline_binding_table();
auto bindings = get_common_binding_table(); auto bindings = get_common_binding_table();
@ -135,13 +136,13 @@ namespace vk
std::array<VkPushConstantRange, 1> push_constants; std::array<VkPushConstantRange, 1> push_constants;
push_constants[0].offset = 0; push_constants[0].offset = 0;
push_constants[0].size = 16; push_constants[0].size = 20;
push_constants[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; push_constants[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
if (vk::emulate_conditional_rendering()) if (vk::emulate_conditional_rendering())
{ {
// Conditional render toggle // Conditional render toggle
push_constants[0].size = 20; push_constants[0].size = 24;
} }
const auto set_layout = vk::descriptors::create_layout(bindings); const auto set_layout = vk::descriptors::create_layout(bindings);
@ -155,6 +156,25 @@ namespace vk
VkPipelineLayout result; VkPipelineLayout result;
CHECK_RESULT(vkCreatePipelineLayout(dev, &layout_info, nullptr, &result)); CHECK_RESULT(vkCreatePipelineLayout(dev, &layout_info, nullptr, &result));
return std::make_tuple(result, set_layout); return std::make_tuple(result, set_layout, bindings);
}
rsx::simple_array<VkDescriptorPoolSize> get_descriptor_pool_sizes(const rsx::simple_array<VkDescriptorSetLayoutBinding>& bindings)
{
// Compile descriptor pool sizes
const u32 num_ubo = bindings.reduce(0, FN(x + (y.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ? y.descriptorCount : 0)));
const u32 num_texel_buffers = bindings.reduce(0, FN(x + (y.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER ? y.descriptorCount : 0)));
const u32 num_combined_image_sampler = bindings.reduce(0, FN(x + (y.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ? y.descriptorCount : 0)));
const u32 num_ssbo = bindings.reduce(0, FN(x + (y.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER ? y.descriptorCount : 0)));
ensure(num_ubo > 0 && num_texel_buffers > 0 && num_combined_image_sampler > 0 && num_ssbo > 0);
return
{
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , num_ubo },
{ VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER , num_texel_buffers },
{ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , num_combined_image_sampler },
{ VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, num_ssbo }
};
} }
} }

View file

@ -7,8 +7,11 @@ namespace vk
{ {
// Grab standard layout for decompiled RSX programs. Also used by the interpreter. // Grab standard layout for decompiled RSX programs. Also used by the interpreter.
// FIXME: This generates a bloated monstrosity that needs to die. // FIXME: This generates a bloated monstrosity that needs to die.
std::tuple<VkPipelineLayout, VkDescriptorSetLayout> get_common_pipeline_layout(VkDevice dev); std::tuple<VkPipelineLayout, VkDescriptorSetLayout, rsx::simple_array<VkDescriptorSetLayoutBinding>> get_common_pipeline_layout(VkDevice dev);
// Returns the standard binding layout without texture slots. Those have special handling depending on the consumer. // Returns the standard binding layout without texture slots. Those have special handling depending on the consumer.
rsx::simple_array<VkDescriptorSetLayoutBinding> get_common_binding_table(); rsx::simple_array<VkDescriptorSetLayoutBinding> get_common_binding_table();
// Returns an array of pool sizes that can be used to generate a proper descriptor pool
rsx::simple_array<VkDescriptorPoolSize> get_descriptor_pool_sizes(const rsx::simple_array<VkDescriptorSetLayoutBinding>& bindings);
} }

View file

@ -491,7 +491,8 @@ VKGSRender::VKGSRender(utils::serial* ar) noexcept : GSRender(ar)
m_secondary_cb_list.create(m_secondary_command_buffer_pool, vk::command_buffer::access_type_hint::all); m_secondary_cb_list.create(m_secondary_command_buffer_pool, vk::command_buffer::access_type_hint::all);
//Precalculated stuff //Precalculated stuff
std::tie(m_pipeline_layout, m_descriptor_layouts) = vk::get_common_pipeline_layout(*m_device); rsx::simple_array<VkDescriptorSetLayoutBinding> binding_layout;
std::tie(m_pipeline_layout, m_descriptor_layouts, binding_layout) = vk::get_common_pipeline_layout(*m_device);
//Occlusion //Occlusion
m_occlusion_query_manager = std::make_unique<vk::query_pool_manager>(*m_device, VK_QUERY_TYPE_OCCLUSION, OCCLUSION_MAX_POOL_SIZE); m_occlusion_query_manager = std::make_unique<vk::query_pool_manager>(*m_device, VK_QUERY_TYPE_OCCLUSION, OCCLUSION_MAX_POOL_SIZE);
@ -507,18 +508,7 @@ VKGSRender::VKGSRender(utils::serial* ar) noexcept : GSRender(ar)
// Generate frame contexts // Generate frame contexts
const u32 max_draw_calls = m_device->get_descriptor_max_draw_calls(); const u32 max_draw_calls = m_device->get_descriptor_max_draw_calls();
const auto& binding_table = m_device->get_pipeline_binding_table(); const auto descriptor_type_sizes = vk::get_descriptor_pool_sizes(binding_layout);
const u32 num_fs_samplers = binding_table.vertex_textures_first_bind_slot - binding_table.textures_first_bind_slot;
rsx::simple_array<VkDescriptorPoolSize> descriptor_type_sizes =
{
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , 6 },
{ VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER , 3 },
{ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , (num_fs_samplers + 4) },
// Conditional rendering predicate slot; refactor to allow skipping this when not needed
{ VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 3 }
};
m_descriptor_pool.create(*m_device, descriptor_type_sizes, max_draw_calls); m_descriptor_pool.create(*m_device, descriptor_type_sizes, max_draw_calls);
VkSemaphoreCreateInfo semaphore_info = {}; VkSemaphoreCreateInfo semaphore_info = {};
@ -531,7 +521,7 @@ VKGSRender::VKGSRender(utils::serial* ar) noexcept : GSRender(ar)
m_fragment_texture_params_ring_info.create(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_UBO_RING_BUFFER_SIZE_M * 0x100000, "fragment texture params buffer"); m_fragment_texture_params_ring_info.create(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_UBO_RING_BUFFER_SIZE_M * 0x100000, "fragment texture params buffer");
m_vertex_layout_ring_info.create(VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, VK_UBO_RING_BUFFER_SIZE_M * 0x100000, "vertex layout buffer", 0x10000, VK_TRUE); m_vertex_layout_ring_info.create(VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, VK_UBO_RING_BUFFER_SIZE_M * 0x100000, "vertex layout buffer", 0x10000, VK_TRUE);
m_fragment_constants_ring_info.create(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_UBO_RING_BUFFER_SIZE_M * 0x100000, "fragment constants buffer"); m_fragment_constants_ring_info.create(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_UBO_RING_BUFFER_SIZE_M * 0x100000, "fragment constants buffer");
m_transform_constants_ring_info.create(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_TRANSFORM_CONSTANTS_BUFFER_SIZE_M * 0x100000, "transform constants buffer"); m_transform_constants_ring_info.create(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VK_TRANSFORM_CONSTANTS_BUFFER_SIZE_M * 0x100000, "transform constants buffer");
m_index_buffer_ring_info.create(VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_INDEX_RING_BUFFER_SIZE_M * 0x100000, "index buffer"); m_index_buffer_ring_info.create(VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_INDEX_RING_BUFFER_SIZE_M * 0x100000, "index buffer");
m_texture_upload_buffer_ring_info.create(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_TEXTURE_UPLOAD_RING_BUFFER_SIZE_M * 0x100000, "texture upload buffer", 32 * 0x100000); m_texture_upload_buffer_ring_info.create(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_TEXTURE_UPLOAD_RING_BUFFER_SIZE_M * 0x100000, "texture upload buffer", 32 * 0x100000);
m_raster_env_ring_info.create(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_UBO_RING_BUFFER_SIZE_M * 0x100000, "raster env buffer"); m_raster_env_ring_info.create(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_UBO_RING_BUFFER_SIZE_M * 0x100000, "raster env buffer");
@ -2107,7 +2097,7 @@ void VKGSRender::load_program_env()
usz mem_offset = 0; usz mem_offset = 0;
auto alloc_storage = [&](usz size) -> std::pair<void*, usz> auto alloc_storage = [&](usz size) -> std::pair<void*, usz>
{ {
const auto alignment = m_device->gpu().get_limits().minUniformBufferOffsetAlignment; const auto alignment = m_device->gpu().get_limits().minStorageBufferOffsetAlignment;
mem_offset = m_transform_constants_ring_info.alloc<1>(utils::align(size, alignment)); mem_offset = m_transform_constants_ring_info.alloc<1>(utils::align(size, alignment));
return std::make_pair(m_transform_constants_ring_info.map(mem_offset, size), size); return std::make_pair(m_transform_constants_ring_info.map(mem_offset, size), size);
}; };
@ -2118,7 +2108,8 @@ void VKGSRender::load_program_env()
if (!io_buf.empty()) if (!io_buf.empty())
{ {
m_transform_constants_ring_info.unmap(); m_transform_constants_ring_info.unmap();
m_vertex_constants_buffer_info = { m_transform_constants_ring_info.heap->value, mem_offset, io_buf.size() }; m_vertex_constants_buffer_info = { m_transform_constants_ring_info.heap->value, 0, VK_WHOLE_SIZE };
m_xform_constants_dynamic_offset = mem_offset;
} }
} }
@ -2225,7 +2216,7 @@ void VKGSRender::load_program_env()
const auto& binding_table = m_device->get_pipeline_binding_table(); const auto& binding_table = m_device->get_pipeline_binding_table();
m_program->bind_uniform(m_vertex_env_buffer_info, binding_table.vertex_params_bind_slot, m_current_frame->descriptor_set); m_program->bind_uniform(m_vertex_env_buffer_info, binding_table.vertex_params_bind_slot, m_current_frame->descriptor_set);
m_program->bind_uniform(m_vertex_constants_buffer_info, binding_table.vertex_constant_buffers_bind_slot, m_current_frame->descriptor_set); m_program->bind_buffer(m_vertex_constants_buffer_info, binding_table.vertex_constant_buffers_bind_slot, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, m_current_frame->descriptor_set);
m_program->bind_uniform(m_fragment_env_buffer_info, binding_table.fragment_state_bind_slot, m_current_frame->descriptor_set); m_program->bind_uniform(m_fragment_env_buffer_info, binding_table.fragment_state_bind_slot, m_current_frame->descriptor_set);
m_program->bind_uniform(m_fragment_texture_params_buffer_info, binding_table.fragment_texture_params_bind_slot, m_current_frame->descriptor_set); m_program->bind_uniform(m_fragment_texture_params_buffer_info, binding_table.fragment_texture_params_bind_slot, m_current_frame->descriptor_set);
m_program->bind_uniform(m_raster_env_buffer_info, binding_table.rasterizer_env_bind_slot, m_current_frame->descriptor_set); m_program->bind_uniform(m_raster_env_buffer_info, binding_table.rasterizer_env_bind_slot, m_current_frame->descriptor_set);
@ -2320,21 +2311,31 @@ void VKGSRender::update_vertex_env(u32 id, const vk::vertex_upload_info& vertex_
base_offset = 0; base_offset = 0;
} }
u8 data_size = 16; const u32 vertex_layout_offset = (id * 16) + (base_offset / 8);
u32 draw_info[5]; const volatile u32 constant_id_offset = static_cast<volatile u32>(m_xform_constants_dynamic_offset) / 16u;
draw_info[0] = vertex_info.vertex_index_base; u32 push_constants[6];
draw_info[1] = vertex_info.vertex_index_offset; u32 data_length = 20;
draw_info[2] = id;
draw_info[3] = (id * 16) + (base_offset / 8); push_constants[0] = vertex_info.vertex_index_base;
push_constants[1] = vertex_info.vertex_index_offset;
push_constants[2] = id;
push_constants[3] = vertex_layout_offset;
push_constants[4] = constant_id_offset;
if (vk::emulate_conditional_rendering()) if (vk::emulate_conditional_rendering())
{ {
draw_info[4] = cond_render_ctrl.hw_cond_active ? 1 : 0; push_constants[5] = cond_render_ctrl.hw_cond_active ? 1 : 0;
data_size = 20; data_length += 4;
} }
vkCmdPushConstants(*m_current_command_buffer, m_pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT, 0, data_size, draw_info); vkCmdPushConstants(
*m_current_command_buffer,
m_pipeline_layout,
VK_SHADER_STAGE_VERTEX_BIT,
0,
data_length,
push_constants);
const usz data_offset = (id * 128) + m_vertex_layout_stream_info.offset; const usz data_offset = (id * 128) + m_vertex_layout_stream_info.offset;
auto dst = m_vertex_layout_ring_info.map(data_offset, 128); auto dst = m_vertex_layout_ring_info.map(data_offset, 128);
@ -2351,7 +2352,7 @@ void VKGSRender::update_vertex_env(u32 id, const vk::vertex_upload_info& vertex_
m_vertex_layout_ring_info.unmap(); m_vertex_layout_ring_info.unmap();
} }
void VKGSRender::patch_transform_constants(rsx::context* ctx, u32 index, u32 count) void VKGSRender::patch_transform_constants(rsx::context* /*ctx*/, u32 index, u32 count)
{ {
if (!m_program || !m_vertex_prog) if (!m_program || !m_vertex_prog)
{ {
@ -2366,83 +2367,16 @@ void VKGSRender::patch_transform_constants(rsx::context* ctx, u32 index, u32 cou
return; return;
} }
// Hot-patching transform constants mid-draw (instanced draw) // Buffer updates mid-pass violate the spec and destroy performance on NVIDIA
std::pair<VkDeviceSize, VkDeviceSize> data_range;
void* data_source = nullptr;
if (m_vertex_prog->has_indexed_constants)
{
// We're working with a full range. We can do a direct patch in this case since no index translation is required.
const auto byte_count = count * 16;
const auto byte_offset = index * 16;
data_range = { m_vertex_constants_buffer_info.offset + byte_offset, byte_count };
data_source = &REGS(ctx)->transform_constants[index];
}
else if (auto xform_id = m_vertex_prog->translate_constants_range(index, count); xform_id >= 0)
{
const auto write_offset = xform_id * 16;
const auto byte_count = count * 16;
data_range = { m_vertex_constants_buffer_info.offset + write_offset, byte_count };
data_source = &REGS(ctx)->transform_constants[index];
}
else
{
// Indexed. This is a bit trickier. Use scratchpad to avoid UAF
auto allocate_mem = [&](usz size) -> std::pair<void*, usz> auto allocate_mem = [&](usz size) -> std::pair<void*, usz>
{ {
m_scratch_mem.resize(size); const usz alignment = m_device->gpu().get_limits().minStorageBufferOffsetAlignment;
return { m_scratch_mem.data(), size }; m_xform_constants_dynamic_offset = m_transform_constants_ring_info.alloc<1>(utils::align(size, alignment));
return std::make_pair(m_transform_constants_ring_info.map(m_xform_constants_dynamic_offset, size), size);
}; };
rsx::io_buffer iobuf(allocate_mem); rsx::io_buffer iobuf(allocate_mem);
upload_transform_constants(iobuf); upload_transform_constants(iobuf);
ensure(iobuf.size() >= m_vertex_constants_buffer_info.range);
data_range = { m_vertex_constants_buffer_info.offset, m_vertex_constants_buffer_info.range };
data_source = iobuf.data();
}
// Preserving an active renderpass across a transfer operation is illegal vulkan. However, splitting up the CB into thousands of renderpasses incurs an overhead.
// We cheat here for specific cases where we already know the driver can let us get away with this.
static const std::set<vk::driver_vendor> s_allowed_vendors =
{
vk::driver_vendor::AMD,
vk::driver_vendor::RADV,
vk::driver_vendor::LAVAPIPE,
vk::driver_vendor::NVIDIA,
vk::driver_vendor::NVK
};
const auto driver_vendor = vk::get_driver_vendor();
const bool preserve_renderpass = !g_cfg.video.strict_rendering_mode && s_allowed_vendors.contains(driver_vendor);
vk::insert_buffer_memory_barrier(
*m_current_command_buffer,
m_vertex_constants_buffer_info.buffer,
data_range.first,
data_range.second,
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_ACCESS_UNIFORM_READ_BIT, VK_ACCESS_TRANSFER_WRITE_BIT,
preserve_renderpass);
// FIXME: This is illegal during a renderpass
vkCmdUpdateBuffer(
*m_current_command_buffer,
m_vertex_constants_buffer_info.buffer,
data_range.first,
data_range.second,
data_source);
vk::insert_buffer_memory_barrier(
*m_current_command_buffer,
m_vertex_constants_buffer_info.buffer,
data_range.first,
data_range.second,
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_UNIFORM_READ_BIT,
preserve_renderpass);
} }
void VKGSRender::init_buffers(rsx::framebuffer_creation_context context, bool) void VKGSRender::init_buffers(rsx::framebuffer_creation_context context, bool)

View file

@ -160,6 +160,8 @@ private:
VkDescriptorBufferInfo m_vertex_instructions_buffer_info {}; VkDescriptorBufferInfo m_vertex_instructions_buffer_info {};
VkDescriptorBufferInfo m_fragment_instructions_buffer_info {}; VkDescriptorBufferInfo m_fragment_instructions_buffer_info {};
u64 m_xform_constants_dynamic_offset = 0; // We manage transform_constants dynamic offset manually to alleviate performance penalty of doing a hot-patch of constants.
std::array<vk::frame_context_t, VK_MAX_ASYNC_FRAMES> frame_context_storage; std::array<vk::frame_context_t, VK_MAX_ASYNC_FRAMES> frame_context_storage;
//Temp frame context to use if the real frame queue is overburdened. Only used for storage //Temp frame context to use if the real frame queue is overburdened. Only used for storage
vk::frame_context_t m_aux_frame_context; vk::frame_context_t m_aux_frame_context;

View file

@ -386,22 +386,14 @@ namespace vk
VK_BLEND_OP_ADD, VK_BLEND_OP_ADD); VK_BLEND_OP_ADD, VK_BLEND_OP_ADD);
} }
vk::image_view* ui_overlay_renderer::upload_simple_texture(vk::render_device& dev, vk::command_buffer& cmd, void ui_overlay_renderer::upload_simple_texture(vk::image* tex, vk::command_buffer& cmd,
vk::data_heap& upload_heap, u64 key, u32 w, u32 h, u32 layers, bool font, bool temp, const void* pixel_src, u32 owner_uid) vk::data_heap& upload_heap, u32 w, u32 h, u32 layers, bool font, const void* pixel_src)
{ {
const VkFormat format = (font) ? VK_FORMAT_R8_UNORM : VK_FORMAT_B8G8R8A8_UNORM;
const u32 pitch = (font) ? w : w * 4; const u32 pitch = (font) ? w : w * 4;
const u32 data_size = pitch * h * layers; const u32 data_size = pitch * h * layers;
const auto offset = upload_heap.alloc<512>(data_size); const auto offset = upload_heap.alloc<512>(data_size);
const auto addr = upload_heap.map(offset, data_size); const auto addr = upload_heap.map(offset, data_size);
const VkImageSubresourceRange range = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, layers };
auto tex = std::make_unique<vk::image>(dev, dev.get_memory_mapping().device_local, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
VK_IMAGE_TYPE_2D, format, std::max(w, 1u), std::max(h, 1u), 1, 1, layers, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
0, VMM_ALLOCATION_POOL_UNDEFINED);
if (pixel_src && data_size) if (pixel_src && data_size)
std::memcpy(addr, pixel_src, data_size); std::memcpy(addr, pixel_src, data_size);
else if (data_size) else if (data_size)
@ -409,17 +401,32 @@ namespace vk
upload_heap.unmap(); upload_heap.unmap();
VkBufferImageCopy region; const VkImageSubresourceRange range = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, layers };
region.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, layers }; VkBufferImageCopy region
region.bufferOffset = offset; {
region.bufferRowLength = w; .bufferOffset = offset,
region.bufferImageHeight = h; .bufferRowLength = w,
region.imageOffset = {}; .bufferImageHeight = h,
region.imageExtent = { static_cast<u32>(w), static_cast<u32>(h), 1u }; .imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, layers },
.imageOffset = {},
change_image_layout(cmd, tex.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, range); .imageExtent = { static_cast<u32>(w), static_cast<u32>(h), 1u }
};
change_image_layout(cmd, tex, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, range);
vkCmdCopyBufferToImage(cmd, upload_heap.heap->value, tex->value, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region); vkCmdCopyBufferToImage(cmd, upload_heap.heap->value, tex->value, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
change_image_layout(cmd, tex.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, range); change_image_layout(cmd, tex, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, range);
}
vk::image_view* ui_overlay_renderer::upload_simple_texture(vk::render_device& dev, vk::command_buffer& cmd,
vk::data_heap& upload_heap, u64 key, u32 w, u32 h, u32 layers, bool font, bool temp, const void* pixel_src, u32 owner_uid)
{
const VkFormat format = (font) ? VK_FORMAT_R8_UNORM : VK_FORMAT_B8G8R8A8_UNORM;
auto tex = std::make_unique<vk::image>(dev, dev.get_memory_mapping().device_local, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
VK_IMAGE_TYPE_2D, format, std::max(w, 1u), std::max(h, 1u), 1, 1, layers, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
0, VMM_ALLOCATION_POOL_UNDEFINED);
upload_simple_texture(tex.get(), cmd, upload_heap, w, h, layers, font, pixel_src);
auto view = std::make_unique<vk::image_view>(dev, tex.get()); auto view = std::make_unique<vk::image_view>(dev, tex.get());
@ -521,12 +528,23 @@ namespace vk
true, false, bytes.data(), -1); true, false, bytes.data(), -1);
} }
vk::image_view* ui_overlay_renderer::find_temp_image(rsx::overlays::image_info* desc, vk::command_buffer& cmd, vk::data_heap& upload_heap, u32 owner_uid) vk::image_view* ui_overlay_renderer::find_temp_image(rsx::overlays::image_info_base* desc, vk::command_buffer& cmd, vk::data_heap& upload_heap, u32 owner_uid)
{ {
u64 key = reinterpret_cast<u64>(desc); const bool dirty = std::exchange(desc->dirty, false);
auto found = temp_view_cache.find(key); const u64 key = reinterpret_cast<u64>(desc);
if (found != temp_view_cache.end())
return found->second.get(); auto cached = temp_view_cache.find(key);
if (cached != temp_view_cache.end())
{
vk::image_view* view = cached->second.get();
if (dirty)
{
upload_simple_texture(view->image(), cmd, upload_heap, desc->w, desc->h, 1, false, desc->get_data());
}
return view;
}
return upload_simple_texture(cmd.get_command_pool().get_owner(), cmd, upload_heap, key, desc->w, desc->h, 1, return upload_simple_texture(cmd.get_command_pool().get_owner(), cmd, upload_heap, key, desc->w, desc->h, 1,
false, true, desc->get_data(), owner_uid); false, true, desc->get_data(), owner_uid);
@ -693,7 +711,7 @@ namespace vk
: rsx::overlays::texture_sampling_mode::font3D; : rsx::overlays::texture_sampling_mode::font3D;
break; break;
case rsx::overlays::image_resource_id::raw_image: case rsx::overlays::image_resource_id::raw_image:
src = find_temp_image(static_cast<rsx::overlays::image_info*>(command.config.external_data_ref), cmd, upload_heap, ui.uid); src = find_temp_image(static_cast<rsx::overlays::image_info_base*>(command.config.external_data_ref), cmd, upload_heap, ui.uid);
break; break;
default: default:
src = view_cache[command.config.texture_ref].get(); src = view_cache[command.config.texture_ref].get();

View file

@ -154,6 +154,9 @@ namespace vk
ui_overlay_renderer(); ui_overlay_renderer();
void upload_simple_texture(vk::image* tex, vk::command_buffer& cmd,
vk::data_heap& upload_heap, u32 w, u32 h, u32 layers, bool font, const void* pixel_src);
vk::image_view* upload_simple_texture(vk::render_device& dev, vk::command_buffer& cmd, vk::image_view* upload_simple_texture(vk::render_device& dev, vk::command_buffer& cmd,
vk::data_heap& upload_heap, u64 key, u32 w, u32 h, u32 layers, bool font, bool temp, const void* pixel_src, u32 owner_uid); vk::data_heap& upload_heap, u64 key, u32 w, u32 h, u32 layers, bool font, bool temp, const void* pixel_src, u32 owner_uid);
@ -164,7 +167,7 @@ namespace vk
void remove_temp_resources(u32 key); void remove_temp_resources(u32 key);
vk::image_view* find_font(rsx::overlays::font* font, vk::command_buffer& cmd, vk::data_heap& upload_heap); vk::image_view* find_font(rsx::overlays::font* font, vk::command_buffer& cmd, vk::data_heap& upload_heap);
vk::image_view* find_temp_image(rsx::overlays::image_info* desc, vk::command_buffer& cmd, vk::data_heap& upload_heap, u32 owner_uid); vk::image_view* find_temp_image(rsx::overlays::image_info_base* desc, vk::command_buffer& cmd, vk::data_heap& upload_heap, u32 owner_uid);
std::vector<VkPushConstantRange> get_push_constants() override; std::vector<VkPushConstantRange> get_push_constants() override;

View file

@ -330,21 +330,7 @@ namespace vk
idx++; idx++;
bindings.resize(idx); bindings.resize(idx);
// Compile descriptor pool sizes m_descriptor_pool_sizes = get_descriptor_pool_sizes(bindings);
const u32 num_ubo = bindings.reduce(0, FN(x + (y.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ? y.descriptorCount : 0)));
const u32 num_texel_buffers = bindings.reduce(0, FN(x + (y.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER ? y.descriptorCount : 0)));
const u32 num_combined_image_sampler = bindings.reduce(0, FN(x + (y.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ? y.descriptorCount : 0)));
const u32 num_ssbo = bindings.reduce(0, FN(x + (y.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER ? y.descriptorCount : 0)));
ensure(num_ubo > 0 && num_texel_buffers > 0 && num_combined_image_sampler > 0 && num_ssbo > 0);
m_descriptor_pool_sizes =
{
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , num_ubo },
{ VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER , num_texel_buffers },
{ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , num_combined_image_sampler },
{ VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, num_ssbo }
};
std::array<VkPushConstantRange, 1> push_constants; std::array<VkPushConstantRange, 1> push_constants;
push_constants[0].offset = 0; push_constants[0].offset = 0;

View file

@ -29,8 +29,9 @@ std::string VKVertexDecompilerThread::compareFunction(COMPARE f, const std::stri
void VKVertexDecompilerThread::insertHeader(std::stringstream &OS) void VKVertexDecompilerThread::insertHeader(std::stringstream &OS)
{ {
OS << "#version 450\n\n"; OS <<
OS << "#extension GL_ARB_separate_shader_objects : enable\n\n"; "#version 450\n\n"
"#extension GL_ARB_separate_shader_objects : enable\n\n";
OS << OS <<
"layout(std140, set = 0, binding = 0) uniform VertexContextBuffer\n" "layout(std140, set = 0, binding = 0) uniform VertexContextBuffer\n"
@ -59,7 +60,8 @@ void VKVertexDecompilerThread::insertHeader(std::stringstream &OS)
" uint vertex_base_index;\n" " uint vertex_base_index;\n"
" uint vertex_index_offset;\n" " uint vertex_index_offset;\n"
" uint draw_id;\n" " uint draw_id;\n"
" uint layout_ptr_offset;\n"; " uint layout_ptr_offset;\n"
" uint xform_constants_offset;\n";
if (m_device_props.emulate_conditional_rendering) if (m_device_props.emulate_conditional_rendering)
{ {
@ -115,15 +117,15 @@ void VKVertexDecompilerThread::insertConstants(std::stringstream & OS, const std
{ {
if (!(m_prog.ctrl & RSX_SHADER_CONTROL_INSTANCED_CONSTANTS)) if (!(m_prog.ctrl & RSX_SHADER_CONTROL_INSTANCED_CONSTANTS))
{ {
OS << "layout(std140, set=0, binding=" << static_cast<int>(m_binding_table.vertex_constant_buffers_bind_slot) << ") uniform VertexConstantsBuffer\n"; OS << "layout(std430, set=0, binding=" << static_cast<int>(m_binding_table.vertex_constant_buffers_bind_slot) << ") readonly buffer VertexConstantsBuffer\n";
OS << "{\n"; OS << "{\n";
OS << " vec4 " << PI.name << ";\n"; OS << " vec4 vc[];\n";
OS << "};\n\n"; OS << "};\n\n";
in.location = m_binding_table.vertex_constant_buffers_bind_slot; in.location = m_binding_table.vertex_constant_buffers_bind_slot;
in.domain = glsl::glsl_vertex_program; in.domain = glsl::glsl_vertex_program;
in.name = "VertexConstantsBuffer"; in.name = "VertexConstantsBuffer";
in.type = vk::glsl::input_type_uniform_buffer; in.type = vk::glsl::input_type_storage_buffer;
inputs.push_back(in); inputs.push_back(in);
continue; continue;

View file

@ -430,6 +430,17 @@ namespace vk
} }
} }
void descriptor_set::push(const descriptor_set_dynamic_offset_t& offset)
{
ensure(offset.location >= 0 && offset.location <= 16);
while (m_dynamic_offsets.size() < (static_cast<u32>(offset.location) + 1u))
{
m_dynamic_offsets.push_back(0);
}
m_dynamic_offsets[offset.location] = offset.value;
}
void descriptor_set::bind(const vk::command_buffer& cmd, VkPipelineBindPoint bind_point, VkPipelineLayout layout) void descriptor_set::bind(const vk::command_buffer& cmd, VkPipelineBindPoint bind_point, VkPipelineLayout layout)
{ {
if ((m_push_type_mask & ~m_update_after_bind_mask) || (m_pending_writes.size() >= max_cache_size)) if ((m_push_type_mask & ~m_update_after_bind_mask) || (m_pending_writes.size() >= max_cache_size))
@ -437,7 +448,7 @@ namespace vk
flush(); flush();
} }
vkCmdBindDescriptorSets(cmd, bind_point, layout, 0, 1, &m_handle, 0, nullptr); vkCmdBindDescriptorSets(cmd, bind_point, layout, 0, 1, &m_handle, ::size32(m_dynamic_offsets), m_dynamic_offsets.data());
} }
void descriptor_set::flush() void descriptor_set::flush()

View file

@ -27,6 +27,12 @@ namespace vk
} }
}; };
struct descriptor_set_dynamic_offset_t
{
int location;
u32 value;
};
class descriptor_pool class descriptor_pool
{ {
public: public:
@ -95,6 +101,7 @@ namespace vk
void push(const VkDescriptorImageInfo& image_info, VkDescriptorType type, u32 binding); void push(const VkDescriptorImageInfo& image_info, VkDescriptorType type, u32 binding);
void push(const VkDescriptorImageInfo* image_info, u32 count, VkDescriptorType type, u32 binding); void push(const VkDescriptorImageInfo* image_info, u32 count, VkDescriptorType type, u32 binding);
void push(rsx::simple_array<VkCopyDescriptorSet>& copy_cmd, u32 type_mask = umax); void push(rsx::simple_array<VkCopyDescriptorSet>& copy_cmd, u32 type_mask = umax);
void push(const descriptor_set_dynamic_offset_t& offset);
void bind(const vk::command_buffer& cmd, VkPipelineBindPoint bind_point, VkPipelineLayout layout); void bind(const vk::command_buffer& cmd, VkPipelineBindPoint bind_point, VkPipelineLayout layout);
@ -109,6 +116,7 @@ namespace vk
rsx::simple_array<VkBufferView> m_buffer_view_pool; rsx::simple_array<VkBufferView> m_buffer_view_pool;
rsx::simple_array<VkDescriptorBufferInfo> m_buffer_info_pool; rsx::simple_array<VkDescriptorBufferInfo> m_buffer_info_pool;
rsx::simple_array<VkDescriptorImageInfo> m_image_info_pool; rsx::simple_array<VkDescriptorImageInfo> m_image_info_pool;
rsx::simple_array<u32> m_dynamic_offsets;
#ifdef __clang__ #ifdef __clang__
// Clang (pre 16.x) does not support LWG 2089, std::construct_at for POD types // Clang (pre 16.x) does not support LWG 2089, std::construct_at for POD types

View file

@ -111,6 +111,7 @@ struct EmuCallbacks
std::function<bool()> display_sleep_control_supported; std::function<bool()> display_sleep_control_supported;
std::function<void(bool)> enable_display_sleep; std::function<void(bool)> enable_display_sleep;
std::function<void()> check_microphone_permissions; std::function<void()> check_microphone_permissions;
std::function<std::unique_ptr<class video_source>()> make_video_source;
}; };
namespace utils namespace utils

View file

@ -236,6 +236,7 @@ void pad_thread::SetRumble(const u32 pad, u8 large_motor, bool small_motor)
if (pad >= m_pads.size()) if (pad >= m_pads.size())
return; return;
m_pads[pad]->m_last_rumble_time_us = get_system_time();
m_pads[pad]->m_vibrateMotors[0].m_value = large_motor; m_pads[pad]->m_vibrateMotors[0].m_value = large_motor;
m_pads[pad]->m_vibrateMotors[1].m_value = small_motor ? 255 : 0; m_pads[pad]->m_vibrateMotors[1].m_value = small_motor ? 255 : 0;
} }

View file

@ -147,6 +147,7 @@
<ClCompile Include="Emu\RSX\Overlays\overlay_compile_notification.cpp" /> <ClCompile Include="Emu\RSX\Overlays\overlay_compile_notification.cpp" />
<ClCompile Include="Emu\RSX\Overlays\overlay_user_list_dialog.cpp" /> <ClCompile Include="Emu\RSX\Overlays\overlay_user_list_dialog.cpp" />
<ClCompile Include="Emu\RSX\Overlays\overlay_utils.cpp" /> <ClCompile Include="Emu\RSX\Overlays\overlay_utils.cpp" />
<ClCompile Include="Emu\RSX\Overlays\overlay_video.cpp" />
<ClCompile Include="Emu\RSX\Overlays\Shaders\shader_loading_dialog.cpp" /> <ClCompile Include="Emu\RSX\Overlays\Shaders\shader_loading_dialog.cpp" />
<ClCompile Include="Emu\RSX\Overlays\Shaders\shader_loading_dialog_native.cpp" /> <ClCompile Include="Emu\RSX\Overlays\Shaders\shader_loading_dialog_native.cpp" />
<ClCompile Include="Emu\RSX\Overlays\Trophies\overlay_trophy_list_dialog.cpp" /> <ClCompile Include="Emu\RSX\Overlays\Trophies\overlay_trophy_list_dialog.cpp" />
@ -682,6 +683,7 @@
<ClInclude Include="Emu\RSX\Overlays\overlay_manager.h" /> <ClInclude Include="Emu\RSX\Overlays\overlay_manager.h" />
<ClInclude Include="Emu\RSX\Overlays\overlay_media_list_dialog.h" /> <ClInclude Include="Emu\RSX\Overlays\overlay_media_list_dialog.h" />
<ClInclude Include="Emu\RSX\Overlays\overlay_progress_bar.hpp" /> <ClInclude Include="Emu\RSX\Overlays\overlay_progress_bar.hpp" />
<ClInclude Include="Emu\RSX\Overlays\overlay_video.h" />
<ClInclude Include="Emu\RSX\Overlays\Trophies\overlay_trophy_list_dialog.h" /> <ClInclude Include="Emu\RSX\Overlays\Trophies\overlay_trophy_list_dialog.h" />
<ClInclude Include="Emu\RSX\Program\FragmentProgramRegister.h" /> <ClInclude Include="Emu\RSX\Program\FragmentProgramRegister.h" />
<ClInclude Include="Emu\RSX\Program\GLSLTypes.h" /> <ClInclude Include="Emu\RSX\Program\GLSLTypes.h" />

View file

@ -1354,6 +1354,9 @@
<ClCompile Include="Emu\RSX\Common\texture_cache_types.cpp"> <ClCompile Include="Emu\RSX\Common\texture_cache_types.cpp">
<Filter>Emu\GPU\RSX\Common</Filter> <Filter>Emu\GPU\RSX\Common</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Emu\RSX\Overlays\overlay_video.cpp">
<Filter>Emu\GPU\RSX\Overlays</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="Crypto\aes.h"> <ClInclude Include="Crypto\aes.h">
@ -2719,6 +2722,9 @@
<ClInclude Include="util\video_source.h"> <ClInclude Include="util\video_source.h">
<Filter>Utilities</Filter> <Filter>Utilities</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="Emu\RSX\Overlays\overlay_video.h">
<Filter>Emu\GPU\RSX\Overlays</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="Emu\RSX\Program\GLSLSnippets\GPUDeswizzle.glsl"> <None Include="Emu\RSX\Program\GLSLSnippets\GPUDeswizzle.glsl">

View file

@ -8,6 +8,7 @@
#include "Emu/Cell/Modules/sceNpTrophy.h" #include "Emu/Cell/Modules/sceNpTrophy.h"
#include "Emu/Io/Null/null_camera_handler.h" #include "Emu/Io/Null/null_camera_handler.h"
#include "Emu/Io/Null/null_music_handler.h" #include "Emu/Io/Null/null_music_handler.h"
#include "util/video_source.h"
#include <clocale> #include <clocale>
@ -173,6 +174,8 @@ void headless_application::InitializeCallbacks()
callbacks.check_microphone_permissions = [](){}; callbacks.check_microphone_permissions = [](){};
callbacks.make_video_source = [](){ return nullptr; };
Emu.SetCallbacks(std::move(callbacks)); Emu.SetCallbacks(std::move(callbacks));
} }

File diff suppressed because it is too large Load diff

View file

@ -28,7 +28,7 @@ namespace rpcs3
// Currently accessible by Windows and Linux build scripts, see implementations when doing MACOSX // Currently accessible by Windows and Linux build scripts, see implementations when doing MACOSX
const utils::version& get_version() const utils::version& get_version()
{ {
static constexpr utils::version version{ 0, 0, 35, utils::version_type::alpha, 1, RPCS3_GIT_VERSION }; static constexpr utils::version version{ 0, 0, 36, utils::version_type::alpha, 1, RPCS3_GIT_VERSION };
return version; return version;
} }

View file

@ -28,7 +28,7 @@ about_dialog::about_dialog(QWidget* parent) : QDialog(parent), ui(new Ui::about_
connect(ui->website, &QPushButton::clicked, [] { QDesktopServices::openUrl(QUrl("https://rpcs3.net")); }); connect(ui->website, &QPushButton::clicked, [] { QDesktopServices::openUrl(QUrl("https://rpcs3.net")); });
connect(ui->forum, &QPushButton::clicked, [] { QDesktopServices::openUrl(QUrl("https://forums.rpcs3.net")); }); connect(ui->forum, &QPushButton::clicked, [] { QDesktopServices::openUrl(QUrl("https://forums.rpcs3.net")); });
connect(ui->patreon, &QPushButton::clicked, [] { QDesktopServices::openUrl(QUrl("https://rpcs3.net/patreon")); }); connect(ui->patreon, &QPushButton::clicked, [] { QDesktopServices::openUrl(QUrl("https://rpcs3.net/patreon")); });
connect(ui->discord, &QPushButton::clicked, [] { QDesktopServices::openUrl(QUrl("https://discord.me/RPCS3")); }); connect(ui->discord, &QPushButton::clicked, [] { QDesktopServices::openUrl(QUrl("https://discord.gg/rpcs3")); });
connect(ui->wiki, &QPushButton::clicked, [] { QDesktopServices::openUrl(QUrl("https://wiki.rpcs3.net/index.php?title=Main_Page")); }); connect(ui->wiki, &QPushButton::clicked, [] { QDesktopServices::openUrl(QUrl("https://wiki.rpcs3.net/index.php?title=Main_Page")); });
connect(ui->close, &QPushButton::clicked, this, &QWidget::close); connect(ui->close, &QPushButton::clicked, this, &QWidget::close);
} }

View file

@ -2363,7 +2363,7 @@ void game_list_frame::BatchActionBySerials(progress_dialog* pdlg, const std::set
connect(future_watcher, &QFutureWatcher<void>::finished, this, [=, this]() connect(future_watcher, &QFutureWatcher<void>::finished, this, [=, this]()
{ {
pdlg->setLabelText(progressLabel.arg(*index).arg(serials_size)); pdlg->setLabelText(progressLabel.arg(+*index).arg(serials_size));
pdlg->setCancelButtonText(tr("OK")); pdlg->setCancelButtonText(tr("OK"));
QApplication::beep(); QApplication::beep();
@ -2396,7 +2396,7 @@ void game_list_frame::BatchActionBySerials(progress_dialog* pdlg, const std::set
return; return;
} }
pdlg->setLabelText(progressLabel.arg(*index).arg(serials_size)); pdlg->setLabelText(progressLabel.arg(+*index).arg(serials_size));
pdlg->setCancelButtonText(tr("OK")); pdlg->setCancelButtonText(tr("OK"));
connect(pdlg, &progress_dialog::canceled, this, [pdlg](){ pdlg->deleteLater(); }); connect(pdlg, &progress_dialog::canceled, this, [pdlg](){ pdlg->deleteLater(); });
QApplication::beep(); QApplication::beep();

View file

@ -68,8 +68,6 @@ gs_frame::gs_frame(QScreen* screen, const QRect& geometry, const QIcon& appIcon,
, m_start_games_fullscreen(force_fullscreen) , m_start_games_fullscreen(force_fullscreen)
, m_renderer(g_cfg.video.renderer) , m_renderer(g_cfg.video.renderer)
{ {
load_gui_settings();
m_window_title = Emu.GetFormattedTitle(0); m_window_title = Emu.GetFormattedTitle(0);
if (!g_cfg_recording.load()) if (!g_cfg_recording.load())
@ -121,8 +119,7 @@ gs_frame::gs_frame(QScreen* screen, const QRect& geometry, const QIcon& appIcon,
create(); create();
} }
m_shortcut_handler = new shortcut_handler(gui::shortcuts::shortcut_handler_id::game_window, this, m_gui_settings); load_gui_settings();
connect(m_shortcut_handler, &shortcut_handler::shortcut_activated, this, &gs_frame::handle_shortcut);
// Change cursor when in fullscreen. // Change cursor when in fullscreen.
connect(this, &QWindow::visibilityChanged, this, [this](QWindow::Visibility visibility) connect(this, &QWindow::visibilityChanged, this, [this](QWindow::Visibility visibility)
@ -174,6 +171,20 @@ void gs_frame::load_gui_settings()
m_lock_mouse_in_fullscreen = m_gui_settings->GetValue(gui::gs_lockMouseFs).toBool(); m_lock_mouse_in_fullscreen = m_gui_settings->GetValue(gui::gs_lockMouseFs).toBool();
m_hide_mouse_after_idletime = m_gui_settings->GetValue(gui::gs_hideMouseIdle).toBool(); m_hide_mouse_after_idletime = m_gui_settings->GetValue(gui::gs_hideMouseIdle).toBool();
m_hide_mouse_idletime = m_gui_settings->GetValue(gui::gs_hideMouseIdleTime).toUInt(); m_hide_mouse_idletime = m_gui_settings->GetValue(gui::gs_hideMouseIdleTime).toUInt();
if (m_disable_kb_hotkeys)
{
if (m_shortcut_handler)
{
m_shortcut_handler->deleteLater();
m_shortcut_handler = nullptr;
}
}
else if (!m_shortcut_handler)
{
m_shortcut_handler = new shortcut_handler(gui::shortcuts::shortcut_handler_id::game_window, this, m_gui_settings);
connect(m_shortcut_handler, &shortcut_handler::shortcut_activated, this, &gs_frame::handle_shortcut);
}
} }
void gs_frame::update_shortcuts() void gs_frame::update_shortcuts()
@ -650,9 +661,6 @@ void gs_frame::show()
} }
} }
}); });
// if we do this before show, the QWinTaskbarProgress won't show
m_progress_indicator->show(this);
} }
display_handle_t gs_frame::handle() const display_handle_t gs_frame::handle() const
@ -1101,7 +1109,7 @@ void gs_frame::handle_cursor(QWindow::Visibility visibility, bool visibility_cha
void gs_frame::mouse_hide_timeout() void gs_frame::mouse_hide_timeout()
{ {
// Our idle timeout occured, so we update the cursor // Our idle timeout occurred, so we update the cursor
if (m_hide_mouse_after_idletime && m_show_mouse) if (m_hide_mouse_after_idletime && m_show_mouse)
{ {
handle_cursor(visibility(), false, false, false); handle_cursor(visibility(), false, false, false);

View file

@ -27,6 +27,7 @@
#include "Emu/vfs_config.h" #include "Emu/vfs_config.h"
#include "util/init_mutex.hpp" #include "util/init_mutex.hpp"
#include "util/console.h" #include "util/console.h"
#include "qt_video_source.h"
#include "trophy_notification_helper.h" #include "trophy_notification_helper.h"
#include "save_data_dialog.h" #include "save_data_dialog.h"
#include "msg_dialog_frame.h" #include "msg_dialog_frame.h"
@ -955,6 +956,8 @@ void gui_application::InitializeCallbacks()
}); });
}; };
callbacks.make_video_source = [](){ return std::make_unique<qt_video_source_wrapper>(); };
Emu.SetCallbacks(std::move(callbacks)); Emu.SetCallbacks(std::move(callbacks));
} }

View file

@ -226,49 +226,6 @@ bool main_window::Init([[maybe_unused]] bool with_cli_boot)
ui->sysPauseAct->setEnabled(enable_play_last); ui->sysPauseAct->setEnabled(enable_play_last);
ui->toolbar_start->setEnabled(enable_play_last); ui->toolbar_start->setEnabled(enable_play_last);
// create tool buttons for the taskbar thumbnail
#ifdef HAS_QT_WIN_STUFF
m_thumb_bar = new QWinThumbnailToolBar(this);
m_thumb_bar->setWindow(windowHandle());
m_thumb_playPause = new QWinThumbnailToolButton(m_thumb_bar);
m_thumb_playPause->setToolTip(start_tooltip);
m_thumb_playPause->setIcon(m_icon_thumb_play);
m_thumb_playPause->setEnabled(enable_play_last);
m_thumb_stop = new QWinThumbnailToolButton(m_thumb_bar);
m_thumb_stop->setToolTip(tr("Stop"));
m_thumb_stop->setIcon(m_icon_thumb_stop);
m_thumb_stop->setEnabled(false);
m_thumb_restart = new QWinThumbnailToolButton(m_thumb_bar);
m_thumb_restart->setToolTip(tr("Restart"));
m_thumb_restart->setIcon(m_icon_thumb_restart);
m_thumb_restart->setEnabled(false);
m_thumb_bar->addButton(m_thumb_playPause);
m_thumb_bar->addButton(m_thumb_stop);
m_thumb_bar->addButton(m_thumb_restart);
RepaintThumbnailIcons();
connect(m_thumb_stop, &QWinThumbnailToolButton::clicked, this, []()
{
gui_log.notice("User clicked the stop button on thumbnail toolbar");
Emu.GracefulShutdown(false, true);
});
connect(m_thumb_restart, &QWinThumbnailToolButton::clicked, this, []()
{
gui_log.notice("User clicked the restart button on thumbnail toolbar");
Emu.Restart();
});
connect(m_thumb_playPause, &QWinThumbnailToolButton::clicked, this, [this]()
{
gui_log.notice("User clicked the playPause button on thumbnail toolbar");
OnPlayOrPause();
});
#endif
// RPCS3 Updater // RPCS3 Updater
QMenu* download_menu = new QMenu(tr("Update Available!")); QMenu* download_menu = new QMenu(tr("Update Available!"));
@ -1868,19 +1825,6 @@ void main_window::RepaintThumbnailIcons()
{ {
return gui::utils::get_colorized_icon(QPixmap::fromImage(gui::utils::get_opaque_image_area(path)), Qt::black, new_color); return gui::utils::get_colorized_icon(QPixmap::fromImage(gui::utils::get_opaque_image_area(path)), Qt::black, new_color);
}; };
#ifdef HAS_QT_WIN_STUFF
if (!m_thumb_bar) return;
m_icon_thumb_play = icon(":/Icons/play.png");
m_icon_thumb_pause = icon(":/Icons/pause.png");
m_icon_thumb_stop = icon(":/Icons/stop.png");
m_icon_thumb_restart = icon(":/Icons/restart.png");
m_thumb_playPause->setIcon(Emu.IsRunning() || Emu.IsStarting() ? m_icon_thumb_pause : m_icon_thumb_play);
m_thumb_stop->setIcon(m_icon_thumb_stop);
m_thumb_restart->setIcon(m_icon_thumb_restart);
#endif
} }
void main_window::RepaintToolBarIcons() void main_window::RepaintToolBarIcons()
@ -1971,12 +1915,6 @@ void main_window::OnEmuRun(bool /*start_playtime*/)
m_debugger_frame->EnableButtons(true); m_debugger_frame->EnableButtons(true);
#ifdef HAS_QT_WIN_STUFF
m_thumb_stop->setToolTip(stop_tooltip);
m_thumb_restart->setToolTip(restart_tooltip);
m_thumb_playPause->setToolTip(pause_tooltip);
m_thumb_playPause->setIcon(m_icon_thumb_pause);
#endif
ui->sysPauseAct->setText(tr("&Pause")); ui->sysPauseAct->setText(tr("&Pause"));
ui->sysPauseAct->setIcon(m_icon_pause); ui->sysPauseAct->setIcon(m_icon_pause);
ui->toolbar_start->setIcon(m_icon_pause); ui->toolbar_start->setIcon(m_icon_pause);
@ -1996,12 +1934,6 @@ void main_window::OnEmuResume() const
const QString pause_tooltip = tr("Pause %0").arg(title); const QString pause_tooltip = tr("Pause %0").arg(title);
const QString stop_tooltip = tr("Stop %0").arg(title); const QString stop_tooltip = tr("Stop %0").arg(title);
#ifdef HAS_QT_WIN_STUFF
m_thumb_stop->setToolTip(stop_tooltip);
m_thumb_restart->setToolTip(restart_tooltip);
m_thumb_playPause->setToolTip(pause_tooltip);
m_thumb_playPause->setIcon(m_icon_thumb_pause);
#endif
ui->sysPauseAct->setText(tr("&Pause")); ui->sysPauseAct->setText(tr("&Pause"));
ui->sysPauseAct->setIcon(m_icon_pause); ui->sysPauseAct->setIcon(m_icon_pause);
ui->toolbar_start->setIcon(m_icon_pause); ui->toolbar_start->setIcon(m_icon_pause);
@ -2015,10 +1947,6 @@ void main_window::OnEmuPause() const
const QString title = GetCurrentTitle(); const QString title = GetCurrentTitle();
const QString resume_tooltip = tr("Resume %0").arg(title); const QString resume_tooltip = tr("Resume %0").arg(title);
#ifdef HAS_QT_WIN_STUFF
m_thumb_playPause->setToolTip(resume_tooltip);
m_thumb_playPause->setIcon(m_icon_thumb_play);
#endif
ui->sysPauseAct->setText(tr("&Resume")); ui->sysPauseAct->setText(tr("&Resume"));
ui->sysPauseAct->setIcon(m_icon_play); ui->sysPauseAct->setIcon(m_icon_play);
ui->toolbar_start->setIcon(m_icon_play); ui->toolbar_start->setIcon(m_icon_play);
@ -2039,10 +1967,6 @@ void main_window::OnEmuStop()
ui->sysPauseAct->setText(tr("&Play")); ui->sysPauseAct->setText(tr("&Play"));
ui->sysPauseAct->setIcon(m_icon_play); ui->sysPauseAct->setIcon(m_icon_play);
#ifdef HAS_QT_WIN_STUFF
m_thumb_playPause->setToolTip(play_tooltip);
m_thumb_playPause->setIcon(m_icon_thumb_play);
#endif
EnableMenus(false); EnableMenus(false);
@ -2061,10 +1985,6 @@ void main_window::OnEmuStop()
ui->toolbar_start->setText(tr("Restart")); ui->toolbar_start->setText(tr("Restart"));
ui->toolbar_start->setToolTip(restart_tooltip); ui->toolbar_start->setToolTip(restart_tooltip);
ui->sysRebootAct->setEnabled(true); ui->sysRebootAct->setEnabled(true);
#ifdef HAS_QT_WIN_STUFF
m_thumb_restart->setToolTip(restart_tooltip);
m_thumb_restart->setEnabled(true);
#endif
} }
ui->batchRemoveShaderCachesAct->setEnabled(true); ui->batchRemoveShaderCachesAct->setEnabled(true);
@ -2106,10 +2026,7 @@ void main_window::OnEmuReady() const
const QString play_tooltip = tr("Play %0").arg(title); const QString play_tooltip = tr("Play %0").arg(title);
m_debugger_frame->EnableButtons(true); m_debugger_frame->EnableButtons(true);
#ifdef HAS_QT_WIN_STUFF
m_thumb_playPause->setToolTip(play_tooltip);
m_thumb_playPause->setIcon(m_icon_thumb_play);
#endif
ui->sysPauseAct->setText(tr("&Play")); ui->sysPauseAct->setText(tr("&Play"));
ui->sysPauseAct->setIcon(m_icon_play); ui->sysPauseAct->setIcon(m_icon_play);
ui->toolbar_start->setIcon(m_icon_play); ui->toolbar_start->setIcon(m_icon_play);
@ -2133,13 +2050,6 @@ void main_window::OnEmuReady() const
void main_window::EnableMenus(bool enabled) const void main_window::EnableMenus(bool enabled) const
{ {
// Thumbnail Buttons
#ifdef HAS_QT_WIN_STUFF
m_thumb_playPause->setEnabled(enabled);
m_thumb_stop->setEnabled(enabled);
m_thumb_restart->setEnabled(enabled);
#endif
// Toolbar // Toolbar
ui->toolbar_start->setEnabled(enabled); ui->toolbar_start->setEnabled(enabled);
ui->toolbar_stop->setEnabled(enabled); ui->toolbar_stop->setEnabled(enabled);
@ -3588,16 +3498,10 @@ void main_window::CreateDockWindows()
ui->toolbar_start->setEnabled(enable_play_buttons); ui->toolbar_start->setEnabled(enable_play_buttons);
ui->sysPauseAct->setEnabled(enable_play_buttons); ui->sysPauseAct->setEnabled(enable_play_buttons);
#ifdef HAS_QT_WIN_STUFF
m_thumb_playPause->setEnabled(enable_play_buttons);
#endif
if (!tooltip.isEmpty()) if (!tooltip.isEmpty())
{ {
ui->toolbar_start->setToolTip(tooltip); ui->toolbar_start->setToolTip(tooltip);
#ifdef HAS_QT_WIN_STUFF
m_thumb_playPause->setToolTip(tooltip);
#endif
} }
} }

View file

@ -1,10 +1,5 @@
#pragma once #pragma once
#ifdef HAS_QT_WIN_STUFF
#include <QWinThumbnailToolBar>
#include <QWinThumbnailToolButton>
#endif
#include <QActionGroup> #include <QActionGroup>
#include <QMainWindow> #include <QMainWindow>
#include <QIcon> #include <QIcon>
@ -61,17 +56,6 @@ class main_window : public QMainWindow
QIcon m_icon_fullscreen_on; QIcon m_icon_fullscreen_on;
QIcon m_icon_fullscreen_off; QIcon m_icon_fullscreen_off;
#ifdef HAS_QT_WIN_STUFF
QIcon m_icon_thumb_play;
QIcon m_icon_thumb_pause;
QIcon m_icon_thumb_stop;
QIcon m_icon_thumb_restart;
QWinThumbnailToolBar *m_thumb_bar = nullptr;
QWinThumbnailToolButton *m_thumb_playPause = nullptr;
QWinThumbnailToolButton *m_thumb_stop = nullptr;
QWinThumbnailToolButton *m_thumb_restart = nullptr;
#endif
enum class drop_type enum class drop_type
{ {
drop_error, drop_error,

View file

@ -131,9 +131,6 @@ void msg_dialog_frame::Create(const std::string& msg, const std::string& title)
// Fix size // Fix size
m_dialog->layout()->setSizeConstraint(QLayout::SetFixedSize); m_dialog->layout()->setSizeConstraint(QLayout::SetFixedSize);
m_dialog->show(); m_dialog->show();
// if we do this before, the QWinTaskbarProgress won't show
if (m_progress_indicator) m_progress_indicator->show(m_dialog->windowHandle());
} }
void msg_dialog_frame::Close(bool success) void msg_dialog_frame::Close(bool success)

View file

@ -51,34 +51,3 @@ void progress_dialog::SignalFailure() const
QApplication::beep(); QApplication::beep();
} }
void progress_dialog::show_progress_indicator()
{
// Try to find a window handle first
QWindow* handle = windowHandle();
for (QWidget* ancestor = this; !handle && ancestor;)
{
ancestor = static_cast<QWidget*>(ancestor->parent());
if (ancestor) handle = ancestor->windowHandle();
}
m_progress_indicator->show(handle);
}
void progress_dialog::setVisible(bool visible)
{
if (visible)
{
if (!isVisible())
{
show_progress_indicator();
}
}
else if (isVisible())
{
m_progress_indicator->hide();
}
QProgressDialog::setVisible(visible);
}

View file

@ -14,10 +14,6 @@ public:
void SetDeleteOnClose(); void SetDeleteOnClose();
void SignalFailure() const; void SignalFailure() const;
void show_progress_indicator();
void setVisible(bool visible) override;
private: private:
std::unique_ptr<progress_indicator> m_progress_indicator; std::unique_ptr<progress_indicator> m_progress_indicator;
}; };

View file

@ -1,106 +1,57 @@
#include "stdafx.h"
#include "progress_indicator.h" #include "progress_indicator.h"
#ifdef HAS_QT_WIN_STUFF #if HAVE_QTDBUS
#include <QCoreApplication>
#include <QWinTaskbarProgress>
#elif HAVE_QTDBUS
#include <QtDBus/QDBusMessage> #include <QtDBus/QDBusMessage>
#include <QtDBus/QDBusConnection> #include <QtDBus/QDBusConnection>
#endif #endif
progress_indicator::progress_indicator(int minimum, int maximum) progress_indicator::progress_indicator(int minimum, int maximum)
{ {
#ifdef HAS_QT_WIN_STUFF
m_tb_button = std::make_unique<QWinTaskbarButton>();
m_tb_button->progress()->setRange(minimum, maximum);
m_tb_button->progress()->setVisible(false);
#else
m_minimum = minimum; m_minimum = minimum;
m_maximum = maximum; m_maximum = maximum;
#if HAVE_QTDBUS #if HAVE_QTDBUS
update_progress(0, true, false); update_progress(0, true, false);
#endif #endif
#endif
} }
progress_indicator::~progress_indicator() progress_indicator::~progress_indicator()
{ {
#ifdef HAS_QT_WIN_STUFF #if HAVE_QTDBUS
// QWinTaskbarProgress::hide() will crash if the application is already about to close, even if the object is not null.
if (!QCoreApplication::closingDown())
{
m_tb_button->progress()->hide();
}
#elif HAVE_QTDBUS
update_progress(0, false, false); update_progress(0, false, false);
#endif #endif
} }
void progress_indicator::show(QWindow* window)
{
#ifdef HAS_QT_WIN_STUFF
m_tb_button->setWindow(window);
m_tb_button->progress()->show();
#else
Q_UNUSED(window);
#endif
}
void progress_indicator::hide()
{
#ifdef HAS_QT_WIN_STUFF
m_tb_button->progress()->hide();
#endif
}
int progress_indicator::value() const int progress_indicator::value() const
{ {
#ifdef HAS_QT_WIN_STUFF
return m_tb_button->progress()->value();
#else
return m_value; return m_value;
#endif
} }
void progress_indicator::set_value(int value) void progress_indicator::set_value(int value)
{ {
#ifdef HAS_QT_WIN_STUFF
m_tb_button->progress()->setValue(std::clamp(value, m_tb_button->progress()->minimum(), m_tb_button->progress()->maximum()));
#else
m_value = std::clamp(value, m_minimum, m_maximum); m_value = std::clamp(value, m_minimum, m_maximum);
#if HAVE_QTDBUS #if HAVE_QTDBUS
update_progress(m_value, true, false); update_progress(m_value, true, false);
#endif #endif
#endif
} }
void progress_indicator::set_range(int minimum, int maximum) void progress_indicator::set_range(int minimum, int maximum)
{ {
#ifdef HAS_QT_WIN_STUFF
m_tb_button->progress()->setRange(minimum, maximum);
#else
m_minimum = minimum; m_minimum = minimum;
m_maximum = maximum; m_maximum = maximum;
#endif
} }
void progress_indicator::reset() void progress_indicator::reset()
{ {
#ifdef HAS_QT_WIN_STUFF
m_tb_button->progress()->reset();
#else
m_value = m_minimum; m_value = m_minimum;
#if HAVE_QTDBUS #if HAVE_QTDBUS
update_progress(m_value, false, false); update_progress(m_value, false, false);
#endif #endif
#endif
} }
void progress_indicator::signal_failure() void progress_indicator::signal_failure()
{ {
#ifdef HAS_QT_WIN_STUFF #if HAVE_QTDBUS
m_tb_button->progress()->stop();
#elif HAVE_QTDBUS
update_progress(0, false, true); update_progress(0, false, true);
#endif #endif
} }

View file

@ -1,20 +1,11 @@
#pragma once #pragma once
#include <QWindow>
#ifdef HAS_QT_WIN_STUFF
#include <QWinTaskbarButton>
#endif
class progress_indicator class progress_indicator
{ {
public: public:
progress_indicator(int minimum, int maximum); progress_indicator(int minimum, int maximum);
~progress_indicator(); ~progress_indicator();
void show(QWindow* window);
void hide();
int value() const; int value() const;
void set_value(int value); void set_value(int value);
@ -23,15 +14,10 @@ public:
void signal_failure(); void signal_failure();
private: private:
#ifdef HAS_QT_WIN_STUFF
std::unique_ptr<QWinTaskbarButton> m_tb_button;
#else
int m_value = 0; int m_value = 0;
int m_minimum = 0; int m_minimum = 0;
int m_maximum = 100; int m_maximum = 100;
#if HAVE_QTDBUS #if HAVE_QTDBUS
void update_progress(int progress, bool progress_visible, bool urgent); void update_progress(int progress, bool progress_visible, bool urgent);
#endif #endif
#endif
}; };

View file

@ -14,9 +14,9 @@ qt_video_source::~qt_video_source()
stop_movie(); stop_movie();
} }
void qt_video_source::set_video_path(const std::string& path) void qt_video_source::set_video_path(const std::string& video_path)
{ {
m_video_path = QString::fromStdString(path); m_video_path = QString::fromStdString(video_path);
} }
void qt_video_source::set_active(bool active) void qt_video_source::set_active(bool active)
@ -209,14 +209,14 @@ qt_video_source_wrapper::~qt_video_source_wrapper()
}); });
} }
void qt_video_source_wrapper::set_video_path(const std::string& path) void qt_video_source_wrapper::set_video_path(const std::string& video_path)
{ {
Emu.BlockingCallFromMainThread([this, &path]() Emu.CallFromMainThread([this, path = video_path]()
{ {
m_qt_video_source = std::make_unique<qt_video_source>(); m_qt_video_source = std::make_unique<qt_video_source>();
m_qt_video_source->m_image_change_callback = [this](const QVideoFrame& frame) m_qt_video_source->m_image_change_callback = [this](const QVideoFrame& frame)
{ {
std::lock_guard lock(m_qt_video_source->m_image_mutex); std::unique_lock lock(m_qt_video_source->m_image_mutex);
if (m_qt_video_source->m_movie) if (m_qt_video_source->m_movie)
{ {
@ -236,12 +236,30 @@ void qt_video_source_wrapper::set_video_path(const std::string& path)
{ {
m_qt_video_source->m_image.convertTo(QImage::Format_RGBA8888); m_qt_video_source->m_image.convertTo(QImage::Format_RGBA8888);
} }
lock.unlock();
notify_update();
}; };
m_qt_video_source->set_video_path(path); m_qt_video_source->set_video_path(path);
});
}
void qt_video_source_wrapper::set_active(bool active)
{
Emu.CallFromMainThread([this, active]()
{
m_qt_video_source->set_active(true); m_qt_video_source->set_active(true);
}); });
} }
bool qt_video_source_wrapper::get_active() const
{
ensure(m_qt_video_source);
return m_qt_video_source->get_active();
}
void qt_video_source_wrapper::get_image(std::vector<u8>& data, int& w, int& h, int& ch, int& bpp) void qt_video_source_wrapper::get_image(std::vector<u8>& data, int& w, int& h, int& ch, int& bpp)
{ {
ensure(m_qt_video_source); ensure(m_qt_video_source);

View file

@ -17,17 +17,14 @@ public:
qt_video_source(); qt_video_source();
virtual ~qt_video_source(); virtual ~qt_video_source();
void set_video_path(const std::string& path) override; void set_video_path(const std::string& video_path) override;
const QString& video_path() const { return m_video_path; } const QString& video_path() const { return m_video_path; }
void get_image(std::vector<u8>& data, int& w, int& h, int& ch, int& bpp) override; void get_image(std::vector<u8>& data, int& w, int& h, int& ch, int& bpp) override;
bool has_new() const override { return m_has_new; } bool has_new() const override { return m_has_new; }
virtual void set_active(bool active); void set_active(bool active) override;
[[nodiscard]] bool get_active() const bool get_active() const override { return m_active; }
{
return m_active;
}
void start_movie(); void start_movie();
void stop_movie(); void stop_movie();
@ -67,9 +64,11 @@ public:
qt_video_source_wrapper() : video_source() {} qt_video_source_wrapper() : video_source() {}
virtual ~qt_video_source_wrapper(); virtual ~qt_video_source_wrapper();
void set_video_path(const std::string& path) override; void set_video_path(const std::string& video_path) override;
void get_image(std::vector<u8>& data, int& w, int& h, int& ch, int& bpp) override; void set_active(bool active) override;
bool get_active() const override;
bool has_new() const override { return m_qt_video_source && m_qt_video_source->has_new(); } bool has_new() const override { return m_qt_video_source && m_qt_video_source->has_new(); }
void get_image(std::vector<u8>& data, int& w, int& h, int& ch, int& bpp) override;
private: private:
std::unique_ptr<qt_video_source> m_qt_video_source; std::unique_ptr<qt_video_source> m_qt_video_source;

View file

@ -12,7 +12,7 @@
LOG_CHANNEL(cellSaveData); LOG_CHANNEL(cellSaveData);
s32 save_data_dialog::ShowSaveDataList(std::vector<SaveDataEntry>& save_entries, s32 focused, u32 op, vm::ptr<CellSaveDataListSet> listSet, bool enable_overlay) s32 save_data_dialog::ShowSaveDataList(const std::string& base_dir, std::vector<SaveDataEntry>& save_entries, s32 focused, u32 op, vm::ptr<CellSaveDataListSet> listSet, bool enable_overlay)
{ {
cellSaveData.notice("ShowSaveDataList(save_entries=%d, focused=%d, op=0x%x, listSet=*0x%x, enable_overlay=%d)", save_entries.size(), focused, op, listSet, enable_overlay); cellSaveData.notice("ShowSaveDataList(save_entries=%d, focused=%d, op=0x%x, listSet=*0x%x, enable_overlay=%d)", save_entries.size(), focused, op, listSet, enable_overlay);
@ -29,7 +29,7 @@ s32 save_data_dialog::ShowSaveDataList(std::vector<SaveDataEntry>& save_entries,
{ {
cellSaveData.notice("ShowSaveDataList: Showing native UI dialog"); cellSaveData.notice("ShowSaveDataList: Showing native UI dialog");
const s32 result = manager->create<rsx::overlays::save_dialog>()->show(save_entries, focused, op, listSet, enable_overlay); const s32 result = manager->create<rsx::overlays::save_dialog>()->show(base_dir, save_entries, focused, op, listSet, enable_overlay);
if (result != rsx::overlays::user_interface::selection_code::error) if (result != rsx::overlays::user_interface::selection_code::error)
{ {
cellSaveData.notice("ShowSaveDataList: Native UI dialog returned with selection %d", result); cellSaveData.notice("ShowSaveDataList: Native UI dialog returned with selection %d", result);

View file

@ -6,5 +6,5 @@
class save_data_dialog : public SaveDialogBase class save_data_dialog : public SaveDialogBase
{ {
public: public:
s32 ShowSaveDataList(std::vector<SaveDataEntry>& save_entries, s32 focused, u32 op, vm::ptr<CellSaveDataListSet> listSet, bool enable_overlay) override; s32 ShowSaveDataList(const std::string& base_dir, std::vector<SaveDataEntry>& save_entries, s32 focused, u32 op, vm::ptr<CellSaveDataListSet> listSet, bool enable_overlay) override;
}; };

View file

@ -270,13 +270,12 @@ std::vector<SaveDataEntry> save_manager_dialog::GetSaveEntries(const std::string
return; return;
} }
SaveDataEntry save_entry2; SaveDataEntry save_entry2 {};
save_entry2.dirName = psf::get_string(psf, "SAVEDATA_DIRECTORY"); save_entry2.dirName = psf::get_string(psf, "SAVEDATA_DIRECTORY");
save_entry2.listParam = psf::get_string(psf, "SAVEDATA_LIST_PARAM"); save_entry2.listParam = psf::get_string(psf, "SAVEDATA_LIST_PARAM");
save_entry2.title = psf::get_string(psf, "TITLE"); save_entry2.title = psf::get_string(psf, "TITLE");
save_entry2.subtitle = psf::get_string(psf, "SUB_TITLE"); save_entry2.subtitle = psf::get_string(psf, "SUB_TITLE");
save_entry2.details = psf::get_string(psf, "DETAIL"); save_entry2.details = psf::get_string(psf, "DETAIL");
save_entry2.size = 0;
for (const auto& entry2 : fs::dir(base_dir + entry.name)) for (const auto& entry2 : fs::dir(base_dir + entry.name))
{ {

View file

@ -76,9 +76,9 @@ shortcut_settings::shortcut_settings()
{ shortcut::gw_frame_limit, shortcut_info{ "game_window_frame_limit", tr("Toggle Framelimit"), "Ctrl+F10", shortcut_handler_id::game_window, false } }, { shortcut::gw_frame_limit, shortcut_info{ "game_window_frame_limit", tr("Toggle Framelimit"), "Ctrl+F10", shortcut_handler_id::game_window, false } },
{ shortcut::gw_toggle_mouse_and_keyboard, shortcut_info{ "game_window_toggle_mouse_and_keyboard", tr("Toggle Keyboard"), "Ctrl+F11", shortcut_handler_id::game_window, false } }, { shortcut::gw_toggle_mouse_and_keyboard, shortcut_info{ "game_window_toggle_mouse_and_keyboard", tr("Toggle Keyboard"), "Ctrl+F11", shortcut_handler_id::game_window, false } },
{ shortcut::gw_home_menu, shortcut_info{ "gw_home_menu", tr("Open Home Menu"), "Shift+F10", shortcut_handler_id::game_window, false } }, { shortcut::gw_home_menu, shortcut_info{ "gw_home_menu", tr("Open Home Menu"), "Shift+F10", shortcut_handler_id::game_window, false } },
{ shortcut::gw_mute_unmute, shortcut_info{ "gw_mute_unmute", tr("Mute/Unmute Audio"), "Shift+M", shortcut_handler_id::game_window, false } }, { shortcut::gw_mute_unmute, shortcut_info{ "gw_mute_unmute", tr("Mute/Unmute Audio"), "Ctrl+Shift+M", shortcut_handler_id::game_window, false } },
{ shortcut::gw_volume_up, shortcut_info{ "gw_volume_up", tr("Volume Up"), "Shift++", shortcut_handler_id::game_window, true } }, { shortcut::gw_volume_up, shortcut_info{ "gw_volume_up", tr("Volume Up"), "Ctrl+Shift++", shortcut_handler_id::game_window, true } },
{ shortcut::gw_volume_down, shortcut_info{ "gw_volume_down", tr("Volume Down"), "Shift+-", shortcut_handler_id::game_window, true } }, { shortcut::gw_volume_down, shortcut_info{ "gw_volume_down", tr("Volume Down"), "Ctrl+Shift+-", shortcut_handler_id::game_window, true } },
}) })
{ {
} }

View file

@ -504,11 +504,29 @@ bool update_manager::handle_rpcs3(const QByteArray& data, bool auto_accept)
ISzAlloc allocImp = g_Alloc; ISzAlloc allocImp = g_Alloc;
ISzAlloc allocTempImp = g_Alloc; ISzAlloc allocTempImp = g_Alloc;
if (const WRes res = InFile_Open(&archiveStream.file, tmpfile_path.c_str())) const auto WRes_to_string = [](WRes res)
{ {
update_log.error("Failed to open temporary storage file: '%s' (error=%d)", tmpfile_path, static_cast<u64>(res)); #ifdef _WIN32
return fmt::format("0x%x='%s'", res, std::system_category().message(HRESULT_FROM_WIN32(res)));
#else
return fmt::format("0x%x='%s'", res, strerror(res));
#endif
};
#ifdef _WIN32
const std::wstring tmpfile_path_w = utf8_to_wchar(tmpfile_path);
if (const WRes res = InFile_OpenW(&archiveStream.file, tmpfile_path_w.c_str()))
{
update_log.error("Failed to open temporary storage file: '%s' (error=%s)", tmpfile_path_w.c_str(), WRes_to_string(res));
return false; return false;
} }
#else
if (const WRes res = InFile_Open(&archiveStream.file, tmpfile_path.c_str()))
{
update_log.error("Failed to open temporary storage file: '%s' (error=%s)", tmpfile_path, WRes_to_string(res));
return false;
}
#endif
FileInStream_CreateVTable(&archiveStream); FileInStream_CreateVTable(&archiveStream);
LookToRead2_CreateVTable(&lookStream, False); LookToRead2_CreateVTable(&lookStream, False);
@ -529,22 +547,14 @@ bool update_manager::handle_rpcs3(const QByteArray& data, bool auto_accept)
CrcGenerateTable(); CrcGenerateTable();
SzArEx_Init(&db); SzArEx_Init(&db);
auto error_free7z = [&]() const auto error_free7z = [&]()
{ {
SzArEx_Free(&db, &allocImp); SzArEx_Free(&db, &allocImp);
ISzAlloc_Free(&allocImp, lookStream.buf); ISzAlloc_Free(&allocImp, lookStream.buf);
const WRes res2 = File_Close(&archiveStream.file); const WRes res2 = File_Close(&archiveStream.file);
if (res2) update_log.warning("7z failed to close file (error=%d)", static_cast<u64>(res2)); if (res2) update_log.warning("7z failed to close file (error=%s)", WRes_to_string(res2));
if (res) update_log.error("7z decoder error: %s", WRes_to_string(res));
switch (res)
{
case SZ_OK: break;
case SZ_ERROR_UNSUPPORTED: update_log.error("7z decoder doesn't support this archive"); break;
case SZ_ERROR_MEM: update_log.error("7z decoder failed to allocate memory"); break;
case SZ_ERROR_CRC: update_log.error("7z decoder CRC error"); break;
default: update_log.error("7z decoder error: %d", static_cast<u64>(res)); break;
}
}; };
if (res != SZ_OK) if (res != SZ_OK)
@ -598,7 +608,7 @@ bool update_manager::handle_rpcs3(const QByteArray& data, bool auto_accept)
} }
SzArEx_GetFileNameUtf16(&db, i, temp_u16); SzArEx_GetFileNameUtf16(&db, i, temp_u16);
memset(temp_u8, 0, sizeof(temp_u8)); std::memset(temp_u8, 0, sizeof(temp_u8));
// Simplistic conversion to UTF-8 // Simplistic conversion to UTF-8
for (usz index = 0; index < len; index++) for (usz index = 0; index < len; index++)
{ {

View file

@ -40,7 +40,7 @@ welcome_dialog::welcome_dialog(std::shared_ptr<gui_settings> gui_settings, bool
.arg(gui::utils::make_link(tr("Quickstart"), "https://rpcs3.net/quickstart")) .arg(gui::utils::make_link(tr("Quickstart"), "https://rpcs3.net/quickstart"))
.arg(gui::utils::make_link(tr("FAQ"), "https://rpcs3.net/faq")) .arg(gui::utils::make_link(tr("FAQ"), "https://rpcs3.net/faq"))
.arg(gui::utils::make_link(tr("Forums"), "https://forums.rpcs3.net")) .arg(gui::utils::make_link(tr("Forums"), "https://forums.rpcs3.net"))
.arg(gui::utils::make_link(tr("Discord"), "https://discord.me/RPCS3")))); .arg(gui::utils::make_link(tr("Discord"), "https://discord.gg/rpcs3"))));
#ifdef __APPLE__ #ifdef __APPLE__
ui->create_applications_menu_shortcut->setText(tr("&Create Launchpad shortcut")); ui->create_applications_menu_shortcut->setText(tr("&Create Launchpad shortcut"));

View file

@ -1192,7 +1192,7 @@ constexpr void write_to_ptr(U&& array, usz pos, const T& value)
{ {
static_assert(sizeof(T) % sizeof(array[0]) == 0); static_assert(sizeof(T) % sizeof(array[0]) == 0);
if (!std::is_constant_evaluated()) if (!std::is_constant_evaluated())
std::memcpy(&array[pos], &value, sizeof(value)); std::memcpy(static_cast<void*>(&array[pos]), &value, sizeof(value));
else else
ensure(!"Unimplemented"); ensure(!"Unimplemented");
} }

View file

@ -1,20 +1,33 @@
#pragma once #pragma once
#include "types.hpp" #include "types.hpp"
#include <functional>
class video_source class video_source
{ {
public: public:
video_source() {}; video_source() {};
virtual ~video_source() {}; virtual ~video_source() {};
virtual void set_video_path(const std::string& path) { static_cast<void>(path); } virtual void set_video_path(const std::string& video_path) = 0;
virtual bool has_new() const { return false; }; virtual void set_active(bool active) = 0;
virtual void get_image(std::vector<u8>& data, int& w, int& h, int& ch, int& bpp) virtual bool get_active() const = 0;
virtual bool has_new() const = 0;
virtual void get_image(std::vector<u8>& data, int& w, int& h, int& ch, int& bpp) = 0;
void set_update_callback(std::function<void()> callback)
{ {
static_cast<void>(data); m_update_callback = callback;
static_cast<void>(w);
static_cast<void>(h);
static_cast<void>(ch);
static_cast<void>(bpp);
} }
protected:
void notify_update()
{
if (m_update_callback)
{
m_update_callback();
}
}
private:
std::function<void()> m_update_callback;
}; };