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_TOOLCHAIN_FILE=buildfiles/cmake/TCDarwinARM64.cmake \
-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
"$BREW_PATH/bin/ninja"; build_status=$?;

View file

@ -108,6 +108,8 @@ export MACOSX_DEPLOYMENT_TARGET=14.0
-DCMAKE_OSX_ARCHITECTURES=x86_64 \
-DCMAKE_IGNORE_PATH="$BREW_PATH/lib" \
-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
"$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
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
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"
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"
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=" \
$QT_BASE_URL \

View file

@ -16,4 +16,4 @@ Submitting your test results for Commercial Games must be done on our forums. Pl
# 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:
value: |
# 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
id: quick-summary
attributes:
@ -50,7 +50,7 @@ body:
* 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).
* 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 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

View file

@ -7,7 +7,7 @@ body:
attributes:
value: |
# 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
id: quick-summary
attributes:
@ -36,7 +36,7 @@ body:
* 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).
* 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 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

View file

@ -6,7 +6,7 @@ body:
- type: markdown
attributes:
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
id: quick-summary
attributes:
@ -31,6 +31,6 @@ body:
* 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).
* 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 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.

View file

@ -4,7 +4,7 @@ contact_links:
url: https://rpcs3.net/quickstart
about: Everything you need to know to install and configure emulator, and add games
- 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
- name: Report game compatibility
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:
include:
- 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"
compiler: clang
UPLOAD_COMMIT_HASH: d812f1254a1157c80fd402f94446310560f54e5f
UPLOAD_REPO_FULL_NAME: "rpcs3/rpcs3-binaries-linux"
- 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"
compiler: gcc
- 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"
compiler: clang
UPLOAD_COMMIT_HASH: a1d35836e8d45bfc6f63c26f0a3e5d46ef622fe1
@ -111,7 +111,7 @@ jobs:
LLVM_VER: '19.1.7'
VULKAN_VER: '1.3.268.0'
VULKAN_SDK_SHA: '8459ef49bd06b697115ddd3d97c9aec729e849cd775f5be70897718a9b3b9db5'
CCACHE_SHA: '6252f081876a9a9f700fae13a5aec5d0d486b28261d7f1f72ac11c7ad9df4da9'
CCACHE_SHA: '1f39f3ad5aae3fe915e99ad1302633bc8f6718e58fa7c0de2b0ba7e080f0f08c'
CCACHE_BIN_DIR: 'C:\ccache_bin'
CCACHE_DIR: 'C:\ccache'
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)
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).")
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)
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)
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)

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)
[![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)
[![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.
@ -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.
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

View file

@ -40,13 +40,13 @@ jobs:
# displayName: ccache
# - bash: |
# docker pull --quiet rpcs3/rpcs3-ci-jammy:1.3
# docker pull --quiet rpcs3/rpcs3-ci-jammy:1.4
# docker run \
# -v $(pwd):/rpcs3 \
# --env-file .ci/docker.env \
# -v $CCACHE_DIR:/root/.ccache \
# -v $BUILD_ARTIFACTSTAGINGDIRECTORY:/root/artifacts \
# rpcs3/rpcs3-ci-jammy:1.3 \
# rpcs3/rpcs3-ci-jammy:1.4 \
# /rpcs3/.ci/build-linux.sh
# 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_user_list_dialog.cpp
RSX/Overlays/overlay_utils.cpp
RSX/Overlays/overlay_video.cpp
RSX/Overlays/Shaders/shader_loading_dialog.cpp
RSX/Overlays/Shaders/shader_loading_dialog_native.cpp
RSX/Program/CgBinaryFragmentProgram.cpp

View file

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

View file

@ -244,7 +244,7 @@ static std::vector<SaveDataEntry> get_save_entries(const std::string& base_dir,
continue;
}
SaveDataEntry save_entry;
SaveDataEntry save_entry {};
save_entry.dirName = psf::get_string(psf, "SAVEDATA_DIRECTORY");
save_entry.listParam = psf::get_string(psf, "SAVEDATA_LIST_PARAM");
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.
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
@ -326,7 +326,7 @@ static error_code select_and_delete(ppu_thread& ppu)
focused = save_entries.empty() ? -1 : selected;
// 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;
// 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)
SaveDataEntry save_entry;
SaveDataEntry save_entry {};
if (setList)
{
@ -820,7 +820,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
break;
}
SaveDataEntry save_entry2;
SaveDataEntry save_entry2 {};
save_entry2.dirName = psf::get_string(psf, "SAVEDATA_DIRECTORY");
save_entry2.listParam = psf::get_string(psf, "SAVEDATA_LIST_PARAM");
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.
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
{
@ -1214,8 +1214,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
else
{
// Get information from the selected entry
SaveDataEntry entry = save_entries[selected];
message = get_confirmation_message(operation, entry);
message = get_confirmation_message(operation, ::at32(save_entries, selected));
}
// 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
{
// Get information from the selected entry
SaveDataEntry entry = save_entries[selected];
message = get_confirmation_message(operation, entry);
message = get_confirmation_message(operation, ::at32(save_entries, selected));
}
// Yield before a blocking dialog is being spawned
lv2_obj::sleep(ppu);
// Get user confirmation by opening a blocking dialog
// TODO: show fixedSet->newIcon
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);

View file

@ -361,5 +361,5 @@ class SaveDialogBase
public:
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;
}
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);
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);
// Translate
if (const auto func = translator.Translate(mod_func))
if ([[maybe_unused]] const auto func = translator.Translate(mod_func))
{
#ifdef ARCH_X64 // TODO
// 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
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
// Run optimization passes

View file

@ -1290,7 +1290,7 @@ void PPUTranslator::VMADDFP(ppu_opcode_t op)
void PPUTranslator::VMAXFP(ppu_opcode_t op)
{
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)
@ -1352,7 +1352,7 @@ void PPUTranslator::VMHRADDSHS(ppu_opcode_t op)
void PPUTranslator::VMINFP(ppu_opcode_t op)
{
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)

View file

@ -1237,7 +1237,7 @@ void spu_thread::dump_regs(std::string& ret, std::any& /*custom_data*/) const
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;
}
@ -1447,7 +1447,7 @@ std::vector<std::pair<u32, u32>> spu_thread::dump_callstack_list() const
if (v != v128::from32r(addr))
{
// 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;
}

View file

@ -752,6 +752,22 @@ void PadHandlerBase::process()
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);
switch (status)

View file

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

View file

@ -483,8 +483,6 @@ namespace vm
}
}
bool to_prepare_memory = true;
for (u64 i = 0;; i++)
{
auto& bits = get_range_lock_bits(true);
@ -512,22 +510,11 @@ namespace vm
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);
}
else
{
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;
}
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();
}
@ -607,13 +587,6 @@ namespace vm
{
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();
}
}

View file

@ -218,12 +218,12 @@ namespace gl
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);
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 result = view.get();
@ -234,7 +234,7 @@ namespace gl
}
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_view_cache[key] = std::move(view);
}
@ -249,7 +249,7 @@ namespace gl
rsx::overlays::resource_config configuration;
configuration.load_files();
for (const auto &res : configuration.texture_raw_data)
for (const auto& res : configuration.texture_raw_data)
{
load_simple_image(res.get(), false, -1);
}
@ -318,13 +318,22 @@ namespace gl
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);
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);
@ -420,7 +429,7 @@ namespace gl
}
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;
}
case rsx::overlays::image_resource_id::font_file:

View file

@ -75,7 +75,7 @@ namespace gl
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 destroy();
@ -84,7 +84,7 @@ namespace gl
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);

View file

@ -40,7 +40,7 @@ namespace rsx
{
update_value();
if (!is_compiled)
if (!is_compiled())
{
const f32 col = m_last_value ? 1.0f : 0.3f;
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)
{
m_last_value = new_value;
is_compiled = false;
m_is_compiled = false;
}
}
}
@ -101,7 +101,7 @@ namespace rsx
{
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));
m_dropdown.set_text(value_text);
@ -145,7 +145,7 @@ namespace rsx
{
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);
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()
{
if (!is_compiled)
if (!is_compiled())
{
compiled_resource& compiled = overlay_element::get_compiled();
compiled.add(m_label.get_compiled());

View file

@ -258,9 +258,9 @@ namespace rsx
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))
{
@ -281,7 +281,7 @@ namespace rsx
}
}
is_compiled = true;
m_is_compiled = true;
}
return compiled_resources;

View file

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

View file

@ -302,7 +302,7 @@ namespace rsx
void overlay_element::refresh()
{
// Just invalidate for draw when get_compiled() is called
is_compiled = false;
m_is_compiled = false;
}
void overlay_element::translate(s16 _x, s16 _y)
@ -310,7 +310,7 @@ namespace rsx
x += _x;
y += _y;
is_compiled = false;
m_is_compiled = false;
}
void overlay_element::scale(f32 _x, f32 _y, bool origin_scaling)
@ -324,7 +324,7 @@ namespace rsx
w = static_cast<u16>(_x * w);
h = static_cast<u16>(_y * h);
is_compiled = false;
m_is_compiled = false;
}
void overlay_element::set_pos(s16 _x, s16 _y)
@ -332,7 +332,7 @@ namespace rsx
x = _x;
y = _y;
is_compiled = false;
m_is_compiled = false;
}
void overlay_element::set_size(u16 _w, u16 _h)
@ -340,7 +340,7 @@ namespace rsx
w = _w;
h = _h;
is_compiled = false;
m_is_compiled = false;
}
void overlay_element::set_padding(u16 left, u16 right, u16 top, u16 bottom)
@ -350,13 +350,13 @@ namespace rsx
padding_top = top;
padding_bottom = bottom;
is_compiled = false;
m_is_compiled = false;
}
void overlay_element::set_padding(u16 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.
@ -365,25 +365,36 @@ namespace rsx
margin_left = left;
margin_top = top;
is_compiled = false;
m_is_compiled = false;
}
void overlay_element::set_margin(u16 margin)
{
margin_left = margin_top = margin;
is_compiled = false;
m_is_compiled = false;
}
void overlay_element::set_text(const std::string& text)
{
this->text = utf8_to_u32string(text);
is_compiled = false;
std::u32string new_text = utf8_to_u32string(text);
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)
{
const bool is_dirty = 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)
@ -394,19 +405,19 @@ namespace rsx
void overlay_element::set_font(const char* font_name, u16 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)
{
alignment = align;
is_compiled = false;
m_is_compiled = false;
}
void overlay_element::set_wrap_text(bool state)
{
wrap_text = state;
is_compiled = false;
m_is_compiled = false;
}
font* overlay_element::get_font() const
@ -563,7 +574,7 @@ namespace rsx
compiled_resource& overlay_element::get_compiled()
{
if (!is_compiled)
if (!is_compiled())
{
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);
}
is_compiled = true;
m_is_compiled = true;
}
return compiled_resources;
@ -664,7 +675,7 @@ namespace rsx
{
overlay_element::translate(_x, _y);
for (auto &itm : m_items)
for (auto& itm : m_items)
itm->translate(_x, _y);
}
@ -675,13 +686,23 @@ namespace rsx
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()
{
if (!is_compiled)
if (!is_compiled())
{
compiled_resource result = overlay_element::get_compiled();
for (auto &itm : m_items)
for (auto& itm : m_items)
result.add(itm->get_compiled());
compiled_resources = result;
@ -716,7 +737,7 @@ namespace rsx
return m_items.back().get();
}
auto result = item.get();
overlay_element* result = item.get();
m_items.insert(m_items.begin() + offset, std::move(item));
return result;
}
@ -726,12 +747,12 @@ namespace rsx
if (scroll_offset_value == 0 && auto_resize)
return layout_container::get_compiled();
if (!is_compiled)
if (!is_compiled())
{
compiled_resource result = overlay_element::get_compiled();
const f32 global_y_offset = static_cast<f32>(-scroll_offset_value);
for (auto &item : m_items)
for (auto& item : m_items)
{
if (!item)
{
@ -808,7 +829,7 @@ namespace rsx
if (scroll_offset_value == 0 && auto_resize)
return layout_container::get_compiled();
if (!is_compiled)
if (!is_compiled())
{
compiled_resource result = overlay_element::get_compiled();
const f32 global_x_offset = static_cast<f32>(-scroll_offset_value);
@ -862,7 +883,7 @@ namespace rsx
compiled_resource& image_view::get_compiled()
{
if (!is_compiled)
if (!is_compiled())
{
auto& result = overlay_element::get_compiled();
auto& cmd_img = result.draw_commands.front();
@ -880,7 +901,7 @@ namespace rsx
verts[2] += vertex(padding_left, -padding_top, 0, 0);
verts[3] += vertex(-padding_right, -padding_top, 0, 0);
is_compiled = true;
m_is_compiled = true;
}
return compiled_resources;
@ -892,7 +913,7 @@ namespace rsx
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;
external_ref = raw_image;
@ -935,7 +956,7 @@ namespace rsx
compiled_resource& image_button::get_compiled()
{
if (!is_compiled)
if (!is_compiled())
{
auto& compiled = image_view::get_compiled();
for (auto& cmd : compiled.draw_commands)
@ -987,7 +1008,7 @@ namespace rsx
compiled_resource& rounded_rect::get_compiled()
{
if (!is_compiled)
if (!is_compiled())
{
compiled_resources.clear();
@ -1068,7 +1089,7 @@ namespace rsx
compiled_resources.add(std::move(compiled_resources_temp), margin_left, margin_top);
}
is_compiled = true;
m_is_compiled = true;
}
return compiled_resources;

View file

@ -30,23 +30,32 @@ namespace rsx
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:
u8* data = nullptr;
std::vector<u8> data_grey;
public:
int w = 0, h = 0, channels = 0;
int bpp = 0;
using image_info_base::image_info_base;
image_info(image_info&) = delete;
image_info(const std::string& filename, 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);
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
@ -165,7 +174,6 @@ namespace rsx
void set_sinus_offset(f32 sinus_modifier);
compiled_resource compiled_resources;
bool is_compiled = false;
bool visible = true;
@ -185,6 +193,7 @@ namespace rsx
virtual ~overlay_element() = default;
virtual void refresh();
virtual bool is_compiled() { return m_is_compiled; }
virtual void translate(s16 _x, s16 _y);
virtual void scale(f32 _x, f32 _y, bool origin_scaling);
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 compiled_resource& get_compiled();
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
@ -221,6 +234,8 @@ namespace rsx
void translate(s16 _x, s16 _y) override;
void set_pos(s16 _x, s16 _y) override;
bool is_compiled() override;
compiled_resource& get_compiled() override;
virtual u16 get_scroll_offset_px() = 0;
@ -248,6 +263,7 @@ namespace rsx
compiled_resource& get_compiled() override
{
// No draw
m_is_compiled = true;
return compiled_resources;
}
};
@ -263,7 +279,7 @@ namespace rsx
struct image_view : public overlay_element
{
private:
protected:
u8 image_resource_ref = image_resource_id::none;
void* external_ref = nullptr;
@ -276,7 +292,7 @@ namespace rsx
compiled_resource& get_compiled() override;
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 set_blur_strength(u8 strength);
};

View file

@ -196,7 +196,7 @@ namespace rsx
compiled_resource& edit_text::get_compiled()
{
if (!is_compiled)
if (!is_compiled())
{
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);
@ -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)};
}
is_compiled = true;
m_is_compiled = true;
}
return compiled_resources;

View file

@ -91,6 +91,15 @@ namespace rsx
void list_view::update_selection()
{
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)
{
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_only = cancel_only;
is_compiled = false;
m_is_compiled = false;
}
bool list_view::get_cancel_only() const
@ -219,7 +228,7 @@ namespace rsx
compiled_resource& list_view::get_compiled()
{
if (!is_compiled)
if (!is_compiled())
{
auto& compiled = vertical_layout::get_compiled();
compiled.add(m_highlight_box->get_compiled());

View file

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

View file

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

View file

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

View file

@ -1,5 +1,6 @@
#include "stdafx.h"
#include "overlay_save_dialog.h"
#include "overlay_video.h"
#include "Utilities/date_time.h"
#include "Emu/System.h"
@ -7,26 +8,18 @@ namespace rsx
{
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_padding(36, 36, 11, 11); // Square image, 88x88
if (resource_id != image_resource_id::raw_image)
{
static_cast<image_view*>(image.get())->set_image_resource(resource_id);
}
else if (!icon_buf.empty())
if (resource_id == image_resource_id::raw_image && !icon_buf.empty())
{
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>();
@ -74,10 +67,18 @@ namespace rsx
// Pack
this->pack_padding = 15;
add_element(image);
m_image = add_element(image);
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()
{
m_dim_background = std::make_unique<overlay_element>();
@ -197,7 +198,7 @@ namespace rsx
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);
@ -218,7 +219,7 @@ namespace rsx
{
const std::string date_and_size = fmt::format("%s %s", entry.date(), entry.data_size());
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));
}
@ -270,7 +271,7 @@ namespace rsx
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);
}

View file

@ -13,11 +13,12 @@ namespace rsx
private:
struct save_dialog_entry : horizontal_layout
{
private:
std::unique_ptr<image_info> icon_data;
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;
@ -38,7 +39,7 @@ namespace rsx
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
return _fetch_constant(int(base_offset));
}
#elif defined(VULKAN)
#define _fetch_constant(x) vc[x + xform_constants_offset]
#else
#define _fetch_constant(x) vc[x]
#endif

View file

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

View file

@ -50,7 +50,7 @@ namespace vk
idx++;
bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
bindings[idx].descriptorCount = 1;
bindings[idx].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
bindings[idx].binding = binding_table.vertex_constant_buffers_bind_slot;
@ -101,7 +101,8 @@ namespace vk
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();
auto bindings = get_common_binding_table();
@ -135,13 +136,13 @@ namespace vk
std::array<VkPushConstantRange, 1> push_constants;
push_constants[0].offset = 0;
push_constants[0].size = 16;
push_constants[0].size = 20;
push_constants[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
if (vk::emulate_conditional_rendering())
{
// Conditional render toggle
push_constants[0].size = 20;
push_constants[0].size = 24;
}
const auto set_layout = vk::descriptors::create_layout(bindings);
@ -155,6 +156,25 @@ namespace vk
VkPipelineLayout 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.
// 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.
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);
//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
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
const u32 max_draw_calls = m_device->get_descriptor_max_draw_calls();
const auto& binding_table = m_device->get_pipeline_binding_table();
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 }
};
const auto descriptor_type_sizes = vk::get_descriptor_pool_sizes(binding_layout);
m_descriptor_pool.create(*m_device, descriptor_type_sizes, max_draw_calls);
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_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_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_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");
@ -2107,7 +2097,7 @@ void VKGSRender::load_program_env()
usz mem_offset = 0;
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));
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())
{
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();
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_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);
@ -2320,21 +2311,31 @@ void VKGSRender::update_vertex_env(u32 id, const vk::vertex_upload_info& vertex_
base_offset = 0;
}
u8 data_size = 16;
u32 draw_info[5];
const u32 vertex_layout_offset = (id * 16) + (base_offset / 8);
const volatile u32 constant_id_offset = static_cast<volatile u32>(m_xform_constants_dynamic_offset) / 16u;
draw_info[0] = vertex_info.vertex_index_base;
draw_info[1] = vertex_info.vertex_index_offset;
draw_info[2] = id;
draw_info[3] = (id * 16) + (base_offset / 8);
u32 push_constants[6];
u32 data_length = 20;
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())
{
draw_info[4] = cond_render_ctrl.hw_cond_active ? 1 : 0;
data_size = 20;
push_constants[5] = cond_render_ctrl.hw_cond_active ? 1 : 0;
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;
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();
}
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)
{
@ -2366,83 +2367,16 @@ void VKGSRender::patch_transform_constants(rsx::context* ctx, u32 index, u32 cou
return;
}
// Hot-patching transform constants mid-draw (instanced draw)
std::pair<VkDeviceSize, VkDeviceSize> data_range;
void* data_source = nullptr;
if (m_vertex_prog->has_indexed_constants)
// Buffer updates mid-pass violate the spec and destroy performance on NVIDIA
auto allocate_mem = [&](usz size) -> std::pair<void*, usz>
{
// 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>
{
m_scratch_mem.resize(size);
return { m_scratch_mem.data(), size };
};
rsx::io_buffer iobuf(allocate_mem);
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 usz alignment = m_device->gpu().get_limits().minStorageBufferOffsetAlignment;
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);
};
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);
rsx::io_buffer iobuf(allocate_mem);
upload_transform_constants(iobuf);
}
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_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;
//Temp frame context to use if the real frame queue is overburdened. Only used for storage
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::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)
void ui_overlay_renderer::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)
{
const VkFormat format = (font) ? VK_FORMAT_R8_UNORM : VK_FORMAT_B8G8R8A8_UNORM;
const u32 pitch = (font) ? w : w * 4;
const u32 data_size = pitch * h * layers;
const auto offset = upload_heap.alloc<512>(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)
std::memcpy(addr, pixel_src, data_size);
else if (data_size)
@ -409,17 +401,32 @@ namespace vk
upload_heap.unmap();
VkBufferImageCopy region;
region.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, layers };
region.bufferOffset = offset;
region.bufferRowLength = w;
region.bufferImageHeight = h;
region.imageOffset = {};
region.imageExtent = { static_cast<u32>(w), static_cast<u32>(h), 1u };
change_image_layout(cmd, tex.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, range);
const VkImageSubresourceRange range = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, layers };
VkBufferImageCopy region
{
.bufferOffset = offset,
.bufferRowLength = w,
.bufferImageHeight = h,
.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, layers },
.imageOffset = {},
.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);
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());
@ -521,12 +528,23 @@ namespace vk
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);
auto found = temp_view_cache.find(key);
if (found != temp_view_cache.end())
return found->second.get();
const bool dirty = std::exchange(desc->dirty, false);
const u64 key = reinterpret_cast<u64>(desc);
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,
false, true, desc->get_data(), owner_uid);
@ -693,7 +711,7 @@ namespace vk
: rsx::overlays::texture_sampling_mode::font3D;
break;
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;
default:
src = view_cache[command.config.texture_ref].get();

View file

@ -154,6 +154,9 @@ namespace vk
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::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);
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;

View file

@ -330,21 +330,7 @@ namespace vk
idx++;
bindings.resize(idx);
// 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);
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 }
};
m_descriptor_pool_sizes = get_descriptor_pool_sizes(bindings);
std::array<VkPushConstantRange, 1> push_constants;
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)
{
OS << "#version 450\n\n";
OS << "#extension GL_ARB_separate_shader_objects : enable\n\n";
OS <<
"#version 450\n\n"
"#extension GL_ARB_separate_shader_objects : enable\n\n";
OS <<
"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_index_offset;\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)
{
@ -115,15 +117,15 @@ void VKVertexDecompilerThread::insertConstants(std::stringstream & OS, const std
{
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 << " vec4 " << PI.name << ";\n";
OS << " vec4 vc[];\n";
OS << "};\n\n";
in.location = m_binding_table.vertex_constant_buffers_bind_slot;
in.domain = glsl::glsl_vertex_program;
in.name = "VertexConstantsBuffer";
in.type = vk::glsl::input_type_uniform_buffer;
in.type = vk::glsl::input_type_storage_buffer;
inputs.push_back(in);
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)
{
if ((m_push_type_mask & ~m_update_after_bind_mask) || (m_pending_writes.size() >= max_cache_size))
@ -437,7 +448,7 @@ namespace vk
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()

View file

@ -27,6 +27,12 @@ namespace vk
}
};
struct descriptor_set_dynamic_offset_t
{
int location;
u32 value;
};
class descriptor_pool
{
public:
@ -95,6 +101,7 @@ namespace vk
void push(const VkDescriptorImageInfo& image_info, 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(const descriptor_set_dynamic_offset_t& offset);
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<VkDescriptorBufferInfo> m_buffer_info_pool;
rsx::simple_array<VkDescriptorImageInfo> m_image_info_pool;
rsx::simple_array<u32> m_dynamic_offsets;
#ifdef __clang__
// 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<void(bool)> enable_display_sleep;
std::function<void()> check_microphone_permissions;
std::function<std::unique_ptr<class video_source>()> make_video_source;
};
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())
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[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_user_list_dialog.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_native.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_media_list_dialog.h" />
<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\Program\FragmentProgramRegister.h" />
<ClInclude Include="Emu\RSX\Program\GLSLTypes.h" />

View file

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

View file

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

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->forum, &QPushButton::clicked, [] { QDesktopServices::openUrl(QUrl("https://forums.rpcs3.net")); });
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->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]()
{
pdlg->setLabelText(progressLabel.arg(*index).arg(serials_size));
pdlg->setLabelText(progressLabel.arg(+*index).arg(serials_size));
pdlg->setCancelButtonText(tr("OK"));
QApplication::beep();
@ -2396,7 +2396,7 @@ void game_list_frame::BatchActionBySerials(progress_dialog* pdlg, const std::set
return;
}
pdlg->setLabelText(progressLabel.arg(*index).arg(serials_size));
pdlg->setLabelText(progressLabel.arg(+*index).arg(serials_size));
pdlg->setCancelButtonText(tr("OK"));
connect(pdlg, &progress_dialog::canceled, this, [pdlg](){ pdlg->deleteLater(); });
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_renderer(g_cfg.video.renderer)
{
load_gui_settings();
m_window_title = Emu.GetFormattedTitle(0);
if (!g_cfg_recording.load())
@ -121,8 +119,7 @@ gs_frame::gs_frame(QScreen* screen, const QRect& geometry, const QIcon& appIcon,
create();
}
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);
load_gui_settings();
// Change cursor when in fullscreen.
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_hide_mouse_after_idletime = m_gui_settings->GetValue(gui::gs_hideMouseIdle).toBool();
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()
@ -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
@ -1101,7 +1109,7 @@ void gs_frame::handle_cursor(QWindow::Visibility visibility, bool visibility_cha
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)
{
handle_cursor(visibility(), false, false, false);

View file

@ -27,6 +27,7 @@
#include "Emu/vfs_config.h"
#include "util/init_mutex.hpp"
#include "util/console.h"
#include "qt_video_source.h"
#include "trophy_notification_helper.h"
#include "save_data_dialog.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));
}

View file

@ -226,49 +226,6 @@ bool main_window::Init([[maybe_unused]] bool with_cli_boot)
ui->sysPauseAct->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
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);
};
#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()
@ -1971,12 +1915,6 @@ void main_window::OnEmuRun(bool /*start_playtime*/)
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->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 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->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 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->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->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);
@ -2061,10 +1985,6 @@ void main_window::OnEmuStop()
ui->toolbar_start->setText(tr("Restart"));
ui->toolbar_start->setToolTip(restart_tooltip);
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);
@ -2106,10 +2026,7 @@ void main_window::OnEmuReady() const
const QString play_tooltip = tr("Play %0").arg(title);
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->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
{
// Thumbnail Buttons
#ifdef HAS_QT_WIN_STUFF
m_thumb_playPause->setEnabled(enabled);
m_thumb_stop->setEnabled(enabled);
m_thumb_restart->setEnabled(enabled);
#endif
// Toolbar
ui->toolbar_start->setEnabled(enabled);
ui->toolbar_stop->setEnabled(enabled);
@ -3588,16 +3498,10 @@ void main_window::CreateDockWindows()
ui->toolbar_start->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())
{
ui->toolbar_start->setToolTip(tooltip);
#ifdef HAS_QT_WIN_STUFF
m_thumb_playPause->setToolTip(tooltip);
#endif
}
}

View file

@ -1,10 +1,5 @@
#pragma once
#ifdef HAS_QT_WIN_STUFF
#include <QWinThumbnailToolBar>
#include <QWinThumbnailToolButton>
#endif
#include <QActionGroup>
#include <QMainWindow>
#include <QIcon>
@ -61,17 +56,6 @@ class main_window : public QMainWindow
QIcon m_icon_fullscreen_on;
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
{
drop_error,

View file

@ -131,9 +131,6 @@ void msg_dialog_frame::Create(const std::string& msg, const std::string& title)
// Fix size
m_dialog->layout()->setSizeConstraint(QLayout::SetFixedSize);
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)

View file

@ -51,34 +51,3 @@ void progress_dialog::SignalFailure() const
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 SignalFailure() const;
void show_progress_indicator();
void setVisible(bool visible) override;
private:
std::unique_ptr<progress_indicator> m_progress_indicator;
};

View file

@ -1,106 +1,57 @@
#include "stdafx.h"
#include "progress_indicator.h"
#ifdef HAS_QT_WIN_STUFF
#include <QCoreApplication>
#include <QWinTaskbarProgress>
#elif HAVE_QTDBUS
#if HAVE_QTDBUS
#include <QtDBus/QDBusMessage>
#include <QtDBus/QDBusConnection>
#endif
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_maximum = maximum;
#if HAVE_QTDBUS
update_progress(0, true, false);
#endif
#endif
}
progress_indicator::~progress_indicator()
{
#ifdef HAS_QT_WIN_STUFF
// 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
#if HAVE_QTDBUS
update_progress(0, false, false);
#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
{
#ifdef HAS_QT_WIN_STUFF
return m_tb_button->progress()->value();
#else
return m_value;
#endif
}
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);
#if HAVE_QTDBUS
update_progress(m_value, true, false);
#endif
#endif
}
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_maximum = maximum;
#endif
}
void progress_indicator::reset()
{
#ifdef HAS_QT_WIN_STUFF
m_tb_button->progress()->reset();
#else
m_value = m_minimum;
#if HAVE_QTDBUS
update_progress(m_value, false, false);
#endif
#endif
}
void progress_indicator::signal_failure()
{
#ifdef HAS_QT_WIN_STUFF
m_tb_button->progress()->stop();
#elif HAVE_QTDBUS
#if HAVE_QTDBUS
update_progress(0, false, true);
#endif
}

View file

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

View file

@ -14,9 +14,9 @@ qt_video_source::~qt_video_source()
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)
@ -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->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)
{
@ -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);
}
lock.unlock();
notify_update();
};
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);
});
}
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)
{
ensure(m_qt_video_source);

View file

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

View file

@ -12,7 +12,7 @@
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);
@ -29,7 +29,7 @@ s32 save_data_dialog::ShowSaveDataList(std::vector<SaveDataEntry>& save_entries,
{
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)
{
cellSaveData.notice("ShowSaveDataList: Native UI dialog returned with selection %d", result);

View file

@ -6,5 +6,5 @@
class save_data_dialog : public SaveDialogBase
{
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;
}
SaveDataEntry save_entry2;
SaveDataEntry save_entry2 {};
save_entry2.dirName = psf::get_string(psf, "SAVEDATA_DIRECTORY");
save_entry2.listParam = psf::get_string(psf, "SAVEDATA_LIST_PARAM");
save_entry2.title = psf::get_string(psf, "TITLE");
save_entry2.subtitle = psf::get_string(psf, "SUB_TITLE");
save_entry2.details = psf::get_string(psf, "DETAIL");
save_entry2.size = 0;
for (const auto& entry2 : fs::dir(base_dir + entry.name))
{
@ -586,7 +585,7 @@ void save_manager_dialog::OnEntriesRemove()
}
// Pop-up a small context-menu, being a replacement for save_data_manage_dialog
void save_manager_dialog::ShowContextMenu(const QPoint &pos)
void save_manager_dialog::ShowContextMenu(const QPoint& pos)
{
const int idx = m_list->currentRow();
if (idx == -1)

View file

@ -42,7 +42,7 @@ private:
void Init();
void UpdateList();
void UpdateIcons();
void ShowContextMenu(const QPoint &pos);
void ShowContextMenu(const QPoint& pos);
void WaitForRepaintThreads(bool abort);
void closeEvent(QCloseEvent* event) override;

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_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_mute_unmute, shortcut_info{ "gw_mute_unmute", tr("Mute/Unmute Audio"), "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_down, shortcut_info{ "gw_volume_down", tr("Volume Down"), "Shift+-", shortcut_handler_id::game_window, true } },
{ 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"), "Ctrl+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 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;
}
#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);
LookToRead2_CreateVTable(&lookStream, False);
@ -529,22 +547,14 @@ bool update_manager::handle_rpcs3(const QByteArray& data, bool auto_accept)
CrcGenerateTable();
SzArEx_Init(&db);
auto error_free7z = [&]()
const auto error_free7z = [&]()
{
SzArEx_Free(&db, &allocImp);
ISzAlloc_Free(&allocImp, lookStream.buf);
const WRes res2 = File_Close(&archiveStream.file);
if (res2) update_log.warning("7z failed to close file (error=%d)", static_cast<u64>(res2));
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 (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));
};
if (res != SZ_OK)
@ -588,7 +598,7 @@ bool update_manager::handle_rpcs3(const QByteArray& data, bool auto_accept)
const DWORD permissions = (attribs >> 16) & (S_IRWXU | S_IRWXG | S_IRWXO);
const bool is_symlink = (attribs & FILE_ATTRIBUTE_UNIX_EXTENSION) != 0 && S_ISLNK(attribs >> 16);
#endif
const usz len = SzArEx_GetFileNameUtf16(&db, i, nullptr);
const usz len = SzArEx_GetFileNameUtf16(&db, i, nullptr);
if (len >= PATH_MAX)
{
@ -598,7 +608,7 @@ bool update_manager::handle_rpcs3(const QByteArray& data, bool auto_accept)
}
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
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("FAQ"), "https://rpcs3.net/faq"))
.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__
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);
if (!std::is_constant_evaluated())
std::memcpy(&array[pos], &value, sizeof(value));
std::memcpy(static_cast<void*>(&array[pos]), &value, sizeof(value));
else
ensure(!"Unimplemented");
}

View file

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