diff --git a/.github/workflows/rpcs3.yml b/.github/workflows/rpcs3.yml index d9cda2c6a3..cc50e17208 100644 --- a/.github/workflows/rpcs3.yml +++ b/.github/workflows/rpcs3.yml @@ -24,7 +24,7 @@ env: jobs: Linux_Build: # Only run push event on master branch of main repo, but run all PRs - #if: github.event_name != 'push' || (github.repository == 'RPCS3/rpcs3' && github.ref_name == 'master') + if: github.event_name != 'push' || (github.repository == 'RPCS3/rpcs3' && github.ref_name == 'master') strategy: fail-fast: false matrix: @@ -117,7 +117,7 @@ jobs: Mac_Build: # Only run push event on master branch of main repo, but run all PRs - #if: github.event_name != 'push' || (github.repository == 'RPCS3/rpcs3' && github.ref_name == 'master') + if: github.event_name != 'push' || (github.repository == 'RPCS3/rpcs3' && github.ref_name == 'master') strategy: fail-fast: false matrix: @@ -191,14 +191,14 @@ jobs: run: .ci/github-upload.sh - name: Save Build Ccache - #if: github.ref == 'refs/heads/master' + if: github.ref == 'refs/heads/master' uses: actions/cache/save@main with: path: ${{ env.CCACHE_DIR }} key: ${{ steps.restore-build-ccache.outputs.cache-primary-key }} - name: Save Qt Cache - #if: github.ref == 'refs/heads/master' + if: github.ref == 'refs/heads/master' uses: actions/cache/save@main with: path: /tmp/Qt @@ -206,7 +206,7 @@ jobs: Windows_Build: # Only run push event on master branch of main repo, but run all PRs - #if: github.event_name != 'push' || (github.repository == 'RPCS3/rpcs3' && github.ref_name == 'master') + if: github.event_name != 'push' || (github.repository == 'RPCS3/rpcs3' && github.ref_name == 'master') name: RPCS3 Windows runs-on: windows-2025 env: @@ -312,14 +312,14 @@ jobs: run: .ci/github-upload.sh - name: Save Build Ccache - #if: github.ref == 'refs/heads/master' + if: github.ref == 'refs/heads/master' uses: actions/cache/save@main with: path: ${{ env.CCACHE_DIR }} key: ${{ steps.restore-build-ccache.outputs.cache-primary-key }} - name: Save Dependencies Cache - #if: github.ref == 'refs/heads/master' + if: github.ref == 'refs/heads/master' uses: actions/cache/save@main with: path: ${{ env.DEPS_CACHE_DIR }} @@ -327,7 +327,7 @@ jobs: Windows_Build_Clang: # Only run push event on master branch of main repo, but run all PRs - #if: github.event_name != 'push' || (github.repository == 'RPCS3/rpcs3' && github.ref_name == 'master') + if: github.event_name != 'push' || (github.repository == 'RPCS3/rpcs3' && github.ref_name == 'master') runs-on: windows-2025 strategy: fail-fast: false @@ -415,9 +415,7 @@ jobs: --clean-after-build - name: Save vcpkg cache - if: ${{ matrix.compiler == 'clang-cl' }} - #if: ${{ !steps.restore-vcpkg-cache.outputs.cache-hit && matrix.compiler == 'clang-cl' }} - #if: github.ref == 'refs/heads/master' + if: ${{ github.ref == 'refs/heads/master' && matrix.compiler == 'clang-cl' }} uses: actions/cache/save@main with: path: | @@ -451,8 +449,7 @@ jobs: Add-Content -Path $env:GITHUB_PATH -Value "D:\a\rpcs3\rpcs3\llvm-${{ matrix.llvmver }}\bin" C:\PROGRA~1\LLVM\bin\clang-cl.exe --version - name: Save LLVM Cache - if: ${{ matrix.compiler == 'clang-cl' && steps.llvm-cache.outputs.cache-hit != 'true' }} - #if: github.ref == 'refs/heads/master' + if: ${{ github.ref == 'refs/heads/master' && matrix.compiler == 'clang-cl' }} uses: actions/cache/save@main with: path: ./llvm-${{ matrix.llvmver }} @@ -473,6 +470,8 @@ jobs: export CCACHE_DIR=$(cygpath -u "$CCACHE_DIR") echo "CCACHE_DIR=$CCACHE_DIR" .ci/build-windows-clang.sh + .ci/setup-windows-ci-vars.sh ${{ matrix.arch }} ${{ matrix.compiler }} + .ci/deploy-windows-${{ matrix.compiler }}.sh - name: install DIA SDK if: ${{ matrix.compiler == 'clang-cl' }} @@ -484,21 +483,18 @@ jobs: - name: Build RPCS3 if: ${{ matrix.compiler == 'clang-cl' }} shell: bash - run: .ci/build-windows-clang-cl.sh + run: | + .ci/build-windows-clang-cl.sh + .ci/setup-windows-ci-vars.sh ${{ matrix.arch }} ${{ matrix.compiler }} + .ci/deploy-windows-${{ matrix.compiler }}.sh - name: Save build Ccache - #if: github.ref == 'refs/heads/master' + if: github.ref == 'refs/heads/master' uses: actions/cache/save@main with: path: ${{ env.CCACHE_DIR }} key: ${{ steps.restore-build-ccache.outputs.cache-primary-key }} - - name: Prepare Artifacts - shell: bash - run: | - .ci/setup-windows-ci-vars.sh ${{ matrix.arch }} ${{ matrix.compiler }} - .ci/deploy-windows-${{ matrix.compiler }}.sh - - name: Upload artifacts uses: actions/upload-artifact@main with: @@ -508,8 +504,8 @@ jobs: if-no-files-found: error FreeBSD_Build: - # Only run push event on master branch of main repo, but run all PRs - #if: github.event_name != 'push' || (github.repository == 'RPCS3/rpcs3' && github.ref_name == 'master') + # Only run push event on master branch of main repo, but run all PRs + if: github.event_name != 'push' || (github.repository == 'RPCS3/rpcs3' && github.ref_name == 'master') name: RPCS3 FreeBSD runs-on: ubuntu-latest timeout-minutes: 60 @@ -540,7 +536,7 @@ jobs: run: .ci/install-freebsd.sh && .ci/build-freebsd.sh - name: Save Build Ccache - #if: github.ref == 'refs/heads/master' + if: github.ref == 'refs/heads/master' uses: actions/cache/save@main with: path: ${{ env.CCACHE_DIR }} diff --git a/3rdparty/qt6.cmake b/3rdparty/qt6.cmake index ef89bdab05..e15e0abdcb 100644 --- a/3rdparty/qt6.cmake +++ b/3rdparty/qt6.cmake @@ -6,14 +6,15 @@ find_package(Qt6 ${QT_MIN_VER} CONFIG COMPONENTS Widgets Concurrent Multimedia M if(WIN32) target_link_libraries(3rdparty_qt6 INTERFACE Qt6::Widgets Qt6::Concurrent Qt6::Multimedia Qt6::MultimediaWidgets Qt6::Svg Qt6::SvgWidgets) else() - find_package(Qt6 ${QT_MIN_VER} COMPONENTS DBus Gui) + set(QT_NO_PRIVATE_MODULE_WARNING ON) + find_package(Qt6 ${QT_MIN_VER} COMPONENTS DBus Gui GuiPrivate) if(Qt6DBus_FOUND) target_link_libraries(3rdparty_qt6 INTERFACE Qt6::Widgets Qt6::DBus Qt6::Concurrent Qt6::Multimedia Qt6::MultimediaWidgets Qt6::Svg Qt6::SvgWidgets) target_compile_definitions(3rdparty_qt6 INTERFACE -DHAVE_QTDBUS) else() target_link_libraries(3rdparty_qt6 INTERFACE Qt6::Widgets Qt6::Concurrent Qt6::Multimedia Qt6::MultimediaWidgets Qt6::Svg Qt6::SvgWidgets) endif() - target_include_directories(3rdparty_qt6 INTERFACE ${Qt6Gui_PRIVATE_INCLUDE_DIRS}) + target_link_libraries(3rdparty_qt6 INTERFACE Qt6::GuiPrivate) endif() if(Qt6Widgets_FOUND) diff --git a/rpcs3/CMakeLists.txt b/rpcs3/CMakeLists.txt index d3d23a3184..72d2f22dfd 100644 --- a/rpcs3/CMakeLists.txt +++ b/rpcs3/CMakeLists.txt @@ -162,7 +162,7 @@ if (NOT ANDROID) add_custom_command(TARGET rpcs3 POST_BUILD COMMAND ${WINDEPLOYQT_EXECUTABLE} --no-compiler-runtime --no-opengl-sw --no-patchqt --no-translations --no-system-d3d-compiler --no-system-dxc-compiler --no-quick-import - --plugindir $/qt6/plugins + --plugindir "$,$/qt6/plugins,$/share/qt6/plugins>" --verbose 0 $ ) diff --git a/rpcs3/Emu/CMakeLists.txt b/rpcs3/Emu/CMakeLists.txt index 3b3af36aa3..6655841278 100644 --- a/rpcs3/Emu/CMakeLists.txt +++ b/rpcs3/Emu/CMakeLists.txt @@ -591,6 +591,7 @@ if(TARGET 3rdparty_vulkan) RSX/VK/vkutils/device.cpp RSX/VK/vkutils/sampler.cpp RSX/VK/vkutils/shared.cpp + RSX/VK/vkutils/unique_resource.cpp RSX/VK/VKAsyncScheduler.cpp RSX/VK/VKCommandStream.cpp RSX/VK/VKCommonDecompiler.cpp diff --git a/rpcs3/Emu/Cell/Modules/sceNp.cpp b/rpcs3/Emu/Cell/Modules/sceNp.cpp index 916aa44a40..beb6c2da91 100644 --- a/rpcs3/Emu/Cell/Modules/sceNp.cpp +++ b/rpcs3/Emu/Cell/Modules/sceNp.cpp @@ -3198,7 +3198,7 @@ error_code sceNpLookupTerm() error_code sceNpLookupCreateTitleCtx(vm::cptr communicationId, vm::cptr selfNpId) { - sceNp.warning("sceNpLookupCreateTitleCtx(communicationId=*0x%x(%s), selfNpId=0x%x)", communicationId, communicationId ? communicationId->data : "", selfNpId); + sceNp.warning("sceNpLookupCreateTitleCtx(communicationId=*0x%x(%s), selfNpId=0x%x)", communicationId, communicationId ? std::string_view(communicationId->data, 9) : "", selfNpId); auto& nph = g_fxo->get>(); @@ -6962,7 +6962,7 @@ error_code sceNpSignalingGetConnectionFromPeerAddress(u32 ctx_id, np_in_addr_t p return CELL_OK; } -error_code sceNpSignalingGetLocalNetInfo(u32 ctx_id, vm::ptr info) +error_code sceNpSignalingGetLocalNetInfo(u32 ctx_id, vm::ptr info) { sceNp.warning("sceNpSignalingGetLocalNetInfo(ctx_id=%d, info=*0x%x)", ctx_id, info); @@ -6973,7 +6973,8 @@ error_code sceNpSignalingGetLocalNetInfo(u32 ctx_id, vm::ptrsize != sizeof(SceNpSignalingNetInfo)) + // Library has backward support for a version of SceNpSignalingNetInfo without npport + if (!info || (info->size != sizeof(SceNpSignalingNetInfo) && info->size != sizeof(SceNpSignalingNetInfoDeprecated))) { return SCE_NP_SIGNALING_ERROR_INVALID_ARGUMENT; } @@ -6985,7 +6986,12 @@ error_code sceNpSignalingGetLocalNetInfo(u32 ctx_id, vm::ptrnat_status = SCE_NP_SIGNALING_NETINFO_NAT_STATUS_TYPE2; info->upnp_status = nph.get_upnp_status(); info->npport_status = SCE_NP_SIGNALING_NETINFO_NPPORT_STATUS_OPEN; - info->npport = SCE_NP_PORT; + + if (info->size == sizeof(SceNpSignalingNetInfo)) + { + auto new_info = vm::unsafe_ptr_cast(info); + new_info->npport = SCE_NP_PORT; + } return CELL_OK; } diff --git a/rpcs3/Emu/Cell/Modules/sceNp.h b/rpcs3/Emu/Cell/Modules/sceNp.h index bc2ab7c6e2..12ca388ba2 100644 --- a/rpcs3/Emu/Cell/Modules/sceNp.h +++ b/rpcs3/Emu/Cell/Modules/sceNp.h @@ -1584,6 +1584,16 @@ struct SceNpSignalingNetInfo be_t npport; }; +struct SceNpSignalingNetInfoDeprecated +{ + be_t size; + be_t local_addr; // in_addr + be_t mapped_addr; // in_addr + be_t nat_status; + be_t upnp_status; + be_t npport_status; +}; + struct SceNpCustomMenuAction { be_t options; diff --git a/rpcs3/Emu/Cell/Modules/sceNp2.cpp b/rpcs3/Emu/Cell/Modules/sceNp2.cpp index ed4655ccd4..7a2ee50bd8 100644 --- a/rpcs3/Emu/Cell/Modules/sceNp2.cpp +++ b/rpcs3/Emu/Cell/Modules/sceNp2.cpp @@ -1300,7 +1300,7 @@ error_code sceNpMatching2GrantRoomOwner( error_code sceNpMatching2CreateContext( vm::cptr npId, vm::cptr commId, vm::cptr passPhrase, vm::ptr ctxId, s32 option) { - sceNp2.warning("sceNpMatching2CreateContext(npId=*0x%x, commId=*0x%x(%s), passPhrase=*0x%x, ctxId=*0x%x, option=%d)", npId, commId, commId ? commId->data : "", passPhrase, ctxId, option); + sceNp2.warning("sceNpMatching2CreateContext(npId=*0x%x, commId=*0x%x(%s), passPhrase=*0x%x, ctxId=*0x%x, option=%d)", npId, commId, commId ? std::string_view(commId->data, 9) : "", passPhrase, ctxId, option); auto& nph = g_fxo->get>(); diff --git a/rpcs3/Emu/NP/np_contexts.cpp b/rpcs3/Emu/NP/np_contexts.cpp index acc934c8b9..8bcfd5f01c 100644 --- a/rpcs3/Emu/NP/np_contexts.cpp +++ b/rpcs3/Emu/NP/np_contexts.cpp @@ -4,6 +4,7 @@ #include "Emu/Cell/PPUCallback.h" #include "Emu/IdManager.h" #include "Emu/Cell/Modules/cellSysutil.h" +#include "np_helpers.h" LOG_CHANNEL(sceNp2); @@ -53,7 +54,7 @@ void generic_async_transaction_context::set_result_and_wake(error_code err) tus_ctx::tus_ctx(vm::cptr communicationId, vm::cptr passphrase) { - ensure(!communicationId->data[9] && strlen(communicationId->data) == 9); + ensure(communicationId && np::validate_communication_id(*communicationId), "tus_ctx::tus_ctx: Invalid SceNpCommunicationId"); memcpy(&this->communicationId, communicationId.get_ptr(), sizeof(SceNpCommunicationId)); memcpy(&this->passphrase, passphrase.get_ptr(), sizeof(SceNpCommunicationPassphrase)); } @@ -96,7 +97,7 @@ bool destroy_tus_transaction_context(s32 ctx_id) score_ctx::score_ctx(vm::cptr communicationId, vm::cptr passphrase) { - ensure(!communicationId->data[9] && strlen(communicationId->data) == 9); + ensure(communicationId && np::validate_communication_id(*communicationId), "score_ctx::score_ctx: Invalid SceNpCommunicationId"); memcpy(&this->communicationId, communicationId.get_ptr(), sizeof(SceNpCommunicationId)); memcpy(&this->passphrase, passphrase.get_ptr(), sizeof(SceNpCommunicationPassphrase)); } @@ -140,7 +141,7 @@ bool destroy_score_transaction_context(s32 ctx_id) match2_ctx::match2_ctx(vm::cptr communicationId, vm::cptr passphrase, s32 option) { - ensure(!communicationId->data[9] && strlen(communicationId->data) == 9); + ensure(communicationId && np::validate_communication_id(*communicationId), "match2_ctx::match2_ctx: Invalid SceNpCommunicationId"); memcpy(&this->communicationId, communicationId.get_ptr(), sizeof(SceNpCommunicationId)); memcpy(&this->passphrase, passphrase.get_ptr(), sizeof(SceNpCommunicationPassphrase)); @@ -149,7 +150,7 @@ match2_ctx::match2_ctx(vm::cptr communicationId, vm::cptr< } u16 create_match2_context(vm::cptr communicationId, vm::cptr passphrase, s32 option) { - sceNp2.notice("Creating match2 context with communicationId: <%s>", static_cast(communicationId->data)); + sceNp2.notice("Creating match2 context with communicationId: <%s>", std::string_view(communicationId->data, 9)); return static_cast(idm::make(communicationId, passphrase, option)); } bool destroy_match2_context(u16 ctx_id) @@ -167,7 +168,7 @@ shared_ptr get_match2_context(u16 ctx_id) lookup_title_ctx::lookup_title_ctx(vm::cptr communicationId) { - ensure(!communicationId->data[9] && strlen(communicationId->data) == 9); + ensure(communicationId && np::validate_communication_id(*communicationId), "lookup_title_ctx::lookup_title_ctx: Invalid SceNpCommunicationId"); memcpy(&this->communicationId, communicationId.get_ptr(), sizeof(SceNpCommunicationId)); } s32 create_lookup_title_context(vm::cptr communicationId) diff --git a/rpcs3/Emu/NP/np_helpers.cpp b/rpcs3/Emu/NP/np_helpers.cpp index 641a15dde3..b6e49b97b2 100644 --- a/rpcs3/Emu/NP/np_helpers.cpp +++ b/rpcs3/Emu/NP/np_helpers.cpp @@ -1,3 +1,4 @@ +#include "Emu/Cell/Modules/sceNp.h" #include "stdafx.h" #include "util/types.hpp" #include "Utilities/StrUtil.h" @@ -22,9 +23,15 @@ namespace np return fmt::format("%02X:%02X:%02X:%02X:%02X:%02X", ether[0], ether[1], ether[2], ether[3], ether[4], ether[5]); } + bool validate_communication_id(const SceNpCommunicationId& com_id) + { + return std::all_of(com_id.data, com_id.data + 9, [](char c) { return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z'); }) && com_id.num <= 99; + } + std::string communication_id_to_string(const SceNpCommunicationId& communicationId) { - return fmt::format("%s_%02d", communicationId.data, communicationId.num); + std::string_view com_id_data(communicationId.data, 9); + return fmt::format("%s_%02d", com_id_data, communicationId.num); } void strings_to_userinfo(std::string_view npid, std::string_view online_name, std::string_view avatar_url, SceNpUserInfo& user_info) diff --git a/rpcs3/Emu/NP/np_helpers.h b/rpcs3/Emu/NP/np_helpers.h index a90f5d144c..054e45388d 100644 --- a/rpcs3/Emu/NP/np_helpers.h +++ b/rpcs3/Emu/NP/np_helpers.h @@ -8,6 +8,7 @@ namespace np { std::string ip_to_string(u32 addr); std::string ether_to_string(std::array& ether); + bool validate_communication_id(const SceNpCommunicationId& com_id); std::string communication_id_to_string(const SceNpCommunicationId& communicationId); void string_to_npid(std::string_view str, SceNpId& npid); diff --git a/rpcs3/Emu/NP/rpcn_client.cpp b/rpcs3/Emu/NP/rpcn_client.cpp index 5074ea81a4..c1dce01cdb 100644 --- a/rpcs3/Emu/NP/rpcn_client.cpp +++ b/rpcs3/Emu/NP/rpcn_client.cpp @@ -2752,7 +2752,7 @@ namespace rpcn void rpcn_client::write_communication_id(const SceNpCommunicationId& com_id, std::vector& data) { - ensure(com_id.data[9] == 0 && com_id.num <= 99, "rpcn_client::write_communication_id: Invalid SceNpCommunicationId"); + ensure(np::validate_communication_id(com_id), "rpcn_client::write_communication_id: Invalid SceNpCommunicationId"); const std::string com_id_str = np::communication_id_to_string(com_id); ensure(com_id_str.size() == 12, "rpcn_client::write_communication_id: Error formatting SceNpCommunicationId"); memcpy(data.data(), com_id_str.data(), COMMUNICATION_ID_SIZE); diff --git a/rpcs3/Emu/RSX/VK/VKCompute.cpp b/rpcs3/Emu/RSX/VK/VKCompute.cpp index 3df2c9695a..9e9e2a4746 100644 --- a/rpcs3/Emu/RSX/VK/VKCompute.cpp +++ b/rpcs3/Emu/RSX/VK/VKCompute.cpp @@ -246,7 +246,7 @@ namespace vk void cs_shuffle_base::bind_resources(const vk::command_buffer& cmd) { set_parameters(cmd); - m_program->bind_uniform({ m_data->value, m_data_offset, m_data_length }, 0, 0); + m_program->bind_uniform({ *m_data, m_data_offset, m_data_length }, 0, 0); } void cs_shuffle_base::set_parameters(const vk::command_buffer& cmd) @@ -296,7 +296,7 @@ namespace vk void cs_interleave_task::bind_resources(const vk::command_buffer& cmd) { set_parameters(cmd); - m_program->bind_uniform({ m_data->value, m_data_offset, m_ssbo_length }, 0, 0); + m_program->bind_uniform({ *m_data, m_data_offset, m_ssbo_length }, 0, 0); } void cs_interleave_task::run(const vk::command_buffer& cmd, const vk::buffer* data, u32 data_offset, u32 data_length, u32 zeta_offset, u32 stencil_offset) @@ -355,8 +355,8 @@ namespace vk void cs_aggregator::bind_resources(const vk::command_buffer& /*cmd*/) { - m_program->bind_uniform({ src->value, 0, block_length }, 0, 0); - m_program->bind_uniform({ dst->value, 0, 4 }, 0, 1); + m_program->bind_uniform({ *src, 0, block_length }, 0, 0); + m_program->bind_uniform({ *dst, 0, 4 }, 0, 1); } void cs_aggregator::run(const vk::command_buffer& cmd, const vk::buffer* dst, const vk::buffer* src, u32 num_words) diff --git a/rpcs3/Emu/RSX/VK/VKCompute.h b/rpcs3/Emu/RSX/VK/VKCompute.h index 5d20a60391..6e8f37772a 100644 --- a/rpcs3/Emu/RSX/VK/VKCompute.h +++ b/rpcs3/Emu/RSX/VK/VKCompute.h @@ -347,7 +347,7 @@ namespace vk void bind_resources(const vk::command_buffer& cmd) override { set_parameters(cmd); - m_program->bind_uniform({ m_data->value, m_data_offset, m_ssbo_length }, 0, 0); + m_program->bind_uniform({ *m_data, m_data_offset, m_ssbo_length }, 0, 0); } void run(const vk::command_buffer& cmd, const vk::buffer* data, u32 src_offset, u32 src_length, u32 dst_offset) @@ -449,8 +449,8 @@ namespace vk { set_parameters(cmd); - m_program->bind_uniform({ src_buffer->value, in_offset, block_length }, 0, 0); - m_program->bind_uniform({ dst_buffer->value, out_offset, block_length }, 0, 1); + m_program->bind_uniform({ *src_buffer, in_offset, block_length }, 0, 0); + m_program->bind_uniform({ *dst_buffer, out_offset, block_length }, 0, 1); } void set_parameters(const vk::command_buffer& cmd) @@ -579,8 +579,8 @@ namespace vk set_parameters(cmd); const auto op = static_cast(Op); - m_program->bind_uniform({ src_buffer->value, in_offset, in_block_length }, 0u, 0u ^ op); - m_program->bind_uniform({ dst_buffer->value, out_offset, out_block_length }, 0u, 1u ^ op); + m_program->bind_uniform({ *src_buffer, in_offset, in_block_length }, 0u, 0u ^ op); + m_program->bind_uniform({ *dst_buffer, out_offset, out_block_length }, 0u, 1u ^ op); } void set_parameters(const vk::command_buffer& cmd) diff --git a/rpcs3/Emu/RSX/VK/VKDraw.cpp b/rpcs3/Emu/RSX/VK/VKDraw.cpp index 345103264e..6101aeb9de 100644 --- a/rpcs3/Emu/RSX/VK/VKDraw.cpp +++ b/rpcs3/Emu/RSX/VK/VKDraw.cpp @@ -505,16 +505,17 @@ void VKGSRender::load_texture_env() } } - if (g_cfg.video.vk.asynchronous_texture_streaming) + if (backend_config.supports_asynchronous_compute) { // We have to do this here, because we have to assume the CB will be dumped - auto& async_task_scheduler = g_fxo->get(); + auto async_task_scheduler = g_fxo->try_get(); - if (async_task_scheduler.is_recording() && - !async_task_scheduler.is_host_mode()) + if (async_task_scheduler && + async_task_scheduler->is_recording() && + !async_task_scheduler->is_host_mode()) { // Sync any async scheduler tasks - if (auto ev = async_task_scheduler.get_primary_sync_label()) + if (auto ev = async_task_scheduler->get_primary_sync_label()) { ev->gpu_wait(*m_current_command_buffer, m_async_compute_dependency_info); } @@ -816,8 +817,8 @@ void VKGSRender::emit_geometry(u32 sub_index) m_current_command_buffer->flags |= (vk::command_buffer::cb_has_occlusion_task | vk::command_buffer::cb_has_open_query); } - auto persistent_buffer = m_persistent_attribute_storage ? m_persistent_attribute_storage->value : null_buffer_view->value; - auto volatile_buffer = m_volatile_attribute_storage ? m_volatile_attribute_storage->value : null_buffer_view->value; + VkDescriptorBufferViewEx persistent_buffer = m_persistent_attribute_storage ? *m_persistent_attribute_storage : *null_buffer_view; + VkDescriptorBufferViewEx volatile_buffer = m_volatile_attribute_storage ? *m_volatile_attribute_storage : *null_buffer_view; bool update_descriptors = false; if (m_current_draw.subdraw_id == 0) diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index 634c95c0c1..37feb1288b 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -553,13 +553,13 @@ VKGSRender::VKGSRender(utils::serial* ar) noexcept : GSRender(ar) } // Initialize optional allocation information with placeholders - m_vertex_env_buffer_info = { m_vertex_env_ring_info.heap->value, 0, VK_WHOLE_SIZE }; - m_vertex_constants_buffer_info = { m_transform_constants_ring_info.heap->value, 0, VK_WHOLE_SIZE }; - m_fragment_env_buffer_info = { m_fragment_env_ring_info.heap->value, 0, VK_WHOLE_SIZE }; - m_fragment_texture_params_buffer_info = { m_fragment_texture_params_ring_info.heap->value, 0, VK_WHOLE_SIZE }; - m_raster_env_buffer_info = { m_raster_env_ring_info.heap->value, 0, VK_WHOLE_SIZE }; - m_vertex_layout_stream_info = { m_vertex_layout_ring_info.heap->value, 0, VK_WHOLE_SIZE }; - m_fragment_constants_buffer_info = { m_fragment_constants_ring_info.heap->value, 0, VK_WHOLE_SIZE }; + m_vertex_env_buffer_info = { *m_vertex_env_ring_info.heap, 0, VK_WHOLE_SIZE }; + m_vertex_constants_buffer_info = { *m_transform_constants_ring_info.heap, 0, VK_WHOLE_SIZE }; + m_fragment_env_buffer_info = { *m_fragment_env_ring_info.heap, 0, VK_WHOLE_SIZE }; + m_fragment_texture_params_buffer_info = { *m_fragment_texture_params_ring_info.heap, 0, VK_WHOLE_SIZE }; + m_raster_env_buffer_info = { *m_raster_env_ring_info.heap, 0, VK_WHOLE_SIZE }; + m_vertex_layout_stream_info = { *m_vertex_layout_ring_info.heap, 0, VK_WHOLE_SIZE }; + m_fragment_constants_buffer_info = { *m_fragment_constants_ring_info.heap, 0, VK_WHOLE_SIZE }; const auto& limits = m_device->gpu().get_limits(); m_texbuffer_view_size = std::min(limits.maxTexelBufferElements, VK_ATTRIB_RING_BUFFER_SIZE_M * 0x100000u); @@ -1980,8 +1980,8 @@ void VKGSRender::load_program_env() m_draw_processor.fill_constants_instancing_buffer(indirection_table_buf, constants_array_buf, bound_vertex_prog); m_instancing_buffer_ring_info.unmap(); - m_instancing_indirection_buffer_info = { m_instancing_buffer_ring_info.heap->value, indirection_table_offset, indirection_table_buf.size() }; - m_instancing_constants_array_buffer_info = { m_instancing_buffer_ring_info.heap->value, constants_data_table_offset, constants_array_buf.size() }; + m_instancing_indirection_buffer_info = { *m_instancing_buffer_ring_info.heap, indirection_table_offset, indirection_table_buf.size() }; + m_instancing_constants_array_buffer_info = { *m_instancing_buffer_ring_info.heap, constants_data_table_offset, constants_array_buf.size() }; } else if (update_transform_constants) { @@ -2066,7 +2066,7 @@ void VKGSRender::load_program_env() std::memcpy(vp_buf + 16, current_vertex_program.data.data(), current_vp_metadata.ucode_length); m_vertex_instructions_buffer.unmap(); - m_vertex_instructions_buffer_info = { m_vertex_instructions_buffer.heap->value, vp_mapping, vp_block_length }; + m_vertex_instructions_buffer_info = { *m_vertex_instructions_buffer.heap, vp_mapping, vp_block_length }; } if (m_interpreter_state & rsx::fragment_program_dirty) @@ -2084,7 +2084,7 @@ void VKGSRender::load_program_env() std::memcpy(fp_buf + 16, current_fragment_program.get_data(), current_fragment_program.ucode_length); m_fragment_instructions_buffer.unmap(); - m_fragment_instructions_buffer_info = { m_fragment_instructions_buffer.heap->value, fp_mapping, fp_block_length }; + m_fragment_instructions_buffer_info = { *m_fragment_instructions_buffer.heap, fp_mapping, fp_block_length }; } } @@ -2111,7 +2111,7 @@ void VKGSRender::load_program_env() if (vk::emulate_conditional_rendering()) { - const VkBuffer predicate = m_cond_render_buffer ? m_cond_render_buffer->value : vk::get_scratch_buffer(*m_current_command_buffer, 4)->value; + const vk::buffer& predicate = m_cond_render_buffer ? *m_cond_render_buffer : *vk::get_scratch_buffer(*m_current_command_buffer, 4); const u32 offset = cond_render_ctrl.hw_cond_active ? 0 : 4; m_program->bind_uniform({ predicate, offset, 4 }, vk::glsl::binding_set_index_vertex, m_vs_binding_table->cr_pred_buffer_location); } diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.h b/rpcs3/Emu/RSX/VK/VKGSRender.h index 1b6ff56c5d..47af7e78c5 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.h +++ b/rpcs3/Emu/RSX/VK/VKGSRender.h @@ -4,6 +4,7 @@ #include "vkutils/descriptors.h" #include "vkutils/data_heap.h" +#include "vkutils/ex.h" #include "vkutils/instance.h" #include "vkutils/sync.h" #include "vkutils/swapchain.h" @@ -136,18 +137,18 @@ private: vk::data_heap m_fragment_instructions_buffer; vk::data_heap m_vertex_instructions_buffer; - VkDescriptorBufferInfo m_vertex_env_buffer_info {}; - VkDescriptorBufferInfo m_fragment_env_buffer_info {}; - VkDescriptorBufferInfo m_vertex_layout_stream_info {}; - VkDescriptorBufferInfo m_vertex_constants_buffer_info {}; - VkDescriptorBufferInfo m_fragment_constants_buffer_info {}; - VkDescriptorBufferInfo m_fragment_texture_params_buffer_info {}; - VkDescriptorBufferInfo m_raster_env_buffer_info {}; - VkDescriptorBufferInfo m_instancing_indirection_buffer_info {}; - VkDescriptorBufferInfo m_instancing_constants_array_buffer_info{}; + VkDescriptorBufferInfoEx m_vertex_env_buffer_info {}; + VkDescriptorBufferInfoEx m_fragment_env_buffer_info {}; + VkDescriptorBufferInfoEx m_vertex_layout_stream_info {}; + VkDescriptorBufferInfoEx m_vertex_constants_buffer_info {}; + VkDescriptorBufferInfoEx m_fragment_constants_buffer_info {}; + VkDescriptorBufferInfoEx m_fragment_texture_params_buffer_info {}; + VkDescriptorBufferInfoEx m_raster_env_buffer_info {}; + VkDescriptorBufferInfoEx m_instancing_indirection_buffer_info {}; + VkDescriptorBufferInfoEx m_instancing_constants_array_buffer_info{}; - VkDescriptorBufferInfo m_vertex_instructions_buffer_info {}; - VkDescriptorBufferInfo m_fragment_instructions_buffer_info {}; + VkDescriptorBufferInfoEx m_vertex_instructions_buffer_info {}; + VkDescriptorBufferInfoEx m_fragment_instructions_buffer_info {}; rsx::simple_array m_multidraw_parameters_buffer; 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. diff --git a/rpcs3/Emu/RSX/VK/VKOverlays.cpp b/rpcs3/Emu/RSX/VK/VKOverlays.cpp index 9ca5a16aaa..3307dc3a48 100644 --- a/rpcs3/Emu/RSX/VK/VKOverlays.cpp +++ b/rpcs3/Emu/RSX/VK/VKOverlays.cpp @@ -183,7 +183,7 @@ namespace vk if (m_num_uniform_buffers > 0) { - program->bind_uniform({ m_ubo.heap->value, m_ubo_offset, std::max(m_ubo_length, 4u) }, 0, 0); + program->bind_uniform({ *m_ubo.heap, m_ubo_offset, std::max(m_ubo_length, 4u) }, 0, 0); } for (uint n = 0; n < src.size(); ++n) diff --git a/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp b/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp index 588c7a5a58..96f45ae7a2 100644 --- a/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp +++ b/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp @@ -18,25 +18,26 @@ namespace vk { const auto ptr = std::get_if(&a); return !!ptr && - ptr->imageView == b.imageView && ptr->resourceId == b.resourceId && + ptr->imageView == b.imageView && ptr->sampler == b.sampler && ptr->imageLayout == b.imageLayout; } - bool operator == (const descriptor_slot_t& a, const VkDescriptorBufferInfo& b) + bool operator == (const descriptor_slot_t& a, const VkDescriptorBufferInfoEx& b) { - const auto ptr = std::get_if(&a); + const auto ptr = std::get_if(&a); return !!ptr && + ptr->resourceId == b.resourceId && ptr->buffer == b.buffer && ptr->offset == b.offset && ptr->range == b.range; } - bool operator == (const descriptor_slot_t& a, const VkBufferView& b) + bool operator == (const descriptor_slot_t& a, const VkDescriptorBufferViewEx& b) { - const auto ptr = std::get_if(&a); - return !!ptr && *ptr == b; + const auto ptr = std::get_if(&a); + return !!ptr && ptr->resourceId == b.resourceId; } bool operator == (const descriptor_slot_t& a, const std::span& b) @@ -324,7 +325,7 @@ namespace vk m_sets[set_id].notify_descriptor_slot_updated(binding_point, image_descriptor); } - void program::bind_uniform(const VkDescriptorBufferInfo &buffer_descriptor, u32 set_id, u32 binding_point) + void program::bind_uniform(const VkDescriptorBufferInfoEx &buffer_descriptor, u32 set_id, u32 binding_point) { if (m_sets[set_id].m_descriptor_slots[binding_point] == buffer_descriptor) { @@ -334,7 +335,7 @@ namespace vk m_sets[set_id].notify_descriptor_slot_updated(binding_point, buffer_descriptor); } - void program::bind_uniform(const VkBufferView &buffer_view, u32 set_id, u32 binding_point) + void program::bind_uniform(const VkDescriptorBufferViewEx& buffer_view, u32 set_id, u32 binding_point) { if (m_sets[set_id].m_descriptor_slots[binding_point] == buffer_view) { @@ -486,15 +487,15 @@ namespace vk return; } - if (auto ptr = std::get_if(&slot)) + if (auto ptr = std::get_if(&slot)) { m_descriptor_set.push(*ptr, type, idx); return; } - if (auto ptr = std::get_if(&slot)) + if (auto ptr = std::get_if(&slot)) { - m_descriptor_set.push(*ptr, type, idx); + m_descriptor_set.push(ptr->view, type, idx); return; } @@ -537,15 +538,15 @@ namespace vk return; } - if (auto ptr = std::get_if(&slot)) + if (auto ptr = std::get_if(&slot)) { m_descriptor_template[idx].pBufferInfo = m_descriptor_set.store(*ptr); return; } - if (auto ptr = std::get_if(&slot)) + if (auto ptr = std::get_if(&slot)) { - m_descriptor_template[idx].pTexelBufferView = m_descriptor_set.store(*ptr); + m_descriptor_template[idx].pTexelBufferView = m_descriptor_set.store(ptr->view); return; } diff --git a/rpcs3/Emu/RSX/VK/VKProgramPipeline.h b/rpcs3/Emu/RSX/VK/VKProgramPipeline.h index 425069a0c4..dba619ec88 100644 --- a/rpcs3/Emu/RSX/VK/VKProgramPipeline.h +++ b/rpcs3/Emu/RSX/VK/VKProgramPipeline.h @@ -115,7 +115,11 @@ namespace vk }; using descriptor_image_array_t = rsx::simple_array; - using descriptor_slot_t = std::variant; + using descriptor_slot_t = std::variant< + VkDescriptorImageInfoEx, + VkDescriptorBufferInfoEx, + VkDescriptorBufferViewEx, + descriptor_image_array_t>; struct descriptor_table_t { @@ -202,9 +206,9 @@ namespace vk std::pair get_uniform_location(::glsl::program_domain domain, program_input_type type, const std::string& uniform_name); void bind_uniform(const VkDescriptorImageInfoEx& image_descriptor, u32 set_id, u32 binding_point); - void bind_uniform(const VkDescriptorBufferInfo &buffer_descriptor, u32 set_id, u32 binding_point); - void bind_uniform(const VkBufferView &buffer_view, u32 set_id, u32 binding_point); - void bind_uniform(const VkBufferView &buffer_view, ::glsl::program_domain domain, program_input_type type, const std::string &binding_name); + void bind_uniform(const VkDescriptorBufferInfoEx& buffer_descriptor, u32 set_id, u32 binding_point); + void bind_uniform(const VkDescriptorBufferViewEx& buffer_view, u32 set_id, u32 binding_point); + void bind_uniform(const VkDescriptorBufferViewEx& buffer_view, ::glsl::program_domain domain, program_input_type type, const std::string &binding_name); void bind_uniform_array(const std::span& image_descriptors,u32 set_id, u32 binding_point); diff --git a/rpcs3/Emu/RSX/VK/VKTexture.cpp b/rpcs3/Emu/RSX/VK/VKTexture.cpp index 23b76df52b..413333d500 100644 --- a/rpcs3/Emu/RSX/VK/VKTexture.cpp +++ b/rpcs3/Emu/RSX/VK/VKTexture.cpp @@ -867,7 +867,7 @@ namespace vk static const vk::command_buffer& prepare_for_transfer(const vk::command_buffer& primary_cb, vk::image* dst_image, rsx::flags32_t& flags) { AsyncTaskScheduler* async_scheduler = (flags & image_upload_options::upload_contents_async) - ? std::addressof(g_fxo->get()) + ? g_fxo->try_get() : nullptr; if (async_scheduler && (dst_image->aspect() & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT))) diff --git a/rpcs3/Emu/RSX/VK/VKTextureCache.cpp b/rpcs3/Emu/RSX/VK/VKTextureCache.cpp index 4505528a34..b6743f1291 100644 --- a/rpcs3/Emu/RSX/VK/VKTextureCache.cpp +++ b/rpcs3/Emu/RSX/VK/VKTextureCache.cpp @@ -1115,7 +1115,7 @@ namespace vk const bool upload_async = rsx::get_current_renderer()->get_backend_config().supports_asynchronous_compute; rsx::flags32_t create_flags = 0; - if (upload_async && g_fxo->get().is_host_mode()) + if (upload_async && ensure(g_fxo->try_get())->is_host_mode()) { create_flags |= texture_create_flags::do_not_reuse; if (m_device->get_graphics_queue() != m_device->get_transfer_queue()) diff --git a/rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp b/rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp index 128aa53546..d9e9cee9e2 100644 --- a/rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp +++ b/rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp @@ -329,13 +329,13 @@ vk::vertex_upload_info VKGSRender::upload_vertex_data() vk::get_resource_manager()->dispose(m_volatile_attribute_storage); } - m_vertex_env_buffer_info = { m_vertex_env_ring_info.heap->value, 0, VK_WHOLE_SIZE }; - m_vertex_constants_buffer_info = { m_transform_constants_ring_info.heap->value, 0, VK_WHOLE_SIZE }; - m_fragment_env_buffer_info = { m_fragment_env_ring_info.heap->value, 0, VK_WHOLE_SIZE }; - m_fragment_texture_params_buffer_info = { m_fragment_texture_params_ring_info.heap->value, 0, VK_WHOLE_SIZE }; - m_raster_env_buffer_info = { m_raster_env_ring_info.heap->value, 0, VK_WHOLE_SIZE }; - m_vertex_layout_stream_info = { m_vertex_layout_ring_info.heap->value, 0, VK_WHOLE_SIZE }; - m_fragment_constants_buffer_info = { m_fragment_constants_ring_info.heap->value, 0, VK_WHOLE_SIZE }; + m_vertex_env_buffer_info = { *m_vertex_env_ring_info.heap, 0, VK_WHOLE_SIZE }; + m_vertex_constants_buffer_info = { *m_transform_constants_ring_info.heap, 0, VK_WHOLE_SIZE }; + m_fragment_env_buffer_info = { *m_fragment_env_ring_info.heap, 0, VK_WHOLE_SIZE }; + m_fragment_texture_params_buffer_info = { *m_fragment_texture_params_ring_info.heap, 0, VK_WHOLE_SIZE }; + m_raster_env_buffer_info = { *m_raster_env_ring_info.heap, 0, VK_WHOLE_SIZE }; + m_vertex_layout_stream_info = { *m_vertex_layout_ring_info.heap, 0, VK_WHOLE_SIZE }; + m_fragment_constants_buffer_info = { *m_fragment_constants_ring_info.heap, 0, VK_WHOLE_SIZE }; vk::clear_status_interrupt(vk::heap_changed); } diff --git a/rpcs3/Emu/RSX/VK/vkutils/buffer_object.h b/rpcs3/Emu/RSX/VK/vkutils/buffer_object.h index 03f5659e49..c74cb1aaa5 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/buffer_object.h +++ b/rpcs3/Emu/RSX/VK/vkutils/buffer_object.h @@ -3,10 +3,11 @@ #include "../VulkanAPI.h" #include "device.h" #include "memory.h" +#include "unique_resource.h" namespace vk { - struct buffer_view + struct buffer_view : public unique_resource { VkBufferView value; VkBufferViewCreateInfo info = {}; @@ -23,7 +24,7 @@ namespace vk VkDevice m_device; }; - struct buffer + struct buffer : public unique_resource { VkBuffer value; VkBufferCreateInfo info = {}; diff --git a/rpcs3/Emu/RSX/VK/vkutils/ex.cpp b/rpcs3/Emu/RSX/VK/vkutils/ex.cpp index 1e4b68c904..0f0c799859 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/ex.cpp +++ b/rpcs3/Emu/RSX/VK/vkutils/ex.cpp @@ -1,4 +1,5 @@ #include "ex.h" +#include "buffer_object.h" #include "image.h" #include "sampler.h" @@ -6,21 +7,31 @@ namespace vk { VkDescriptorImageInfoEx::VkDescriptorImageInfoEx(const vk::image_view& view, const vk::sampler& sampler, VkImageLayout layout) : VkDescriptorImageInfo(sampler.value, view.value, layout) - , resourceId(view.image()->id()) + , resourceId(view.image()->uid()) {} VkDescriptorImageInfoEx::VkDescriptorImageInfoEx(const vk::image_view& view, const vk::sampler& sampler) : VkDescriptorImageInfo(sampler.value, view.value, view.image()->current_layout) - , resourceId(view.image()->id()) + , resourceId(view.image()->uid()) {} VkDescriptorImageInfoEx::VkDescriptorImageInfoEx(const vk::image_view& view, VkSampler sampler) : VkDescriptorImageInfo(sampler, view.value, view.image()->current_layout) - , resourceId(view.image()->id()) + , resourceId(view.image()->uid()) {} VkDescriptorImageInfoEx::VkDescriptorImageInfoEx(const vk::image_view& view) : VkDescriptorImageInfo(VK_NULL_HANDLE, view.value, view.image()->current_layout) - , resourceId(view.image()->id()) + , resourceId(view.image()->uid()) + {} + + VkDescriptorBufferViewEx::VkDescriptorBufferViewEx(const vk::buffer_view& view) + : resourceId(view.uid()) + , view(view.value) + {} + + VkDescriptorBufferInfoEx::VkDescriptorBufferInfoEx(const vk::buffer& buffer, u64 offset, u64 range) + : VkDescriptorBufferInfo(buffer.value, offset, range) + , resourceId(buffer.uid()) {} } diff --git a/rpcs3/Emu/RSX/VK/vkutils/ex.h b/rpcs3/Emu/RSX/VK/vkutils/ex.h index ee49e7bc55..361ae1d32d 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/ex.h +++ b/rpcs3/Emu/RSX/VK/vkutils/ex.h @@ -5,6 +5,8 @@ // Custom extensions to vulkan core namespace vk { + struct buffer; + struct buffer_view; struct image_view; struct sampler; @@ -20,8 +22,27 @@ namespace vk VkDescriptorImageInfoEx(const vk::image_view& view, VkSampler sampler); VkDescriptorImageInfoEx(const vk::image_view& view); }; + + struct VkDescriptorBufferViewEx + { + u64 resourceId = 0ull; + VkBufferView view = VK_NULL_HANDLE; + + VkDescriptorBufferViewEx() = default; + VkDescriptorBufferViewEx(const vk::buffer_view& view); + }; + + struct VkDescriptorBufferInfoEx : public VkDescriptorBufferInfo + { + u64 resourceId = 0ull; + + VkDescriptorBufferInfoEx() = default; + VkDescriptorBufferInfoEx(const vk::buffer& buffer, u64 offset, u64 range); + }; } // Re-export using VkDescriptorImageInfoEx = vk::VkDescriptorImageInfoEx; +using VkDescriptorBufferViewEx = vk::VkDescriptorBufferViewEx; +using VkDescriptorBufferInfoEx = vk::VkDescriptorBufferInfoEx; diff --git a/rpcs3/Emu/RSX/VK/vkutils/image.cpp b/rpcs3/Emu/RSX/VK/vkutils/image.cpp index 65ab7f9f16..31499b0ce1 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/image.cpp +++ b/rpcs3/Emu/RSX/VK/vkutils/image.cpp @@ -10,8 +10,6 @@ namespace vk { - static atomic_t s_image_uid_counter = 0; - void image::validate(const vk::render_device& dev, const VkImageCreateInfo& info) const { const auto& gpu_limits = dev.gpu().get_limits(); @@ -121,8 +119,6 @@ namespace vk CHECK_RESULT(vkCreateImage(m_device, &info, nullptr, &value)); - m_uid = s_image_uid_counter++; - VkMemoryRequirements memory_req; vkGetImageMemoryRequirements(m_device, value, &memory_req); diff --git a/rpcs3/Emu/RSX/VK/vkutils/image.h b/rpcs3/Emu/RSX/VK/vkutils/image.h index d7ec263f17..91ebf5616e 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/image.h +++ b/rpcs3/Emu/RSX/VK/vkutils/image.h @@ -6,6 +6,7 @@ #include "commands.h" #include "device.h" #include "memory.h" +#include "unique_resource.h" #include @@ -26,7 +27,7 @@ namespace vk VK_IMAGE_CREATE_SPECIAL_FLAGS_RPCS3 = (VK_IMAGE_CREATE_ALLOW_NULL_RPCS3 | VK_IMAGE_CREATE_SHAREABLE_RPCS3) }; - class image + class image : public unique_resource { std::stack m_layout_stack; VkImageAspectFlags m_storage_aspect = 0; @@ -68,7 +69,6 @@ namespace vk image(image&&) = delete; // Identifiers - u64 id() const { return m_uid; } VkImage handle() const { return value; } // Properties @@ -99,7 +99,6 @@ namespace vk protected: VkDevice m_device = VK_NULL_HANDLE; - u64 m_uid = 0ull; }; struct image_view diff --git a/rpcs3/Emu/RSX/VK/vkutils/unique_resource.cpp b/rpcs3/Emu/RSX/VK/vkutils/unique_resource.cpp new file mode 100644 index 0000000000..e77d6eae09 --- /dev/null +++ b/rpcs3/Emu/RSX/VK/vkutils/unique_resource.cpp @@ -0,0 +1,12 @@ +#include "unique_resource.h" +#include + +namespace vk +{ + static atomic_t s_resource_uid; + + u64 gen_uid() + { + return s_resource_uid++; + } +} diff --git a/rpcs3/Emu/RSX/VK/vkutils/unique_resource.h b/rpcs3/Emu/RSX/VK/vkutils/unique_resource.h new file mode 100644 index 0000000000..6a201cbd2e --- /dev/null +++ b/rpcs3/Emu/RSX/VK/vkutils/unique_resource.h @@ -0,0 +1,22 @@ +#pragma once + +#include + +namespace vk +{ + u64 gen_uid(); + + class unique_resource + { + public: + unique_resource() + : m_uid(gen_uid()) + {} + + u64 uid() const { return m_uid; } + bool operator == (const unique_resource& other) const { return m_uid == other.m_uid; } + + private: + u64 m_uid = 0ull; + }; +} diff --git a/rpcs3/VKGSRender.vcxproj b/rpcs3/VKGSRender.vcxproj index b964e282c1..2b02e062fb 100644 --- a/rpcs3/VKGSRender.vcxproj +++ b/rpcs3/VKGSRender.vcxproj @@ -67,6 +67,7 @@ + @@ -113,6 +114,7 @@ + diff --git a/rpcs3/VKGSRender.vcxproj.filters b/rpcs3/VKGSRender.vcxproj.filters index 143da9a07b..de87d27733 100644 --- a/rpcs3/VKGSRender.vcxproj.filters +++ b/rpcs3/VKGSRender.vcxproj.filters @@ -84,6 +84,9 @@ vkutils + + vkutils + @@ -206,6 +209,9 @@ vkutils + + vkutils + diff --git a/rpcs3/rpcs3qt/game_list_frame.cpp b/rpcs3/rpcs3qt/game_list_frame.cpp index ac9f58e329..313e043613 100644 --- a/rpcs3/rpcs3qt/game_list_frame.cpp +++ b/rpcs3/rpcs3qt/game_list_frame.cpp @@ -1223,21 +1223,30 @@ void game_list_frame::ShowContextMenu(const QPoint &pos) if (const std::string sstate = get_savestate_file(current_game.serial, current_game.path, 1); is_savestate_compatible(sstate)) { - QAction* boot_state = menu.addAction(is_current_running_game - ? tr("&Reboot with savestate") - : tr("&Boot with savestate")); - connect(boot_state, &QAction::triggered, [this, gameinfo, sstate, current_game] - { - if (!get_savestate_file(current_game.serial, current_game.path, 2).empty()) - { - // If there is any ambiguity, launch the savestate manager - Q_EMIT RequestSaveStateManager(gameinfo); - return; - } + const bool has_ambiguity = !get_savestate_file(current_game.serial, current_game.path, 2).empty(); + QAction* boot_state = menu.addAction(is_current_running_game + ? tr("&Reboot with last SaveState") + : tr("&Boot with last SaveState")); + + connect(boot_state, &QAction::triggered, [this, gameinfo, sstate] + { sys_log.notice("Booting savestate from gamelist per context menu..."); Q_EMIT RequestBoot(gameinfo, cfg_mode::custom, "", sstate); }); + + if (has_ambiguity) + { + QAction* choose_state = menu.addAction(is_current_running_game + ? tr("&Choose SaveState to reboot") + : tr("&Choose SaveState to boot")); + + connect(choose_state, &QAction::triggered, [this, gameinfo] + { + // If there is any ambiguity, launch the savestate manager + Q_EMIT RequestSaveStateManager(gameinfo); + }); + } } menu.addSeparator(); diff --git a/rpcs3/rpcs3qt/qt_utils.cpp b/rpcs3/rpcs3qt/qt_utils.cpp index 5ac9e0207e..fa5e3c250e 100644 --- a/rpcs3/rpcs3qt/qt_utils.cpp +++ b/rpcs3/rpcs3qt/qt_utils.cpp @@ -664,9 +664,22 @@ namespace gui return dateTime; } - QString format_datetime(const QDateTime& date, const QString& fmt) + QString format_datetime(const QDateTime& date, const QString& fmt, bool is_relative, const QString& fmt_relative) { - return date.toString(fmt); + const qint64 exctrated_date = date.date().toJulianDay(); + const qint64 current_date = QDate::currentDate().toJulianDay(); + + if (!is_relative || exctrated_date > current_date || current_date - exctrated_date >= 3) + { + return date.toString(fmt); + } + + if (current_date == exctrated_date) + { + return QString("Today %1").arg(date.toString(fmt_relative)); + } + + return QString("%1 days ago %2").arg(current_date - exctrated_date).arg(date.toString(fmt_relative)); } QString format_timestamp(s64 time, const QString& fmt) diff --git a/rpcs3/rpcs3qt/qt_utils.h b/rpcs3/rpcs3qt/qt_utils.h index 443148c4ff..dc15385923 100644 --- a/rpcs3/rpcs3qt/qt_utils.h +++ b/rpcs3/rpcs3qt/qt_utils.h @@ -161,7 +161,7 @@ namespace gui QDateTime datetime(s64 time); // Convert a QDateTime to a readable string - QString format_datetime(const QDateTime& date, const QString& fmt = "yyyy-MM-dd HH:mm:ss"); + QString format_datetime(const QDateTime& date, const QString& fmt = "yyyy-MM-dd HH:mm:ss", bool is_relative = false, const QString& fmt_relative = "HH:mm:ss"); // Convert a timestamp to a readable string QString format_timestamp(s64 time, const QString& fmt = "yyyy-MM-dd HH:mm:ss"); diff --git a/rpcs3/rpcs3qt/savestate_manager_dialog.cpp b/rpcs3/rpcs3qt/savestate_manager_dialog.cpp index bc37438c73..381debab01 100644 --- a/rpcs3/rpcs3qt/savestate_manager_dialog.cpp +++ b/rpcs3/rpcs3qt/savestate_manager_dialog.cpp @@ -549,33 +549,38 @@ void savestate_manager_dialog::StartSavestateLoadThreads() return; } - std::vector> game_data(count); + std::vector> game_data; qRegisterMetaType>("QVector"); QList indices; for (int i = 0; i < count; ++i) { - indices.append(i); - - game_data[i] = std::make_unique(); - game_data[i]->title_id = folder_list[i].toStdString(); + auto game_data_ptr = std::make_unique(); + game_data_ptr->title_id = folder_list[i].toStdString(); for (const game_info& gameinfo : m_game_info) { - if (gameinfo && gameinfo->info.serial == game_data[i]->title_id) + if (gameinfo && gameinfo->info.serial == game_data_ptr->title_id) { - game_data[i]->game_name = gameinfo->info.name; - game_data[i]->game_icon_path = gameinfo->info.icon_path; + game_data_ptr->game_name = gameinfo->info.name; + game_data_ptr->game_icon_path = gameinfo->info.icon_path; break; } } - if (game_data[i]->game_name.empty()) + if (!game_data_ptr->game_name.empty()) { - game_data[i]->game_name = game_data[i]->title_id; + indices.append(game_data.size()); + game_data.emplace_back(std::move(game_data_ptr)); } } + if (game_data.empty()) + { + RepaintUI(true); + return; + } + QFutureWatcher future_watcher; progress_dialog progress_dialog(tr("Loading savestates"), tr("Loading savestates, please wait..."), tr("Cancel"), 0, 1, false, this, Qt::Dialog | Qt::WindowTitleHint | Qt::CustomizeWindowHint); @@ -681,7 +686,7 @@ void savestate_manager_dialog::PopulateSavestateTable() const savestate_data& savestate = savestates[i]; m_savestate_table->setItem(i, static_cast(gui::savestate_list_columns::name), new custom_table_widget_item(savestate.name)); m_savestate_table->setItem(i, static_cast(gui::savestate_list_columns::compatible), new custom_table_widget_item(savestate.is_compatible ? tr("Compatible") : tr("Not compatible"), Qt::UserRole, savestate.is_compatible)); - m_savestate_table->setItem(i, static_cast(gui::savestate_list_columns::date), new custom_table_widget_item(gui::utils::format_datetime(savestate.date), Qt::UserRole, savestate.date)); + m_savestate_table->setItem(i, static_cast(gui::savestate_list_columns::date), new custom_table_widget_item(gui::utils::format_datetime(savestate.date, "yyyy-MM-dd HH:mm", true, "HH:mm"), Qt::UserRole, savestate.date)); m_savestate_table->setItem(i, static_cast(gui::savestate_list_columns::path), new custom_table_widget_item(savestate.path)); }