From 329655a1bff2460bdd388397184a1bcb18373d76 Mon Sep 17 00:00:00 2001 From: digant73 Date: Mon, 23 Jun 2025 20:15:33 +0200 Subject: [PATCH 01/37] fix DEBUG mode compilation --- rpcs3/Input/hid_pad_handler.h | 2 +- rpcs3/rpcs3.vcxproj | 24 ++++++++++++------------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/rpcs3/Input/hid_pad_handler.h b/rpcs3/Input/hid_pad_handler.h index 544ba21eb5..fe6f6e5925 100644 --- a/rpcs3/Input/hid_pad_handler.h +++ b/rpcs3/Input/hid_pad_handler.h @@ -29,7 +29,7 @@ extern std::mutex g_android_usb_devices_mutex; #else using hid_enumerated_device_type = std::string; using hid_enumerated_device_view = std::string_view; -inline constexpr auto hid_enumerated_device_default = std::string(); +inline const auto hid_enumerated_device_default = std::string(); #endif struct CalibData diff --git a/rpcs3/rpcs3.vcxproj b/rpcs3/rpcs3.vcxproj index 49725e50c4..0e4dab8f27 100644 --- a/rpcs3/rpcs3.vcxproj +++ b/rpcs3/rpcs3.vcxproj @@ -138,7 +138,7 @@ 4577;4467;4281;%(DisableSpecificWarnings) $(IntDir) Disabled - _WINDOWS;UNICODE;WIN32;WIN64;WIN32_LEAN_AND_MEAN;HAVE_VULKAN;HAVE_OPENCV;CV_IGNORE_DEBUG_BUILD_GUARD;MINIUPNP_STATICLIB;ZLIB_CONST;AL_LIBTYPE_STATIC;WOLFSSL_USER_SETTINGS;QT_WIDGETS_LIB;QT_GUI_LIB;QT_CORE_LIB;QT_CONCURRENT_LIB;QT_MULTIMEDIA_LIB;QT_MULTIMEDIAWIDGETS_LIB;QT_SVG_LIB;%(PreprocessorDefinitions) + _WINDOWS;UNICODE;WIN32;WIN64;WIN32_LEAN_AND_MEAN;HAVE_VULKAN;HAVE_OPENCV;CV_IGNORE_DEBUG_BUILD_GUARD;MINIUPNP_STATICLIB;ZLIB_CONST;AL_LIBTYPE_STATIC;WOLFSSL_USER_SETTINGS;HAVE_SDL3;QT_WIDGETS_LIB;QT_GUI_LIB;QT_CORE_LIB;QT_CONCURRENT_LIB;QT_MULTIMEDIA_LIB;QT_MULTIMEDIAWIDGETS_LIB;QT_SVG_LIB;%(PreprocessorDefinitions) false true true @@ -1194,7 +1194,7 @@ $(QTDIR)\bin\moc.exe;%(FullPath) Moc%27ing %(Identity)... .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp - "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWIN32_LEAN_AND_MEAN -DHAVE_VULKAN -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_CONCURRENT_LIB -DQT_MULTIMEDIA_LIB -DQT_MULTIMEDIAWIDGETS_LIB -DQT_SVG_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\SoundTouch\soundtouch\include" "-I.\..\3rdparty\cubeb\extra" "-I.\..\3rdparty\cubeb\cubeb\include" "-I.\..\3rdparty\flatbuffers\include" "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtMultimedia" "-I$(QTDIR)\include\QtMultimediaWidgets" "-I$(QTDIR)\include\QtSvg" + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWIN32_LEAN_AND_MEAN -DHAVE_VULKAN -DHAVE_SDL3 -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_CONCURRENT_LIB -DQT_MULTIMEDIA_LIB -DQT_MULTIMEDIAWIDGETS_LIB -DQT_SVG_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\SoundTouch\soundtouch\include" "-I.\..\3rdparty\cubeb\extra" "-I.\..\3rdparty\cubeb\cubeb\include" "-I.\..\3rdparty\flatbuffers\include" "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtMultimedia" "-I$(QTDIR)\include\QtMultimediaWidgets" "-I$(QTDIR)\include\QtSvg" $(QTDIR)\bin\moc.exe;%(FullPath) Moc%27ing %(Identity)... .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp @@ -1346,7 +1346,7 @@ $(QTDIR)\bin\moc.exe;%(FullPath) Moc%27ing %(Identity)... .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp - "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWIN32_LEAN_AND_MEAN -DHAVE_VULKAN -DMINIUPNP_STATICLIB -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_CONCURRENT_LIB -DQT_MULTIMEDIA_LIB -DQT_MULTIMEDIAWIDGETS_LIB -DQT_SVG_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\SoundTouch\soundtouch\include" "-I.\..\3rdparty\cubeb\extra" "-I.\..\3rdparty\cubeb\cubeb\include" "-I.\..\3rdparty\flatbuffers\include" "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtMultimedia" "-I$(QTDIR)\include\QtMultimediaWidgets" "-I$(QTDIR)\include\QtSvg" + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWIN32_LEAN_AND_MEAN -DHAVE_VULKAN -DMINIUPNP_STATICLIB -DHAVE_SDL3 -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_CONCURRENT_LIB -DQT_MULTIMEDIA_LIB -DQT_MULTIMEDIAWIDGETS_LIB -DQT_SVG_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\SoundTouch\soundtouch\include" "-I.\..\3rdparty\cubeb\extra" "-I.\..\3rdparty\cubeb\cubeb\include" "-I.\..\3rdparty\flatbuffers\include" "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtMultimedia" "-I$(QTDIR)\include\QtMultimediaWidgets" "-I$(QTDIR)\include\QtSvg" $(QTDIR)\bin\moc.exe;%(FullPath) Moc%27ing %(Identity)... .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp @@ -1356,7 +1356,7 @@ $(QTDIR)\bin\moc.exe;%(FullPath) Moc%27ing %(Identity)... .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp - "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWIN32_LEAN_AND_MEAN -DHAVE_VULKAN -DMINIUPNP_STATICLIB -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_CONCURRENT_LIB -DQT_MULTIMEDIA_LIB -DQT_MULTIMEDIAWIDGETS_LIB -DQT_SVG_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\SoundTouch\soundtouch\include" "-I.\..\3rdparty\cubeb\extra" "-I.\..\3rdparty\cubeb\cubeb\include" "-I.\..\3rdparty\flatbuffers\include" "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\rtmidi\rtmidi" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtMultimedia" "-I$(QTDIR)\include\QtMultimediaWidgets" "-I$(QTDIR)\include\QtSvg" + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWIN32_LEAN_AND_MEAN -DHAVE_VULKAN -DMINIUPNP_STATICLIB -DHAVE_SDL3 -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_CONCURRENT_LIB -DQT_MULTIMEDIA_LIB -DQT_MULTIMEDIAWIDGETS_LIB -DQT_SVG_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\SoundTouch\soundtouch\include" "-I.\..\3rdparty\cubeb\extra" "-I.\..\3rdparty\cubeb\cubeb\include" "-I.\..\3rdparty\flatbuffers\include" "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\rtmidi\rtmidi" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtMultimedia" "-I$(QTDIR)\include\QtMultimediaWidgets" "-I$(QTDIR)\include\QtSvg" $(QTDIR)\bin\moc.exe;%(FullPath) Moc%27ing %(Identity)... .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp @@ -1366,7 +1366,7 @@ $(QTDIR)\bin\moc.exe;%(FullPath) Moc%27ing %(Identity)... .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp - "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWIN32_LEAN_AND_MEAN -DHAVE_VULKAN -DMINIUPNP_STATICLIB -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_CONCURRENT_LIB -DQT_MULTIMEDIA_LIB -DQT_MULTIMEDIAWIDGETS_LIB -DQT_SVG_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\SoundTouch\soundtouch\include" "-I.\..\3rdparty\cubeb\extra" "-I.\..\3rdparty\cubeb\cubeb\include" "-I.\..\3rdparty\flatbuffers\include" "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\rtmidi\rtmidi" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtMultimedia" "-I$(QTDIR)\include\QtMultimediaWidgets" "-I$(QTDIR)\include\QtSvg" + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWIN32_LEAN_AND_MEAN -DHAVE_VULKAN -DMINIUPNP_STATICLIB -DHAVE_SDL3 -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_CONCURRENT_LIB -DQT_MULTIMEDIA_LIB -DQT_MULTIMEDIAWIDGETS_LIB -DQT_SVG_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\SoundTouch\soundtouch\include" "-I.\..\3rdparty\cubeb\extra" "-I.\..\3rdparty\cubeb\cubeb\include" "-I.\..\3rdparty\flatbuffers\include" "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\rtmidi\rtmidi" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtMultimedia" "-I$(QTDIR)\include\QtMultimediaWidgets" "-I$(QTDIR)\include\QtSvg" $(QTDIR)\bin\moc.exe;%(FullPath) Moc%27ing %(Identity)... .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp @@ -1387,7 +1387,7 @@ Moc%27ing %(Identity)... .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp - "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWIN32_LEAN_AND_MEAN -DHAVE_VULKAN -DMINIUPNP_STATICLIB -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_CONCURRENT_LIB -DQT_MULTIMEDIA_LIB -DQT_MULTIMEDIAWIDGETS_LIB -DQT_SVG_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\SoundTouch\soundtouch\include" "-I.\..\3rdparty\cubeb\extra" "-I.\..\3rdparty\cubeb\cubeb\include" "-I.\..\3rdparty\flatbuffers\include" "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtMultimedia" "-I$(QTDIR)\include\QtMultimediaWidgets" "-I$(QTDIR)\include\QtSvg" + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWIN32_LEAN_AND_MEAN -DHAVE_VULKAN -DMINIUPNP_STATICLIB -DHAVE_SDL3 -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_CONCURRENT_LIB -DQT_MULTIMEDIA_LIB -DQT_MULTIMEDIAWIDGETS_LIB -DQT_SVG_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\SoundTouch\soundtouch\include" "-I.\..\3rdparty\cubeb\extra" "-I.\..\3rdparty\cubeb\cubeb\include" "-I.\..\3rdparty\flatbuffers\include" "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtMultimedia" "-I$(QTDIR)\include\QtMultimediaWidgets" "-I$(QTDIR)\include\QtSvg" Moc%27ing %(Identity)... .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWIN32_LEAN_AND_MEAN -DHAVE_VULKAN -DMINIUPNP_STATICLIB -DHAVE_SDL3 -DWITH_DISCORD_RPC -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DNDEBUG -DQT_CONCURRENT_LIB -DQT_MULTIMEDIA_LIB -DQT_MULTIMEDIAWIDGETS_LIB -DQT_SVG_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\SoundTouch\soundtouch\include" "-I.\..\3rdparty\cubeb\extra" "-I.\..\3rdparty\cubeb\cubeb\include" "-I.\..\3rdparty\flatbuffers\include" "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I.\..\3rdparty\libsdl-org\SDL\include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtCore" "-I.\release" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtMultimedia" "-I$(QTDIR)\include\QtMultimediaWidgets" "-I$(QTDIR)\include\QtSvg" @@ -1412,7 +1412,7 @@ $(QTDIR)\bin\moc.exe;%(FullPath) Moc%27ing %(Identity)... .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp - "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWIN32_LEAN_AND_MEAN -DHAVE_VULKAN -DMINIUPNP_STATICLIB -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_CONCURRENT_LIB -DQT_MULTIMEDIA_LIB -DQT_MULTIMEDIAWIDGETS_LIB -DQT_SVG_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\SoundTouch\soundtouch\include" "-I.\..\3rdparty\cubeb\extra" "-I.\..\3rdparty\cubeb\cubeb\include" "-I.\..\3rdparty\flatbuffers\include" "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtMultimedia" "-I$(QTDIR)\include\QtMultimediaWidgets" "-I$(QTDIR)\include\QtSvg" + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWIN32_LEAN_AND_MEAN -DHAVE_VULKAN -DMINIUPNP_STATICLIB -DHAVE_SDL3 -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_CONCURRENT_LIB -DQT_MULTIMEDIA_LIB -DQT_MULTIMEDIAWIDGETS_LIB -DQT_SVG_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\SoundTouch\soundtouch\include" "-I.\..\3rdparty\cubeb\extra" "-I.\..\3rdparty\cubeb\cubeb\include" "-I.\..\3rdparty\flatbuffers\include" "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtMultimedia" "-I$(QTDIR)\include\QtMultimediaWidgets" "-I$(QTDIR)\include\QtSvg" $(QTDIR)\bin\moc.exe;%(FullPath) Moc%27ing %(Identity)... .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp @@ -1423,7 +1423,7 @@ $(QTDIR)\bin\moc.exe;%(FullPath) Moc%27ing %(Identity)... .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp - "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWIN32_LEAN_AND_MEAN -DHAVE_VULKAN -DMINIUPNP_STATICLIB -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_CONCURRENT_LIB -DQT_MULTIMEDIA_LIB -DQT_MULTIMEDIAWIDGETS_LIB -DQT_SVG_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\SoundTouch\soundtouch\include" "-I.\..\3rdparty\cubeb\extra" "-I.\..\3rdparty\cubeb\cubeb\include" "-I.\..\3rdparty\flatbuffers\include" "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtMultimedia" "-I$(QTDIR)\include\QtMultimediaWidgets" "-I$(QTDIR)\include\QtSvg" + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWIN32_LEAN_AND_MEAN -DHAVE_VULKAN -DMINIUPNP_STATICLIB -DHAVE_SDL3 -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_CONCURRENT_LIB -DQT_MULTIMEDIA_LIB -DQT_MULTIMEDIAWIDGETS_LIB -DQT_SVG_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\SoundTouch\soundtouch\include" "-I.\..\3rdparty\cubeb\extra" "-I.\..\3rdparty\cubeb\cubeb\include" "-I.\..\3rdparty\flatbuffers\include" "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtMultimedia" "-I$(QTDIR)\include\QtMultimediaWidgets" "-I$(QTDIR)\include\QtSvg" $(QTDIR)\bin\moc.exe;%(FullPath) Moc%27ing %(Identity)... .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp @@ -1433,7 +1433,7 @@ $(QTDIR)\bin\moc.exe;%(FullPath) Moc%27ing %(Identity)... .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp - "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWIN32_LEAN_AND_MEAN -DHAVE_VULKAN -DMINIUPNP_STATICLIB -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_CONCURRENT_LIB -DQT_MULTIMEDIA_LIB -DQT_MULTIMEDIAWIDGETS_LIB -DQT_SVG_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\SoundTouch\soundtouch\include" "-I.\..\3rdparty\cubeb\extra" "-I.\..\3rdparty\cubeb\cubeb\include" "-I.\..\3rdparty\flatbuffers\include" "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtMultimedia" "-I$(QTDIR)\include\QtMultimediaWidgets" "-I$(QTDIR)\include\QtSvg" + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWIN32_LEAN_AND_MEAN -DHAVE_VULKAN -DMINIUPNP_STATICLIB -DHAVE_SDL3 -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_CONCURRENT_LIB -DQT_MULTIMEDIA_LIB -DQT_MULTIMEDIAWIDGETS_LIB -DQT_SVG_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\SoundTouch\soundtouch\include" "-I.\..\3rdparty\cubeb\extra" "-I.\..\3rdparty\cubeb\cubeb\include" "-I.\..\3rdparty\flatbuffers\include" "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtMultimedia" "-I$(QTDIR)\include\QtMultimediaWidgets" "-I$(QTDIR)\include\QtSvg" $(QTDIR)\bin\moc.exe;%(FullPath) Moc%27ing %(Identity)... .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp @@ -1624,7 +1624,7 @@ $(QTDIR)\bin\moc.exe;%(FullPath) Moc%27ing %(Identity)... .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp - "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWIN32_LEAN_AND_MEAN -DHAVE_VULKAN -DMINIUPNP_STATICLIB -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_CONCURRENT_LIB -DQT_MULTIMEDIA_LIB -DQT_MULTIMEDIAWIDGETS_LIB -DQT_SVG_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\SoundTouch\soundtouch\include" "-I.\..\3rdparty\cubeb\extra" "-I.\..\3rdparty\cubeb\cubeb\include" "-I.\..\3rdparty\flatbuffers\include" "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtMultimedia" "-I$(QTDIR)\include\QtMultimediaWidgets" "-I$(QTDIR)\include\QtSvg" + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWIN32_LEAN_AND_MEAN -DHAVE_VULKAN -DMINIUPNP_STATICLIB -DHAVE_SDL3 -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_CONCURRENT_LIB -DQT_MULTIMEDIA_LIB -DQT_MULTIMEDIAWIDGETS_LIB -DQT_SVG_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\SoundTouch\soundtouch\include" "-I.\..\3rdparty\cubeb\extra" "-I.\..\3rdparty\cubeb\cubeb\include" "-I.\..\3rdparty\flatbuffers\include" "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtMultimedia" "-I$(QTDIR)\include\QtMultimediaWidgets" "-I$(QTDIR)\include\QtSvg" $(QTDIR)\bin\moc.exe;%(FullPath) Moc%27ing %(Identity)... .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp @@ -1717,7 +1717,7 @@ $(QTDIR)\bin\moc.exe;%(FullPath) Moc%27ing %(Identity)... .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp - "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWIN32_LEAN_AND_MEAN -DHAVE_VULKAN -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_CONCURRENT_LIB -DQT_MULTIMEDIA_LIB -DQT_MULTIMEDIAWIDGETS_LIB -DQT_SVG_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\SoundTouch\soundtouch\include" "-I.\..\3rdparty\cubeb\extra" "-I.\..\3rdparty\cubeb\cubeb\include" "-I.\..\3rdparty\flatbuffers\include" "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtMultimedia" "-I$(QTDIR)\include\QtMultimediaWidgets" "-I$(QTDIR)\include\QtSvg" + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWIN32_LEAN_AND_MEAN -DHAVE_VULKAN -DHAVE_SDL3 -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_CONCURRENT_LIB -DQT_MULTIMEDIA_LIB -DQT_MULTIMEDIAWIDGETS_LIB -DQT_SVG_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\SoundTouch\soundtouch\include" "-I.\..\3rdparty\cubeb\extra" "-I.\..\3rdparty\cubeb\cubeb\include" "-I.\..\3rdparty\flatbuffers\include" "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtMultimedia" "-I$(QTDIR)\include\QtMultimediaWidgets" "-I$(QTDIR)\include\QtSvg" $(QTDIR)\bin\moc.exe;%(FullPath) Moc%27ing %(Identity)... .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp @@ -1751,7 +1751,7 @@ $(QTDIR)\bin\moc.exe;%(FullPath) Moc%27ing %(Identity)... .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp - "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWIN32_LEAN_AND_MEAN -DHAVE_VULKAN -DMINIUPNP_STATICLIB -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_CONCURRENT_LIB -DQT_MULTIMEDIA_LIB -DQT_MULTIMEDIAWIDGETS_LIB -DQT_SVG_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\SoundTouch\soundtouch\include" "-I.\..\3rdparty\cubeb\extra" "-I.\..\3rdparty\cubeb\cubeb\include" "-I.\..\3rdparty\flatbuffers\include" "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtMultimedia" "-I$(QTDIR)\include\QtMultimediaWidgets" "-I$(QTDIR)\include\QtSvg" + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWIN32_LEAN_AND_MEAN -DHAVE_VULKAN -DMINIUPNP_STATICLIB -DHAVE_SDL3 -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_CONCURRENT_LIB -DQT_MULTIMEDIA_LIB -DQT_MULTIMEDIAWIDGETS_LIB -DQT_SVG_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\SoundTouch\soundtouch\include" "-I.\..\3rdparty\cubeb\extra" "-I.\..\3rdparty\cubeb\cubeb\include" "-I.\..\3rdparty\flatbuffers\include" "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtMultimedia" "-I$(QTDIR)\include\QtMultimediaWidgets" "-I$(QTDIR)\include\QtSvg" $(QTDIR)\bin\moc.exe;%(FullPath) Moc%27ing %(Identity)... .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp From 49729086ac3f53b2493781a4bb7bb8020a93c405 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Sun, 8 Jun 2025 21:21:51 +0300 Subject: [PATCH 02/37] vk: Move descriptor management to the pipeline layer - Frees up callers from managing descriptors themselves (ewww) - Makes descriptor reuse possible - Opens up the door to techniques like descriptor_buffer by abstracting away management to an implementation detail --- rpcs3/Emu/RSX/VK/VKCompute.cpp | 118 +++----- rpcs3/Emu/RSX/VK/VKCompute.h | 26 +- rpcs3/Emu/RSX/VK/VKDraw.cpp | 38 +-- rpcs3/Emu/RSX/VK/VKGSRender.cpp | 65 ++-- rpcs3/Emu/RSX/VK/VKGSRender.h | 7 - rpcs3/Emu/RSX/VK/VKGSRenderTypes.hpp | 3 - rpcs3/Emu/RSX/VK/VKOverlays.cpp | 212 +++++-------- rpcs3/Emu/RSX/VK/VKOverlays.h | 26 +- rpcs3/Emu/RSX/VK/VKPipelineCompiler.cpp | 63 ++-- rpcs3/Emu/RSX/VK/VKPipelineCompiler.h | 38 ++- rpcs3/Emu/RSX/VK/VKProgramBuffer.h | 9 +- rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp | 296 ++++++++++++++++--- rpcs3/Emu/RSX/VK/VKProgramPipeline.h | 134 +++++++-- rpcs3/Emu/RSX/VK/VKRenderTargets.h | 2 +- rpcs3/Emu/RSX/VK/VKResolveHelper.h | 74 +++-- rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp | 46 +-- rpcs3/Emu/RSX/VK/VKShaderInterpreter.h | 10 +- rpcs3/Emu/RSX/VK/upscalers/fsr1/fsr_pass.cpp | 46 ++- rpcs3/Emu/RSX/VK/upscalers/fsr_pass.h | 3 +- 19 files changed, 677 insertions(+), 539 deletions(-) diff --git a/rpcs3/Emu/RSX/VK/VKCompute.cpp b/rpcs3/Emu/RSX/VK/VKCompute.cpp index 637642d8bf..ae36723b81 100644 --- a/rpcs3/Emu/RSX/VK/VKCompute.cpp +++ b/rpcs3/Emu/RSX/VK/VKCompute.cpp @@ -8,64 +8,41 @@ namespace vk { - std::vector> compute_task::get_descriptor_layout() + std::vector compute_task::get_inputs() { - std::vector> result; - result.emplace_back(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, ssbo_count); + std::vector result; + for (unsigned i = 0; i < ssbo_count; ++i) + { + const auto input = glsl::program_input::make + ( + ::glsl::glsl_compute_program, + "ssbo" + std::to_string(i), + glsl::program_input_type::input_type_storage_buffer, + i + ); + result.push_back(input); + } + + if (use_push_constants && push_constants_size > 0) + { + const auto input = glsl::program_input::make + ( + ::glsl::glsl_compute_program, + "push_constants", + glsl::program_input_type::input_type_push_constant, + 0, + glsl::push_constant_ref{ .offset = 0, .size = push_constants_size } + ); + result.push_back(input); + } + return result; } - void compute_task::init_descriptors() - { - rsx::simple_array descriptor_pool_sizes; - rsx::simple_array bindings; - - const auto layout = get_descriptor_layout(); - for (const auto &e : layout) - { - descriptor_pool_sizes.push_back({e.first, e.second}); - - for (unsigned n = 0; n < e.second; ++n) - { - bindings.push_back - ({ - u32(bindings.size()), - e.first, - 1, - VK_SHADER_STAGE_COMPUTE_BIT, - nullptr - }); - } - } - - // Reserve descriptor pools - m_descriptor_pool.create(*g_render_device, descriptor_pool_sizes); - m_descriptor_layout = vk::descriptors::create_layout(bindings); - - VkPipelineLayoutCreateInfo layout_info = {}; - layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - layout_info.setLayoutCount = 1; - layout_info.pSetLayouts = &m_descriptor_layout; - - VkPushConstantRange push_constants{}; - if (use_push_constants) - { - push_constants.size = push_constants_size; - push_constants.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; - - layout_info.pushConstantRangeCount = 1; - layout_info.pPushConstantRanges = &push_constants; - } - - CHECK_RESULT(vkCreatePipelineLayout(*g_render_device, &layout_info, nullptr, &m_pipeline_layout)); - } - void compute_task::create() { if (!initialized) { - init_descriptors(); - switch (vk::get_driver_vendor()) { case vk::driver_vendor::unknown: @@ -121,10 +98,6 @@ namespace vk m_program.reset(); m_param_buffer.reset(); - vkDestroyDescriptorSetLayout(*g_render_device, m_descriptor_layout, nullptr); - vkDestroyPipelineLayout(*g_render_device, m_pipeline_layout, nullptr); - m_descriptor_pool.destroy(); - initialized = false; } } @@ -142,26 +115,23 @@ namespace vk shader_stage.module = handle; shader_stage.pName = "main"; - VkComputePipelineCreateInfo info{}; - info.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; - info.stage = shader_stage; - info.layout = m_pipeline_layout; - info.basePipelineIndex = -1; - info.basePipelineHandle = VK_NULL_HANDLE; + VkComputePipelineCreateInfo create_info + { + .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, + .stage = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .stage = VK_SHADER_STAGE_COMPUTE_BIT, + .module = handle, + .pName = "main" + }, + }; auto compiler = vk::get_pipe_compiler(); - m_program = compiler->compile(info, m_pipeline_layout, vk::pipe_compiler::COMPILE_INLINE); - declare_inputs(); + m_program = compiler->compile(create_info, vk::pipe_compiler::COMPILE_INLINE, {}, get_inputs()); } - ensure(m_used_descriptors < VK_MAX_COMPUTE_TASKS); - - m_descriptor_set = m_descriptor_pool.allocate(m_descriptor_layout, VK_TRUE); - bind_resources(); - - vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, m_program->pipeline); - m_descriptor_set.bind(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, m_pipeline_layout); + m_program->bind(cmd, VK_PIPELINE_BIND_POINT_COMPUTE); } void compute_task::run(const vk::command_buffer& cmd, u32 invocations_x, u32 invocations_y, u32 invocations_z) @@ -273,13 +243,13 @@ namespace vk void cs_shuffle_base::bind_resources() { - m_program->bind_buffer({ m_data->value, m_data_offset, m_data_length }, 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, m_descriptor_set); + m_program->bind_buffer({ m_data->value, m_data_offset, m_data_length }, 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); } void cs_shuffle_base::set_parameters(const vk::command_buffer& cmd, const u32* params, u8 count) { ensure(use_push_constants); - vkCmdPushConstants(cmd, m_pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, count * 4, params); + vkCmdPushConstants(cmd, m_program->layout(), VK_SHADER_STAGE_COMPUTE_BIT, 0, count * 4, params); } void cs_shuffle_base::run(const vk::command_buffer& cmd, const vk::buffer* data, u32 data_length, u32 data_offset) @@ -319,7 +289,7 @@ namespace vk void cs_interleave_task::bind_resources() { - m_program->bind_buffer({ m_data->value, m_data_offset, m_ssbo_length }, 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, m_descriptor_set); + m_program->bind_buffer({ m_data->value, m_data_offset, m_ssbo_length }, 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); } 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) @@ -379,8 +349,8 @@ namespace vk void cs_aggregator::bind_resources() { - m_program->bind_buffer({ src->value, 0, block_length }, 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, m_descriptor_set); - m_program->bind_buffer({ dst->value, 0, 4 }, 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, m_descriptor_set); + m_program->bind_buffer({ src->value, 0, block_length }, 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + m_program->bind_buffer({ dst->value, 0, 4 }, 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); } 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 4f9a3f2a3a..d4e99d8cf3 100644 --- a/rpcs3/Emu/RSX/VK/VKCompute.h +++ b/rpcs3/Emu/RSX/VK/VKCompute.h @@ -19,12 +19,6 @@ namespace vk std::unique_ptr m_program; std::unique_ptr m_param_buffer; - vk::descriptor_pool m_descriptor_pool; - descriptor_set m_descriptor_set; - VkDescriptorSetLayout m_descriptor_layout = nullptr; - VkPipelineLayout m_pipeline_layout = nullptr; - u32 m_used_descriptors = 0; - bool initialized = false; bool unroll_loops = true; bool use_push_constants = false; @@ -37,15 +31,11 @@ namespace vk compute_task() = default; virtual ~compute_task() { destroy(); } - virtual std::vector> get_descriptor_layout(); - - void init_descriptors(); - void create(); void destroy(); + virtual std::vector get_inputs(); virtual void bind_resources() {} - virtual void declare_inputs() {} void load_program(const vk::command_buffer& cmd); @@ -354,7 +344,7 @@ namespace vk void bind_resources() override { - m_program->bind_buffer({ m_data->value, m_data_offset, m_ssbo_length }, 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, m_descriptor_set); + m_program->bind_buffer({ m_data->value, m_data_offset, m_ssbo_length }, 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); } void run(const vk::command_buffer& cmd, const vk::buffer* data, u32 src_offset, u32 src_length, u32 dst_offset) @@ -455,13 +445,13 @@ namespace vk void bind_resources() override { - m_program->bind_buffer({ src_buffer->value, in_offset, block_length }, 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, m_descriptor_set); - m_program->bind_buffer({ dst_buffer->value, out_offset, block_length }, 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, m_descriptor_set); + m_program->bind_buffer({ src_buffer->value, in_offset, block_length }, 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + m_program->bind_buffer({ dst_buffer->value, out_offset, block_length }, 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); } void set_parameters(const vk::command_buffer& cmd) { - vkCmdPushConstants(cmd, m_pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, push_constants_size, params.data); + vkCmdPushConstants(cmd, m_program->layout(), VK_SHADER_STAGE_COMPUTE_BIT, 0, push_constants_size, params.data); } void run(const vk::command_buffer& cmd, const vk::buffer* dst, u32 out_offset, const vk::buffer* src, u32 in_offset, u32 data_length, u32 width, u32 height, u32 depth, u32 mipmaps) override @@ -584,13 +574,13 @@ namespace vk void bind_resources() override { const auto op = static_cast(Op); - m_program->bind_buffer({ src_buffer->value, in_offset, in_block_length }, 0 ^ op, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, m_descriptor_set); - m_program->bind_buffer({ dst_buffer->value, out_offset, out_block_length }, 1 ^ op, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, m_descriptor_set); + m_program->bind_buffer({ src_buffer->value, in_offset, in_block_length }, 0 ^ op, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + m_program->bind_buffer({ dst_buffer->value, out_offset, out_block_length }, 1 ^ op, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); } void set_parameters(const vk::command_buffer& cmd) { - vkCmdPushConstants(cmd, m_pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, push_constants_size, ¶ms); + vkCmdPushConstants(cmd, m_program->layout(), VK_SHADER_STAGE_COMPUTE_BIT, 0, push_constants_size, ¶ms); } void run(const vk::command_buffer& cmd, const RSX_detiler_config& config) diff --git a/rpcs3/Emu/RSX/VK/VKDraw.cpp b/rpcs3/Emu/RSX/VK/VKDraw.cpp index 3b760f103f..4d1253340d 100644 --- a/rpcs3/Emu/RSX/VK/VKDraw.cpp +++ b/rpcs3/Emu/RSX/VK/VKDraw.cpp @@ -555,8 +555,7 @@ bool VKGSRender::bind_texture_env() { m_program->bind_uniform({ fs_sampler_handles[i]->value, view->value, view->image()->current_layout }, i, - ::glsl::program_domain::glsl_fragment_program, - m_current_frame->descriptor_set); + ::glsl::program_domain::glsl_fragment_program); if (current_fragment_program.texture_state.redirected_textures & (1 << i)) { @@ -578,7 +577,6 @@ bool VKGSRender::bind_texture_env() m_program->bind_uniform({ m_stencil_mirror_sampler->value, stencil_view->value, stencil_view->image()->current_layout }, i, ::glsl::program_domain::glsl_fragment_program, - m_current_frame->descriptor_set, true); } } @@ -587,15 +585,13 @@ bool VKGSRender::bind_texture_env() const VkImageViewType view_type = vk::get_view_type(current_fragment_program.get_texture_dimension(i)); m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer, view_type)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, i, - ::glsl::program_domain::glsl_fragment_program, - m_current_frame->descriptor_set); + ::glsl::program_domain::glsl_fragment_program); if (current_fragment_program.texture_state.redirected_textures & (1 << i)) { m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer, view_type)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, i, ::glsl::program_domain::glsl_fragment_program, - m_current_frame->descriptor_set, true); } } @@ -611,8 +607,7 @@ bool VKGSRender::bind_texture_env() const auto view_type = vk::get_view_type(current_vertex_program.get_texture_dimension(i)); m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer, view_type)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, i, - ::glsl::program_domain::glsl_vertex_program, - m_current_frame->descriptor_set); + ::glsl::program_domain::glsl_vertex_program); continue; } @@ -635,8 +630,7 @@ bool VKGSRender::bind_texture_env() m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer, view_type)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, i, - ::glsl::program_domain::glsl_vertex_program, - m_current_frame->descriptor_set); + ::glsl::program_domain::glsl_vertex_program); continue; } @@ -645,8 +639,7 @@ bool VKGSRender::bind_texture_env() m_program->bind_uniform({ vs_sampler_handles[i]->value, image_ptr->value, image_ptr->image()->current_layout }, i, - ::glsl::program_domain::glsl_vertex_program, - m_current_frame->descriptor_set); + ::glsl::program_domain::glsl_vertex_program); } return out_of_memory; @@ -721,7 +714,7 @@ bool VKGSRender::bind_interpreter_texture_env() } } - m_shader_interpreter.update_fragment_textures(texture_env, m_current_frame->descriptor_set); + m_shader_interpreter.update_fragment_textures(texture_env); return out_of_memory; } @@ -850,6 +843,7 @@ void VKGSRender::emit_geometry(u32 sub_index) } else if (persistent_buffer != old_persistent_buffer || volatile_buffer != old_volatile_buffer) { + /* // Need to update descriptors; make a copy for the next draw VkDescriptorSet previous_set = m_current_frame->descriptor_set.value(); m_current_frame->descriptor_set.flush(); @@ -874,6 +868,8 @@ void VKGSRender::emit_geometry(u32 sub_index) m_current_frame->descriptor_set.push(copy_cmds); update_descriptors = true; + */ + fmt::throw_exception("Not implemented"); } // Update vertex fetch parameters @@ -882,9 +878,9 @@ void VKGSRender::emit_geometry(u32 sub_index) ensure(m_vertex_layout_storage); if (update_descriptors) { - m_program->bind_uniform(persistent_buffer, binding_table.vertex_buffers_first_bind_slot, m_current_frame->descriptor_set); - m_program->bind_uniform(volatile_buffer, binding_table.vertex_buffers_first_bind_slot + 1, m_current_frame->descriptor_set); - m_program->bind_uniform(m_vertex_layout_storage->value, binding_table.vertex_buffers_first_bind_slot + 2, m_current_frame->descriptor_set); + m_program->bind_uniform(persistent_buffer, binding_table.vertex_buffers_first_bind_slot); + m_program->bind_uniform(volatile_buffer, binding_table.vertex_buffers_first_bind_slot + 1); + m_program->bind_uniform(m_vertex_layout_storage->value, binding_table.vertex_buffers_first_bind_slot + 2); } bool reload_state = (!m_current_draw.subdraw_id++); @@ -908,10 +904,12 @@ void VKGSRender::emit_geometry(u32 sub_index) reload_state = true; }); + // Bind both pipe and descriptors in one go + // FIXME: We only need to rebind the pipeline when reload state is set. Flags? + m_program->bind(*m_current_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS); + if (reload_state) { - vkCmdBindPipeline(*m_current_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_program->pipeline); - update_draw_state(); begin_render_pass(); @@ -929,7 +927,6 @@ void VKGSRender::emit_geometry(u32 sub_index) } // Bind the new set of descriptors for use with this draw call - m_current_frame->descriptor_set.bind(*m_current_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_program->pipeline_layout); m_frame_stats.setup_time += m_profiler.duration(); if (!upload_info.index_info) @@ -1083,9 +1080,6 @@ void VKGSRender::end() return; } - // Allocate descriptor set - m_current_frame->descriptor_set = allocate_descriptor_set(); - // Load program execution environment load_program_env(); m_frame_stats.setup_time += m_profiler.duration(); diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index 107cd7b399..17f42f45e8 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -423,8 +423,8 @@ VKGSRender::VKGSRender(utils::serial* ar) noexcept : GSRender(ar) std::vector& gpus = m_instance.enumerate_devices(); - //Actually confirm that the loader found at least one compatible device - //This should not happen unless something is wrong with the driver setup on the target system + // Actually confirm that the loader found at least one compatible device + // This should not happen unless something is wrong with the driver setup on the target system if (gpus.empty()) { //We can't throw in Emulator::Load, so we show error and return @@ -482,20 +482,16 @@ VKGSRender::VKGSRender(utils::serial* ar) noexcept : GSRender(ar) swapchain_unavailable = true; } - //create command buffer... + // create command buffer... m_command_buffer_pool.create((*m_device), m_device->get_graphics_queue_family()); m_primary_cb_list.create(m_command_buffer_pool, vk::command_buffer::access_type_hint::flush_only); m_current_command_buffer = m_primary_cb_list.get(); m_current_command_buffer->begin(); - //Create secondary command_buffer for parallel operations + // Create secondary command_buffer for parallel operations m_secondary_command_buffer_pool.create((*m_device), m_device->get_graphics_queue_family()); m_secondary_cb_list.create(m_secondary_command_buffer_pool, vk::command_buffer::access_type_hint::all); - //Precalculated stuff - rsx::simple_array 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(*m_device, VK_QUERY_TYPE_OCCLUSION, OCCLUSION_MAX_POOL_SIZE); m_occlusion_map.resize(rsx::reports::occlusion_query_count); @@ -508,11 +504,6 @@ VKGSRender::VKGSRender(utils::serial* ar) noexcept : GSRender(ar) m_occlusion_query_manager->set_control_flags(VK_QUERY_CONTROL_PRECISE_BIT, 0); } - // Generate frame contexts - const u32 max_draw_calls = m_device->get_descriptor_max_draw_calls(); - 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 = {}; semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; @@ -852,12 +843,6 @@ VKGSRender::~VKGSRender() m_stencil_mirror_sampler.reset(); - // Pipeline descriptors - m_descriptor_pool.destroy(); - - vkDestroyPipelineLayout(*m_device, m_pipeline_layout, nullptr); - vkDestroyDescriptorSetLayout(*m_device, m_descriptor_layouts, nullptr); - // Queries m_occlusion_query_manager.reset(); m_cond_render_buffer.reset(); @@ -1157,18 +1142,6 @@ void VKGSRender::check_present_status() } } -VkDescriptorSet VKGSRender::allocate_descriptor_set() -{ - if (!m_shader_interpreter.is_interpreter(m_program)) [[likely]] - { - return m_descriptor_pool.allocate(m_descriptor_layouts, VK_TRUE); - } - else - { - return m_shader_interpreter.allocate_descriptor_set(); - } -} - void VKGSRender::set_viewport() { const auto [clip_width, clip_height] = rsx::apply_resolution_scale( @@ -1242,7 +1215,7 @@ void VKGSRender::on_init_thread() if (!m_overlay_manager) { m_frame->hide(); - m_shaders_cache->load(nullptr, m_pipeline_layout); + m_shaders_cache->load(nullptr); m_frame->show(); } else @@ -1250,7 +1223,7 @@ void VKGSRender::on_init_thread() rsx::shader_loading_dialog_native dlg(this); // TODO: Handle window resize messages during loading on GPUs without OUT_OF_DATE_KHR support - m_shaders_cache->load(&dlg, m_pipeline_layout); + m_shaders_cache->load(&dlg); } } @@ -1870,7 +1843,7 @@ bool VKGSRender::load_program() vertex_program, fragment_program, m_pipeline_properties, - shadermode != shader_mode::recompiler, true, m_pipeline_layout); + shadermode != shader_mode::recompiler, true); vk::leave_uninterruptible(); @@ -2103,32 +2076,32 @@ 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_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); + m_program->bind_uniform(m_vertex_env_buffer_info, binding_table.vertex_params_bind_slot); + m_program->bind_buffer(m_vertex_constants_buffer_info, binding_table.vertex_constant_buffers_bind_slot, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + m_program->bind_uniform(m_fragment_env_buffer_info, binding_table.fragment_state_bind_slot); + m_program->bind_uniform(m_fragment_texture_params_buffer_info, binding_table.fragment_texture_params_bind_slot); + m_program->bind_uniform(m_raster_env_buffer_info, binding_table.rasterizer_env_bind_slot); if (!m_shader_interpreter.is_interpreter(m_program)) { - m_program->bind_uniform(m_fragment_constants_buffer_info, binding_table.fragment_constant_buffers_bind_slot, m_current_frame->descriptor_set); + m_program->bind_uniform(m_fragment_constants_buffer_info, binding_table.fragment_constant_buffers_bind_slot); } else { - m_program->bind_buffer(m_vertex_instructions_buffer_info, m_shader_interpreter.get_vertex_instruction_location(), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, m_current_frame->descriptor_set); - m_program->bind_buffer(m_fragment_instructions_buffer_info, m_shader_interpreter.get_fragment_instruction_location(), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, m_current_frame->descriptor_set); + m_program->bind_buffer(m_vertex_instructions_buffer_info, m_shader_interpreter.get_vertex_instruction_location(), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + m_program->bind_buffer(m_fragment_instructions_buffer_info, m_shader_interpreter.get_fragment_instruction_location(), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); } if (vk::emulate_conditional_rendering()) { auto predicate = m_cond_render_buffer ? m_cond_render_buffer->value : vk::get_scratch_buffer(*m_current_command_buffer, 4)->value; - m_program->bind_buffer({ predicate, 0, 4 }, binding_table.conditional_render_predicate_slot, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, m_current_frame->descriptor_set); + m_program->bind_buffer({ predicate, 0, 4 }, binding_table.conditional_render_predicate_slot, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); } if (current_vertex_program.ctrl & RSX_SHADER_CONTROL_INSTANCED_CONSTANTS) { - m_program->bind_buffer(m_instancing_indirection_buffer_info, binding_table.instancing_lookup_table_bind_slot, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, m_current_frame->descriptor_set); - m_program->bind_buffer(m_instancing_constants_array_buffer_info, binding_table.instancing_constants_buffer_slot, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, m_current_frame->descriptor_set); + m_program->bind_buffer(m_instancing_indirection_buffer_info, binding_table.instancing_lookup_table_bind_slot, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + m_program->bind_buffer(m_instancing_constants_array_buffer_info, binding_table.instancing_constants_buffer_slot, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); } // Clear flags @@ -2215,7 +2188,7 @@ void VKGSRender::update_vertex_env(u32 id, const vk::vertex_upload_info& vertex_ vkCmdPushConstants( *m_current_command_buffer, - m_pipeline_layout, + m_program->layout(), VK_SHADER_STAGE_VERTEX_BIT, 0, data_length, diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.h b/rpcs3/Emu/RSX/VK/VKGSRender.h index e16d8d1afa..61dc496402 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.h +++ b/rpcs3/Emu/RSX/VK/VKGSRender.h @@ -105,11 +105,6 @@ private: vk::command_buffer_chunk* m_current_command_buffer = nullptr; std::unique_ptr m_host_object_data; - - vk::descriptor_pool m_descriptor_pool; - VkDescriptorSetLayout m_descriptor_layouts = VK_NULL_HANDLE; - VkPipelineLayout m_pipeline_layout = VK_NULL_HANDLE; - vk::framebuffer_holder* m_draw_fbo = nullptr; sizeu m_swapchain_dims{}; @@ -220,8 +215,6 @@ private: void update_draw_state(); void check_present_status(); - VkDescriptorSet allocate_descriptor_set(); - vk::vertex_upload_info upload_vertex_data(); rsx::simple_array m_scratch_mem; diff --git a/rpcs3/Emu/RSX/VK/VKGSRenderTypes.hpp b/rpcs3/Emu/RSX/VK/VKGSRenderTypes.hpp index acd4c42cb2..8f38378f52 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRenderTypes.hpp +++ b/rpcs3/Emu/RSX/VK/VKGSRenderTypes.hpp @@ -178,8 +178,6 @@ namespace vk VkSemaphore acquire_signal_semaphore = VK_NULL_HANDLE; VkSemaphore present_wait_semaphore = VK_NULL_HANDLE; - vk::descriptor_set descriptor_set; - rsx::flags32_t flags = 0; u32 present_image = -1; @@ -193,7 +191,6 @@ namespace vk { present_wait_semaphore = other.present_wait_semaphore; acquire_signal_semaphore = other.acquire_signal_semaphore; - descriptor_set.swap(other.descriptor_set); flags = other.flags; heap_snapshot = other.heap_snapshot; } diff --git a/rpcs3/Emu/RSX/VK/VKOverlays.cpp b/rpcs3/Emu/RSX/VK/VKOverlays.cpp index f4e7d092f9..5cd4761983 100644 --- a/rpcs3/Emu/RSX/VK/VKOverlays.cpp +++ b/rpcs3/Emu/RSX/VK/VKOverlays.cpp @@ -47,102 +47,38 @@ namespace vk } } - void overlay_pass::init_descriptors() - { - rsx::simple_array descriptor_pool_sizes = {}; - - if (m_num_uniform_buffers) - { - descriptor_pool_sizes.push_back({ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, m_num_uniform_buffers }); - }; - - if (m_num_usable_samplers) - { - descriptor_pool_sizes.push_back({ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, m_num_usable_samplers }); - } - - if (m_num_input_attachments) - { - descriptor_pool_sizes.push_back({ VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, m_num_input_attachments }); - } - - // Reserve descriptor pools - m_descriptor_pool.create(*m_device, descriptor_pool_sizes); - - const auto num_bindings = m_num_uniform_buffers + m_num_usable_samplers + m_num_input_attachments; - rsx::simple_array bindings(num_bindings); - u32 binding_slot = 0; - - for (u32 n = 0; n < m_num_uniform_buffers; ++n, ++binding_slot) - { - bindings[binding_slot].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - bindings[binding_slot].descriptorCount = 1; - bindings[binding_slot].stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; - bindings[binding_slot].binding = binding_slot; - bindings[binding_slot].pImmutableSamplers = nullptr; - } - - for (u32 n = 0; n < m_num_usable_samplers; ++n, ++binding_slot) - { - bindings[binding_slot].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - bindings[binding_slot].descriptorCount = 1; - bindings[binding_slot].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - bindings[binding_slot].binding = binding_slot; - bindings[binding_slot].pImmutableSamplers = nullptr; - } - - for (u32 n = 0; n < m_num_input_attachments; ++n, ++binding_slot) - { - bindings[binding_slot].descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT; - bindings[binding_slot].descriptorCount = 1; - bindings[binding_slot].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - bindings[binding_slot].binding = binding_slot; - bindings[binding_slot].pImmutableSamplers = nullptr; - } - - ensure(binding_slot == num_bindings); - m_descriptor_layout = vk::descriptors::create_layout(bindings); - - VkPipelineLayoutCreateInfo layout_info = {}; - layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - layout_info.setLayoutCount = 1; - layout_info.pSetLayouts = &m_descriptor_layout; - - std::vector push_constants = get_push_constants(); - if (!push_constants.empty()) - { - layout_info.pushConstantRangeCount = u32(push_constants.size()); - layout_info.pPushConstantRanges = push_constants.data(); - } - - CHECK_RESULT(vkCreatePipelineLayout(*m_device, &layout_info, nullptr, &m_pipeline_layout)); - } - std::vector overlay_pass::get_vertex_inputs() { check_heap(); - return{}; + return {}; } std::vector overlay_pass::get_fragment_inputs() { - std::vector fs_inputs; + using namespace vk::glsl; + + std::vector fs_inputs; u32 binding = 0; for (u32 n = 0; n < m_num_uniform_buffers; ++n, ++binding) { const std::string name = std::string("static_data") + (n > 0 ? std::to_string(n) : ""); - fs_inputs.push_back({ ::glsl::program_domain::glsl_fragment_program, vk::glsl::program_input_type::input_type_uniform_buffer,{},{}, 0, name }); + const auto input = program_input::make(::glsl::program_domain::glsl_fragment_program, name, program_input_type::input_type_uniform_buffer, 0); + fs_inputs.push_back(input); } for (u32 n = 0; n < m_num_usable_samplers; ++n, ++binding) { - fs_inputs.push_back({ ::glsl::program_domain::glsl_fragment_program, vk::glsl::program_input_type::input_type_texture,{},{}, binding, "fs" + std::to_string(n) }); + const std::string name = "fs" + std::to_string(n); + const auto input = program_input::make(::glsl::program_domain::glsl_fragment_program, name, program_input_type::input_type_texture, binding); + fs_inputs.push_back(input); } for (u32 n = 0; n < m_num_input_attachments; ++n, ++binding) { - fs_inputs.push_back({ ::glsl::program_domain::glsl_fragment_program, vk::glsl::program_input_type::input_type_texture,{},{}, binding, "sp" + std::to_string(n) }); + const std::string name = "sp" + std::to_string(n); + const auto input = program_input::make(::glsl::program_domain::glsl_fragment_program, name, program_input_type::input_type_texture, binding); + fs_inputs.push_back(input); } return fs_inputs; @@ -208,20 +144,20 @@ namespace vk info.stageCount = 2; info.pStages = shader_stages; info.pDynamicState = &dynamic_state_info; - info.layout = m_pipeline_layout; + info.layout = VK_NULL_HANDLE; info.basePipelineIndex = -1; info.basePipelineHandle = VK_NULL_HANDLE; info.renderPass = render_pass; auto compiler = vk::get_pipe_compiler(); - auto program = compiler->compile(info, m_pipeline_layout, vk::pipe_compiler::COMPILE_INLINE, {}, get_vertex_inputs(), get_fragment_inputs()); + auto program = compiler->compile(info, vk::pipe_compiler::COMPILE_INLINE, {}, get_vertex_inputs(), get_fragment_inputs()); auto result = program.get(); m_program_cache[storage_key] = std::move(program); return result; } - void overlay_pass::load_program(vk::command_buffer& cmd, VkRenderPass pass, const std::vector& src) + vk::glsl::program* overlay_pass::load_program(vk::command_buffer& cmd, VkRenderPass pass, const std::vector& src) { vk::glsl::program *program = nullptr; const auto key = get_pipeline_key(pass); @@ -232,8 +168,6 @@ namespace vk else program = build_pipeline(key, pass); - m_descriptor_set = m_descriptor_pool.allocate(m_descriptor_layout); - if (!m_sampler && !src.empty()) { m_sampler = std::make_unique(*m_device, @@ -245,21 +179,22 @@ 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, m_descriptor_set); + program->bind_uniform({ m_ubo.heap->value, m_ubo_offset, std::max(m_ubo_length, 4u) }, 0); } for (uint n = 0; n < src.size(); ++n) { VkDescriptorImageInfo info = { m_sampler->value, src[n]->value, src[n]->image()->current_layout }; - program->bind_uniform(info, "fs" + std::to_string(n), VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, m_descriptor_set); + program->bind_uniform(info, "fs" + std::to_string(n), VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER); } - vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, program->pipeline); - m_descriptor_set.bind(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout); + program->bind(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS); VkBuffer buffers = m_vao.heap->value; VkDeviceSize offsets = m_vao_offset; vkCmdBindVertexBuffers(cmd, 0, 1, &buffers, &offsets); + + return program; } void overlay_pass::create(const vk::render_device& dev) @@ -267,8 +202,6 @@ namespace vk if (!initialized) { m_device = &dev; - init_descriptors(); - initialized = true; } } @@ -282,10 +215,6 @@ namespace vk m_program_cache.clear(); m_sampler.reset(); - vkDestroyDescriptorSetLayout(*m_device, m_descriptor_layout, nullptr); - vkDestroyPipelineLayout(*m_device, m_pipeline_layout, nullptr); - m_descriptor_pool.destroy(); - initialized = false; } } @@ -303,7 +232,7 @@ namespace vk return vk::get_framebuffer(dev, target->width(), target->height(), m_num_input_attachments > 0, render_pass, { target }); } - void overlay_pass::emit_geometry(vk::command_buffer& cmd) + void overlay_pass::emit_geometry(vk::command_buffer& cmd, glsl::program* /*program*/) { vkCmdDraw(cmd, num_drawable_elements, 1, first_vertex, 0); } @@ -328,11 +257,11 @@ namespace vk // This call clobbers dynamic state cmd.flags |= vk::command_buffer::cb_reload_dynamic_state; - load_program(cmd, render_pass, src); + auto program = load_program(cmd, render_pass, src); set_up_viewport(cmd, viewport.x1, viewport.y1, viewport.width(), viewport.height()); vk::begin_renderpass(cmd, render_pass, fbo->value, { positionu{0u, 0u}, sizeu{fbo->width(), fbo->height()} }); - emit_geometry(cmd); + emit_geometry(cmd, program); } void overlay_pass::run(vk::command_buffer& cmd, const areau& viewport, vk::image* target, const std::vector& src, VkRenderPass render_pass) @@ -550,24 +479,37 @@ namespace vk false, true, desc->get_data(), owner_uid); } - std::vector ui_overlay_renderer::get_push_constants() + std::vector ui_overlay_renderer::get_vertex_inputs() { - return - { - { - .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, - .offset = 0, - .size = 68 - }, - { - .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, - .offset = 68, - .size = 12 - } - }; + auto result = overlay_pass::get_vertex_inputs(); + result.push_back( + glsl::program_input::make( + ::glsl::glsl_vertex_program, + "push_constants", + glsl::input_type_push_constant, + 0, + glsl::push_constant_ref { .size = 68 } + ) + ); + return result; } - void ui_overlay_renderer::update_uniforms(vk::command_buffer& cmd, vk::glsl::program* /*program*/) + std::vector ui_overlay_renderer::get_fragment_inputs() + { + auto result = overlay_pass::get_fragment_inputs(); + result.push_back( + glsl::program_input::make( + ::glsl::glsl_fragment_program, + "push_constants", + glsl::input_type_push_constant, + 0, + glsl::push_constant_ref {.offset = 68, .size = 12 } + ) + ); + return result; + } + + void ui_overlay_renderer::update_uniforms(vk::command_buffer& cmd, vk::glsl::program* program) { // Byte Layout // 00: vec4 ui_scale; @@ -600,7 +542,7 @@ namespace vk .get(); push_buf[16] = std::bit_cast(vert_config); - vkCmdPushConstants(cmd, m_pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT, 0, 68, push_buf); + vkCmdPushConstants(cmd, program->layout(), VK_SHADER_STAGE_VERTEX_BIT, 0, 68, push_buf); // 2. Fragment stuff rsx::overlays::fragment_options frag_opts; @@ -614,7 +556,7 @@ namespace vk push_buf[1] = m_time; push_buf[2] = m_blur_strength; - vkCmdPushConstants(cmd, m_pipeline_layout, VK_SHADER_STAGE_FRAGMENT_BIT, 68, 12, push_buf); + vkCmdPushConstants(cmd, program->layout(), VK_SHADER_STAGE_FRAGMENT_BIT, 68, 12, push_buf); } void ui_overlay_renderer::set_primitive_type(rsx::overlays::primitive_type type) @@ -641,7 +583,7 @@ namespace vk } } - void ui_overlay_renderer::emit_geometry(vk::command_buffer& cmd) + void ui_overlay_renderer::emit_geometry(vk::command_buffer& cmd, glsl::program* program) { if (m_current_primitive_type == rsx::overlays::primitive_type::quad_list) { @@ -657,7 +599,7 @@ namespace vk } else { - overlay_pass::emit_geometry(cmd); + overlay_pass::emit_geometry(cmd, program); } } @@ -764,17 +706,20 @@ namespace vk renderpass_config.set_attachment_count(1); } - std::vector attachment_clear_pass::get_push_constants() + std::vector attachment_clear_pass::get_vertex_inputs() { - VkPushConstantRange constant; - constant.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - constant.offset = 0; - constant.size = 32; - - return { constant }; + return + { + vk::glsl::program_input::make( + ::glsl::glsl_vertex_program, + "push_constants", + vk::glsl::input_type_push_constant, + 0, + glsl::push_constant_ref{ .size = 32 }) + }; } - void attachment_clear_pass::update_uniforms(vk::command_buffer& cmd, vk::glsl::program* /*program*/) + void attachment_clear_pass::update_uniforms(vk::command_buffer& cmd, vk::glsl::program* program) { f32 data[8]; data[0] = clear_color.r; @@ -786,7 +731,7 @@ namespace vk data[6] = colormask.b; data[7] = colormask.a; - vkCmdPushConstants(cmd, m_pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT, 0, 32, data); + vkCmdPushConstants(cmd, program->layout(), VK_SHADER_STAGE_VERTEX_BIT, 0, 32, data); } void attachment_clear_pass::set_up_viewport(vk::command_buffer& cmd, u32 x, u32 y, u32 w, u32 h) @@ -910,19 +855,24 @@ namespace vk m_num_usable_samplers = 2; } - std::vector video_out_calibration_pass::get_push_constants() + std::vector video_out_calibration_pass::get_fragment_inputs() { - VkPushConstantRange constant; - constant.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - constant.offset = 0; - constant.size = 16; - - return { constant }; + auto result = overlay_pass::get_fragment_inputs(); + result.push_back( + vk::glsl::program_input::make( + ::glsl::glsl_fragment_program, + "push_constants", + vk::glsl::input_type_push_constant, + 0, + glsl::push_constant_ref{ .size = 16 } + ) + ); + return result; } - void video_out_calibration_pass::update_uniforms(vk::command_buffer& cmd, vk::glsl::program* /*program*/) + void video_out_calibration_pass::update_uniforms(vk::command_buffer& cmd, vk::glsl::program* program) { - vkCmdPushConstants(cmd, m_pipeline_layout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, 16, config.data); + vkCmdPushConstants(cmd, program->layout(), VK_SHADER_STAGE_FRAGMENT_BIT, 0, 16, config.data); } void video_out_calibration_pass::run(vk::command_buffer& cmd, const areau& viewport, vk::framebuffer* target, diff --git a/rpcs3/Emu/RSX/VK/VKOverlays.h b/rpcs3/Emu/RSX/VK/VKOverlays.h index 7308a5c894..a968f706a1 100644 --- a/rpcs3/Emu/RSX/VK/VKOverlays.h +++ b/rpcs3/Emu/RSX/VK/VKOverlays.h @@ -44,11 +44,6 @@ namespace vk vk::glsl::shader m_vertex_shader; vk::glsl::shader m_fragment_shader; - vk::descriptor_pool m_descriptor_pool; - descriptor_set m_descriptor_set; - VkDescriptorSetLayout m_descriptor_layout = nullptr; - VkPipelineLayout m_pipeline_layout = nullptr; - VkFilter m_sampler_filter = VK_FILTER_LINEAR; u32 m_num_usable_samplers = 1; u32 m_num_input_attachments = 0; @@ -83,8 +78,6 @@ namespace vk void check_heap(); - void init_descriptors(); - virtual void update_uniforms(vk::command_buffer& /*cmd*/, vk::glsl::program* /*program*/) {} virtual std::vector get_vertex_inputs(); @@ -92,11 +85,6 @@ namespace vk virtual void get_dynamic_state_entries(std::vector& /*state_descriptors*/) {} - virtual std::vector get_push_constants() - { - return {}; - } - int sampler_location(int index) const { return 1 + index; } int input_attachment_location(int index) const { return 1 + m_num_usable_samplers + index; } @@ -113,8 +101,7 @@ namespace vk } vk::glsl::program* build_pipeline(u64 storage_key, VkRenderPass render_pass); - - void load_program(vk::command_buffer& cmd, VkRenderPass pass, const std::vector& src); + vk::glsl::program* load_program(vk::command_buffer& cmd, VkRenderPass pass, const std::vector& src); virtual void create(const vk::render_device& dev); virtual void destroy(); @@ -123,7 +110,7 @@ namespace vk vk::framebuffer* get_framebuffer(vk::image* target, VkRenderPass render_pass); - virtual void emit_geometry(vk::command_buffer& cmd); + virtual void emit_geometry(vk::command_buffer& cmd, glsl::program* program); virtual void set_up_viewport(vk::command_buffer& cmd, u32 x, u32 y, u32 w, u32 h); @@ -169,13 +156,14 @@ namespace vk 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_base* desc, vk::command_buffer& cmd, vk::data_heap& upload_heap, u32 owner_uid); - std::vector get_push_constants() override; + std::vector get_vertex_inputs() override; + std::vector get_fragment_inputs() override; void update_uniforms(vk::command_buffer& cmd, vk::glsl::program* program) override; void set_primitive_type(rsx::overlays::primitive_type type); - void emit_geometry(vk::command_buffer& cmd) override; + void emit_geometry(vk::command_buffer& cmd, glsl::program* program) override; void run(vk::command_buffer& cmd, const areau& viewport, vk::framebuffer* target, VkRenderPass render_pass, vk::data_heap& upload_heap, rsx::overlays::overlay& ui); @@ -189,7 +177,7 @@ namespace vk attachment_clear_pass(); - std::vector get_push_constants() override; + std::vector get_vertex_inputs() override; void update_uniforms(vk::command_buffer& cmd, vk::glsl::program* program) override; @@ -227,7 +215,7 @@ namespace vk video_out_calibration_pass(); - std::vector get_push_constants() override; + std::vector get_fragment_inputs() override; void update_uniforms(vk::command_buffer& cmd, vk::glsl::program* /*program*/) override; diff --git a/rpcs3/Emu/RSX/VK/VKPipelineCompiler.cpp b/rpcs3/Emu/RSX/VK/VKPipelineCompiler.cpp index 52742e1241..13c16513d3 100644 --- a/rpcs3/Emu/RSX/VK/VKPipelineCompiler.cpp +++ b/rpcs3/Emu/RSX/VK/VKPipelineCompiler.cpp @@ -36,12 +36,12 @@ namespace vk { if (job.is_graphics_job) { - auto compiled = int_compile_graphics_pipe(job.graphics_data, job.graphics_modules, job.pipe_layout, job.inputs, {}); + auto compiled = int_compile_graphics_pipe(job.graphics_data, job.graphics_modules, job.inputs, {}); job.callback_func(compiled); } else { - auto compiled = int_compile_compute_pipe(job.compute_data, job.pipe_layout); + auto compiled = int_compile_compute_pipe(job.compute_data, job.inputs); job.callback_func(compiled); } } @@ -50,25 +50,26 @@ namespace vk } } - std::unique_ptr pipe_compiler::int_compile_compute_pipe(const VkComputePipelineCreateInfo& create_info, VkPipelineLayout pipe_layout) + std::unique_ptr pipe_compiler::int_compile_compute_pipe( + const VkComputePipelineCreateInfo& create_info, + const std::vector& cs_inputs) { - VkPipeline pipeline; - vkCreateComputePipelines(*g_render_device, nullptr, 1, &create_info, nullptr, &pipeline); - return std::make_unique(*m_device, pipeline, pipe_layout); + return std::make_unique(*m_device, create_info, cs_inputs); } - std::unique_ptr pipe_compiler::int_compile_graphics_pipe(const VkGraphicsPipelineCreateInfo& create_info, VkPipelineLayout pipe_layout, - const std::vector& vs_inputs, const std::vector& fs_inputs) + std::unique_ptr pipe_compiler::int_compile_graphics_pipe( + const VkGraphicsPipelineCreateInfo& create_info, + const std::vector& vs_inputs, + const std::vector& fs_inputs) { - VkPipeline pipeline; - CHECK_RESULT(vkCreateGraphicsPipelines(*m_device, VK_NULL_HANDLE, 1, &create_info, nullptr, &pipeline)); - auto result = std::make_unique(*m_device, pipeline, pipe_layout, vs_inputs, fs_inputs); - result->link(); - return result; + return std::make_unique(*m_device, create_info, vs_inputs, fs_inputs); } - std::unique_ptr pipe_compiler::int_compile_graphics_pipe(const vk::pipeline_props &create_info, VkShaderModule modules[2], VkPipelineLayout pipe_layout, - const std::vector& vs_inputs, const std::vector& fs_inputs) + std::unique_ptr pipe_compiler::int_compile_graphics_pipe( + const vk::pipeline_props &create_info, + VkShaderModule modules[2], + const std::vector& vs_inputs, + const std::vector& fs_inputs) { VkPipelineShaderStageCreateInfo shader_stages[2] = {}; shader_stages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; @@ -157,52 +158,54 @@ namespace vk info.stageCount = 2; info.pStages = shader_stages; info.pDynamicState = &dynamic_state_info; - info.layout = pipe_layout; + info.layout = VK_NULL_HANDLE; info.basePipelineIndex = -1; info.basePipelineHandle = VK_NULL_HANDLE; info.renderPass = vk::get_renderpass(*m_device, create_info.renderpass_key); - return int_compile_graphics_pipe(info, pipe_layout, vs_inputs, fs_inputs); + return int_compile_graphics_pipe(info, vs_inputs, fs_inputs); } std::unique_ptr pipe_compiler::compile( const VkComputePipelineCreateInfo& create_info, - VkPipelineLayout pipe_layout, - op_flags flags, callback_t callback) + op_flags flags, callback_t callback, + const std::vector& cs_inputs) { if (flags == COMPILE_INLINE) { - return int_compile_compute_pipe(create_info, pipe_layout); + return int_compile_compute_pipe(create_info, cs_inputs); } - m_work_queue.push(create_info, pipe_layout, callback); + m_work_queue.push(create_info, cs_inputs, callback); return {}; } std::unique_ptr pipe_compiler::compile( const VkGraphicsPipelineCreateInfo& create_info, - VkPipelineLayout pipe_layout, op_flags flags, callback_t /*callback*/, - const std::vector& vs_inputs, const std::vector& fs_inputs) + const std::vector& vs_inputs, + const std::vector& fs_inputs) { // It is very inefficient to defer this as all pointers need to be saved ensure(flags == COMPILE_INLINE); - return int_compile_graphics_pipe(create_info, pipe_layout, vs_inputs, fs_inputs); + return int_compile_graphics_pipe(create_info, vs_inputs, fs_inputs); } std::unique_ptr pipe_compiler::compile( - const vk::pipeline_props& create_info, - VkShaderModule module_handles[2], - VkPipelineLayout pipe_layout, + const vk::pipeline_props &create_info, + VkShaderModule vs, + VkShaderModule fs, op_flags flags, callback_t callback, - const std::vector& vs_inputs, const std::vector& fs_inputs) + const std::vector& vs_inputs, + const std::vector& fs_inputs) { + VkShaderModule modules[] = { vs, fs }; if (flags == COMPILE_INLINE) { - return int_compile_graphics_pipe(create_info, module_handles, pipe_layout, vs_inputs, fs_inputs); + return int_compile_graphics_pipe(create_info, modules, vs_inputs, fs_inputs); } - m_work_queue.push(create_info, pipe_layout, module_handles, vs_inputs, fs_inputs, callback); + m_work_queue.push(create_info, modules, vs_inputs, fs_inputs, callback); return {}; } diff --git a/rpcs3/Emu/RSX/VK/VKPipelineCompiler.h b/rpcs3/Emu/RSX/VK/VKPipelineCompiler.h index 836bc5f14f..a915595e62 100644 --- a/rpcs3/Emu/RSX/VK/VKPipelineCompiler.h +++ b/rpcs3/Emu/RSX/VK/VKPipelineCompiler.h @@ -68,21 +68,20 @@ namespace vk void initialize(const vk::render_device* pdev); std::unique_ptr compile( - const VkComputePipelineCreateInfo& create_info, - VkPipelineLayout pipe_layout, - op_flags flags, callback_t callback = {}); + const VkComputePipelineCreateInfo& cs, + op_flags flags, callback_t callback = {}, + const std::vector& cs_inputs = {}); std::unique_ptr compile( const VkGraphicsPipelineCreateInfo& create_info, - VkPipelineLayout pipe_layout, op_flags flags, callback_t callback = {}, const std::vector& vs_inputs = {}, const std::vector& fs_inputs = {}); std::unique_ptr compile( const vk::pipeline_props &create_info, - VkShaderModule module_handles[2], - VkPipelineLayout pipe_layout, + VkShaderModule vs, + VkShaderModule fs, op_flags flags, callback_t callback = {}, const std::vector& vs_inputs = {}, const std::vector& fs_inputs = {}); @@ -112,13 +111,11 @@ namespace vk vk::pipeline_props graphics_data; compute_pipeline_props compute_data; - VkPipelineLayout pipe_layout; VkShaderModule graphics_modules[2]; std::vector inputs; pipe_compiler_job( const vk::pipeline_props& props, - VkPipelineLayout layout, VkShaderModule modules[2], const std::vector& vs_in, const std::vector& fs_in, @@ -126,7 +123,6 @@ namespace vk { callback_func = func; graphics_data = props; - pipe_layout = layout; graphics_modules[0] = modules[0]; graphics_modules[1] = modules[1]; is_graphics_job = true; @@ -138,24 +134,34 @@ namespace vk pipe_compiler_job( const VkComputePipelineCreateInfo& props, - VkPipelineLayout layout, + const std::vector& cs_in, callback_t func) { callback_func = func; compute_data = props; - pipe_layout = layout; is_graphics_job = false; + + inputs = cs_in; } }; const vk::render_device* m_device = nullptr; lf_queue m_work_queue; - std::unique_ptr int_compile_compute_pipe(const VkComputePipelineCreateInfo& create_info, VkPipelineLayout pipe_layout); - std::unique_ptr int_compile_graphics_pipe(const VkGraphicsPipelineCreateInfo& create_info, VkPipelineLayout pipe_layout, - const std::vector& vs_inputs, const std::vector& fs_inputs); - std::unique_ptr int_compile_graphics_pipe(const vk::pipeline_props &create_info, VkShaderModule modules[2], VkPipelineLayout pipe_layout, - const std::vector& vs_inputs, const std::vector& fs_inputs); + std::unique_ptr int_compile_compute_pipe( + const VkComputePipelineCreateInfo& create_info, + const std::vector& cs_inputs); + + std::unique_ptr int_compile_graphics_pipe( + const VkGraphicsPipelineCreateInfo& create_info, + const std::vector& vs_inputs, + const std::vector& fs_inputs); + + std::unique_ptr int_compile_graphics_pipe( + const vk::pipeline_props &create_info, + VkShaderModule modules[2], + const std::vector& vs_inputs, + const std::vector& fs_inputs); }; void initialize_pipe_compiler(int num_worker_threads = -1); diff --git a/rpcs3/Emu/RSX/VK/VKProgramBuffer.h b/rpcs3/Emu/RSX/VK/VKProgramBuffer.h index 4f9f535a76..647b21adc4 100644 --- a/rpcs3/Emu/RSX/VK/VKProgramBuffer.h +++ b/rpcs3/Emu/RSX/VK/VKProgramBuffer.h @@ -46,15 +46,14 @@ namespace vk const fragment_program_type& fragmentProgramData, const vk::pipeline_props& pipelineProperties, bool compile_async, - std::function callback, - VkPipelineLayout common_pipeline_layout) + std::function callback) { const auto compiler_flags = compile_async ? vk::pipe_compiler::COMPILE_DEFERRED : vk::pipe_compiler::COMPILE_INLINE; - VkShaderModule modules[2] = { vertexProgramData.handle, fragmentProgramData.handle }; - auto compiler = vk::get_pipe_compiler(); auto result = compiler->compile( - pipelineProperties, modules, common_pipeline_layout, + pipelineProperties, + vertexProgramData.handle, + fragmentProgramData.handle, compiler_flags, callback, vertexProgramData.uniforms, fragmentProgramData.uniforms); diff --git a/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp b/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp index 57174caa98..34bb4d1331 100644 --- a/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp +++ b/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp @@ -1,5 +1,6 @@ #include "stdafx.h" #include "VKProgramPipeline.h" +#include "VKResourceManager.h" #include "vkutils/descriptors.h" #include "vkutils/device.h" @@ -7,10 +8,61 @@ namespace vk { + extern vk::render_device* get_current_renderer(); + namespace glsl { using namespace ::glsl; + VkDescriptorType to_descriptor_type(program_input_type type) + { + switch (type) + { + case input_type_uniform_buffer: + return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + case input_type_texel_buffer: + return VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; + case input_type_texture: + return VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + case input_type_storage_buffer: + return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + case input_type_storage_texture: + return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + default: + fmt::throw_exception("Unexpected program input type %d", static_cast(type)); + } + } + + VkShaderStageFlags to_shader_stage_flags(::glsl::program_domain domain) + { + switch (domain) + { + case glsl_vertex_program: + return VK_SHADER_STAGE_VERTEX_BIT; + case glsl_fragment_program: + return VK_SHADER_STAGE_FRAGMENT_BIT; + case glsl_compute_program: + return VK_SHADER_STAGE_COMPUTE_BIT; + default: + fmt::throw_exception("Unexpected domain %d", static_cast(domain)); + } + } + + const char* to_string(::glsl::program_domain domain) + { + switch (domain) + { + case glsl_vertex_program: + return "vertex"; + case glsl_fragment_program: + return "fragment"; + case glsl_compute_program: + return "compute"; + default: + fmt::throw_exception("Unexpected domain %d", static_cast(domain)); + } + } + void shader::create(::glsl::program_domain domain, const std::string& source) { type = domain; @@ -23,11 +75,8 @@ namespace vk if (!spirv::compile_glsl_to_spv(m_compiled, m_source, type, ::glsl::glsl_rules_vulkan)) { - const std::string shader_type = type == ::glsl::program_domain::glsl_vertex_program ? "vertex" : - type == ::glsl::program_domain::glsl_fragment_program ? "fragment" : "compute"; - rsx_log.notice("%s", m_source); - fmt::throw_exception("Failed to compile %s shader", shader_type); + fmt::throw_exception("Failed to compile %s shader", to_string(type)); } VkShaderModuleCreateInfo vs_info; @@ -69,34 +118,56 @@ namespace vk return m_handle; } - void program::create_impl() + void program::init() { linked = false; - attribute_location_mask = 0; - vertex_attributes_mask = 0; fs_texture_bindings.fill(~0u); fs_texture_mirror_bindings.fill(~0u); vs_texture_bindings.fill(~0u); } - program::program(VkDevice dev, VkPipeline p, VkPipelineLayout layout, const std::vector &vertex_input, const std::vector& fragment_inputs) - : m_device(dev), pipeline(p), pipeline_layout(layout) + program::program(VkDevice dev, const VkGraphicsPipelineCreateInfo& create_info, const std::vector &vertex_inputs, const std::vector& fragment_inputs) + : m_device(dev) { - create_impl(); - load_uniforms(vertex_input); + init(); + + load_uniforms(vertex_inputs); load_uniforms(fragment_inputs); + + create_pipeline_layout(); + ensure(m_pipeline_layout); + + auto _create_info = create_info; + _create_info.layout = m_pipeline_layout; + CHECK_RESULT(vkCreateGraphicsPipelines(dev, nullptr, 1, &create_info, nullptr, &m_pipeline)); } - program::program(VkDevice dev, VkPipeline p, VkPipelineLayout layout) - : m_device(dev), pipeline(p), pipeline_layout(layout) + program::program(VkDevice dev, const VkComputePipelineCreateInfo& create_info, const std::vector& compute_inputs) + : m_device(dev) { - create_impl(); + init(); + + load_uniforms(compute_inputs); + + create_pipeline_layout(); + ensure(m_pipeline_layout); + + auto _create_info = create_info; + _create_info.layout = m_pipeline_layout; + CHECK_RESULT(vkCreateComputePipelines(dev, nullptr, 1, &create_info, nullptr, &m_pipeline)); } program::~program() { - vkDestroyPipeline(m_device, pipeline, nullptr); + vkDestroyPipeline(m_device, m_pipeline, nullptr); + + if (m_pipeline_layout) + { + vkDestroyPipelineLayout(m_device, m_pipeline_layout, nullptr); + vkDestroyDescriptorSetLayout(m_device, m_descriptor_set_layout, nullptr); + vk::get_resource_manager()->dispose(m_descriptor_pool); + } } program& program::load_uniforms(const std::vector& inputs) @@ -160,14 +231,36 @@ namespace vk }); } - void program::bind_uniform(const VkDescriptorImageInfo &image_descriptor, const std::string& uniform_name, VkDescriptorType type, vk::descriptor_set &set) + u32 program::get_uniform_location(program_input_type type, const std::string& uniform_name) + { + const auto& uniform = uniforms[type]; + const auto result = std::find_if(uniform.cbegin(), uniform.cend(), [&uniform_name](const auto& u) + { + return u.name == uniform_name; + }); + + if (result == uniform.end()) + { + return { umax }; + } + + return result->location; + } + + void program::bind_uniform(const VkDescriptorImageInfo &image_descriptor, const std::string& uniform_name, VkDescriptorType type) { for (const auto &uniform : uniforms[program_input_type::input_type_texture]) { if (uniform.name == uniform_name) { - set.push(image_descriptor, type, uniform.location); - attribute_location_mask |= (1ull << uniform.location); + if (m_descriptor_slots[uniform.location].matches(image_descriptor)) + { + return; + } + + next_descriptor_set(); + m_descriptor_set.push(image_descriptor, type, uniform.location); + m_descriptors_dirty[uniform.location] = false; return; } } @@ -175,7 +268,7 @@ namespace vk rsx_log.notice("texture not found in program: %s", uniform_name.c_str()); } - void program::bind_uniform(const VkDescriptorImageInfo & image_descriptor, int texture_unit, ::glsl::program_domain domain, vk::descriptor_set &set, bool is_stencil_mirror) + void program::bind_uniform(const VkDescriptorImageInfo & image_descriptor, int texture_unit, ::glsl::program_domain domain, bool is_stencil_mirror) { ensure(domain != ::glsl::program_domain::glsl_compute_program); @@ -189,34 +282,46 @@ namespace vk binding = vs_texture_bindings[texture_unit]; } - if (binding != ~0u) + if (binding == ~0u) [[ unlikely ]] { - set.push(image_descriptor, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, binding); - attribute_location_mask |= (1ull << binding); + rsx_log.notice("texture not found in program: %stex%u", (domain == ::glsl::program_domain::glsl_vertex_program) ? "v" : "", texture_unit); return; } - rsx_log.notice("texture not found in program: %stex%u", (domain == ::glsl::program_domain::glsl_vertex_program)? "v" : "", texture_unit); + if (m_descriptor_slots[binding].matches(image_descriptor)) + { + return; + } + + next_descriptor_set(); + m_descriptor_set.push(image_descriptor, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, binding); + m_descriptors_dirty[binding] = false; } - void program::bind_uniform(const VkDescriptorBufferInfo &buffer_descriptor, u32 binding_point, vk::descriptor_set &set) + void program::bind_uniform(const VkDescriptorBufferInfo &buffer_descriptor, u32 binding_point) { - bind_buffer(buffer_descriptor, binding_point, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, set); + bind_buffer(buffer_descriptor, binding_point, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER); } - void program::bind_uniform(const VkBufferView &buffer_view, u32 binding_point, vk::descriptor_set &set) + void program::bind_uniform(const VkBufferView &buffer_view, u32 binding_point) { - set.push(buffer_view, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, binding_point); - attribute_location_mask |= (1ull << binding_point); + if (m_descriptor_slots[binding_point].matches(buffer_view)) + { + return; + } + + next_descriptor_set(); + m_descriptor_set.push(buffer_view, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, binding_point); + m_descriptors_dirty[binding_point] = false; } - void program::bind_uniform(const VkBufferView &buffer_view, program_input_type type, const std::string &binding_name, vk::descriptor_set &set) + void program::bind_uniform(const VkBufferView &buffer_view, program_input_type type, const std::string &binding_name) { for (const auto &uniform : uniforms[type]) { if (uniform.name == binding_name) { - bind_uniform(buffer_view, uniform.location, set); + bind_uniform(buffer_view, uniform.location); return; } } @@ -224,10 +329,135 @@ namespace vk rsx_log.notice("vertex buffer not found in program: %s", binding_name.c_str()); } - void program::bind_buffer(const VkDescriptorBufferInfo &buffer_descriptor, u32 binding_point, VkDescriptorType type, vk::descriptor_set &set) + void program::bind_buffer(const VkDescriptorBufferInfo &buffer_descriptor, u32 binding_point, VkDescriptorType type) { - set.push(buffer_descriptor, type, binding_point); - attribute_location_mask |= (1ull << binding_point); + m_descriptor_set.push(buffer_descriptor, type, binding_point); + m_descriptors_dirty[binding_point] = false; + } + + VkDescriptorSet program::allocate_descriptor_set() + { + if (!m_descriptor_pool) + { + create_descriptor_pool(); + } + + return m_descriptor_pool->allocate(m_descriptor_set_layout); + } + + void program::next_descriptor_set() + { + const auto new_set = allocate_descriptor_set(); + const auto old_set = m_descriptor_set.value(); + + if (old_set) + { + m_copy_cmds.clear(); + for (unsigned i = 0; i < m_copy_cmds.size(); ++i) + { + if (!m_descriptors_dirty[i]) + { + continue; + } + + // Reuse already initialized memory. Each command is the same anyway. + m_copy_cmds.resize(m_copy_cmds.size() + 1); + auto& cmd = m_copy_cmds.back(); + cmd.srcBinding = cmd.dstBinding = i; + cmd.srcSet = old_set; + cmd.dstSet = new_set; + } + + m_descriptor_set.push(m_copy_cmds); + } + + m_descriptor_set = allocate_descriptor_set(); + } + + program& program::bind(const vk::command_buffer& cmd, VkPipelineBindPoint bind_point) + { + VkDescriptorSet set = m_descriptor_set.value(); + vkCmdBindPipeline(cmd, bind_point, m_pipeline); + vkCmdBindDescriptorSets(cmd, bind_point, m_pipeline_layout, 0, 1, &set, 0, nullptr); + return *this; + } + + void program::create_descriptor_set_layout() + { + ensure(m_descriptor_set_layout == VK_NULL_HANDLE); + + rsx::simple_array bindings; + bindings.reserve(16); + + m_descriptor_pool_sizes.clear(); + m_descriptor_pool_sizes.reserve(input_type_max_enum); + + for (const auto& type_arr : uniforms) + { + if (type_arr.empty() || type_arr.front().type == input_type_push_constant) + { + continue; + } + + VkDescriptorType type = to_descriptor_type(type_arr.front().type); + m_descriptor_pool_sizes.push_back({ .type = type }); + + for (const auto& input : type_arr) + { + VkDescriptorSetLayoutBinding binding + { + .binding = input.location, + .descriptorType = type, + .descriptorCount = 1, + .stageFlags = to_shader_stage_flags(input.domain) + }; + bindings.push_back(binding); + m_descriptor_pool_sizes.back().descriptorCount++; + } + } + + VkDescriptorSetLayoutCreateInfo set_layout_create_info + { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + .flags = 0, + .bindingCount = ::size32(bindings), + .pBindings = bindings.data() + }; + CHECK_RESULT(vkCreateDescriptorSetLayout(m_device, &set_layout_create_info, nullptr, &m_descriptor_set_layout)); + } + + void program::create_pipeline_layout() + { + ensure(!linked); + ensure(m_pipeline_layout == VK_NULL_HANDLE); + + create_descriptor_set_layout(); + + rsx::simple_array push_constants{}; + for (const auto& input : uniforms[input_type_push_constant]) + { + const auto& range = input.as_push_constant(); + push_constants.push_back({ .offset = range.offset, .size = range.size }); + } + + VkPipelineLayoutCreateInfo create_info + { + .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + .flags = 0, + .setLayoutCount = 1, + .pSetLayouts = &m_descriptor_set_layout, + .pushConstantRangeCount = ::size32(push_constants), + .pPushConstantRanges = push_constants.data() + }; + CHECK_RESULT(vkCreatePipelineLayout(m_device, &create_info, nullptr, &m_pipeline_layout)); + } + + void program::create_descriptor_pool() + { + ensure(linked); + + m_descriptor_pool = std::make_unique(); + m_descriptor_pool->create(*vk::get_current_renderer(), m_descriptor_pool_sizes); } } } diff --git a/rpcs3/Emu/RSX/VK/VKProgramPipeline.h b/rpcs3/Emu/RSX/VK/VKProgramPipeline.h index 06dbaf877f..0b3e8ed7d1 100644 --- a/rpcs3/Emu/RSX/VK/VKProgramPipeline.h +++ b/rpcs3/Emu/RSX/VK/VKProgramPipeline.h @@ -7,6 +7,7 @@ #include #include +#include namespace vk { @@ -15,18 +16,20 @@ namespace vk enum program_input_type : u32 { input_type_uniform_buffer = 0, - input_type_texel_buffer = 1, - input_type_texture = 2, - input_type_storage_buffer = 3, + input_type_texel_buffer, + input_type_texture, + input_type_storage_buffer, + input_type_storage_texture, + input_type_push_constant, - input_type_max_enum = 4 + input_type_max_enum }; struct bound_sampler { - VkFormat format; - VkImage image; - VkComponentMapping mapping; + VkFormat format = VK_FORMAT_UNDEFINED; + VkImage image = VK_NULL_HANDLE; + VkComponentMapping mapping{}; }; struct bound_buffer @@ -37,16 +40,73 @@ namespace vk u64 size = 0; }; + struct push_constant_ref + { + u32 offset = 0; + u32 size = 0; + }; + struct program_input { ::glsl::program_domain domain; program_input_type type; - bound_buffer as_buffer; - bound_sampler as_sampler; + using bound_data_t = std::variant; + bound_data_t bound_data; u32 location; std::string name; + + inline bound_buffer& as_buffer() { return *std::get_if(&bound_data); } + inline bound_sampler& as_sampler() { return *std::get_if(&bound_data); } + inline push_constant_ref& as_push_constant() { return *std::get_if(&bound_data); } + + inline const bound_buffer& as_buffer() const { return *std::get_if(&bound_data); } + inline const bound_sampler& as_sampler() const { return *std::get_if(&bound_data); } + inline const push_constant_ref& as_push_constant() const { return *std::get_if(&bound_data); } + + static program_input make( + ::glsl::program_domain domain, + const std::string& name, + program_input_type type, + u32 location, + const bound_data_t& data = bound_buffer{}) + { + return program_input + { + .domain = domain, + .type = type, + .bound_data = data, + .location = location, + .name = name + }; + } + }; + + union descriptor_slot_t + { + VkDescriptorImageInfo image_info; + VkDescriptorBufferInfo buffer_info; + VkBufferView buffer_view; + + bool matches(const VkDescriptorImageInfo& test) const + { + return test.imageView == image_info.imageView && + test.sampler == image_info.sampler && + test.imageLayout == image_info.imageLayout; + } + + bool matches(const VkDescriptorBufferInfo& test) const + { + return test.buffer == buffer_info.buffer && + test.offset == buffer_info.offset && + test.range == buffer_info.range; + } + + bool matches(VkBufferView test) const + { + return test == buffer_view; + } }; class shader @@ -75,37 +135,61 @@ namespace vk class program { std::array, input_type_max_enum> uniforms; - VkDevice m_device; + VkDevice m_device = VK_NULL_HANDLE; + + VkPipeline m_pipeline = VK_NULL_HANDLE; + VkPipelineLayout m_pipeline_layout = VK_NULL_HANDLE; std::array fs_texture_bindings; std::array fs_texture_mirror_bindings; std::array vs_texture_bindings; - bool linked; + bool linked = false; - void create_impl(); + std::unique_ptr m_descriptor_pool; + VkDescriptorSetLayout m_descriptor_set_layout = VK_NULL_HANDLE; + vk::descriptor_set m_descriptor_set{}; + rsx::simple_array m_descriptor_pool_sizes; + + std::vector m_descriptor_slots; + std::vector m_descriptors_dirty; + rsx::simple_array m_copy_cmds; + + void init(); + + void create_descriptor_set_layout(); + void create_pipeline_layout(); + void create_descriptor_pool(); + + VkDescriptorSet allocate_descriptor_set(); + void next_descriptor_set(); + + program& load_uniforms(const std::vector& inputs); public: - VkPipeline pipeline; - VkPipelineLayout pipeline_layout; - u64 attribute_location_mask; - u64 vertex_attributes_mask; - program(VkDevice dev, VkPipeline p, VkPipelineLayout layout, const std::vector &vertex_input, const std::vector& fragment_inputs); - program(VkDevice dev, VkPipeline p, VkPipelineLayout layout); + program(VkDevice dev, const VkGraphicsPipelineCreateInfo& create_info, const std::vector &vertex_inputs, const std::vector& fragment_inputs); + program(VkDevice dev, const VkComputePipelineCreateInfo& create_info, const std::vector& compute_inputs); program(const program&) = delete; program(program&& other) = delete; ~program(); - program& load_uniforms(const std::vector& inputs); program& link(); + program& bind(const vk::command_buffer& cmd, VkPipelineBindPoint bind_point); bool has_uniform(program_input_type type, const std::string &uniform_name); - void bind_uniform(const VkDescriptorImageInfo &image_descriptor, const std::string &uniform_name, VkDescriptorType type, vk::descriptor_set &set); - void bind_uniform(const VkDescriptorImageInfo &image_descriptor, int texture_unit, ::glsl::program_domain domain, vk::descriptor_set &set, bool is_stencil_mirror = false); - void bind_uniform(const VkDescriptorBufferInfo &buffer_descriptor, u32 binding_point, vk::descriptor_set &set); - void bind_uniform(const VkBufferView &buffer_view, u32 binding_point, vk::descriptor_set &set); - void bind_uniform(const VkBufferView &buffer_view, program_input_type type, const std::string &binding_name, vk::descriptor_set &set); - void bind_buffer(const VkDescriptorBufferInfo &buffer_descriptor, u32 binding_point, VkDescriptorType type, vk::descriptor_set &set); + u32 get_uniform_location(program_input_type type, const std::string& uniform_name); + + void bind_uniform(const VkDescriptorImageInfo &image_descriptor, const std::string &uniform_name, VkDescriptorType type); + void bind_uniform(const VkDescriptorImageInfo &image_descriptor, int texture_unit, ::glsl::program_domain domain, bool is_stencil_mirror = false); + void bind_uniform(const VkDescriptorBufferInfo &buffer_descriptor, u32 binding_point); + void bind_uniform(const VkBufferView &buffer_view, u32 binding_point); + void bind_uniform(const VkBufferView &buffer_view, program_input_type type, const std::string &binding_name); + void bind_buffer(const VkDescriptorBufferInfo &buffer_descriptor, u32 binding_point, VkDescriptorType type); + + void bind_uniform_array(const VkDescriptorImageInfo* image_descriptors, VkDescriptorType type, int count, u32 binding_point); + + inline VkPipelineLayout layout() const { return m_pipeline_layout; } + inline VkPipeline value() const { return m_pipeline; } }; } } diff --git a/rpcs3/Emu/RSX/VK/VKRenderTargets.h b/rpcs3/Emu/RSX/VK/VKRenderTargets.h index caa85dcc84..3c3ef0acbd 100644 --- a/rpcs3/Emu/RSX/VK/VKRenderTargets.h +++ b/rpcs3/Emu/RSX/VK/VKRenderTargets.h @@ -154,7 +154,7 @@ namespace vk // If we have driver support for FBO loops, set the usage flag for it. if (vk::get_current_renderer()->get_framebuffer_loops_support()) { - return { VK_IMAGE_USAGE_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT, 0 }; + return { VK_IMAGE_USAGE_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT, VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT }; } // Workarounds to force transition to GENERAL to decompress. diff --git a/rpcs3/Emu/RSX/VK/VKResolveHelper.h b/rpcs3/Emu/RSX/VK/VKResolveHelper.h index 7cf6631b67..2403f5bc59 100644 --- a/rpcs3/Emu/RSX/VK/VKResolveHelper.h +++ b/rpcs3/Emu/RSX/VK/VKResolveHelper.h @@ -23,43 +23,36 @@ namespace vk void build(const std::string& format_prefix, bool unresolve, bool bgra_swap); - std::vector> get_descriptor_layout() override - { - return - { - { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 2 } - }; - } - - void declare_inputs() override + std::vector get_inputs() override { std::vector inputs = { - { + glsl::program_input::make( ::glsl::program_domain::glsl_compute_program, - vk::glsl::program_input_type::input_type_texture, - {}, {}, - 0, - "multisampled" - }, - { + "multisampled", + glsl::input_type_storage_texture, + 0 + ), + + glsl::program_input::make( ::glsl::program_domain::glsl_compute_program, - vk::glsl::program_input_type::input_type_texture, - {}, {}, - 1, - "resolve" - } + "resolve", + glsl::input_type_storage_texture, + 1 + ), }; - m_program->load_uniforms(inputs); + auto result = compute_task::get_inputs(); + result.insert(result.end(), inputs.begin(), inputs.end()); + return result; } void bind_resources() override { auto msaa_view = multisampled->get_view(rsx::default_remap_vector.with_encoding(VK_REMAP_VIEW_MULTISAMPLED)); auto resolved_view = resolve->get_view(rsx::default_remap_vector.with_encoding(VK_REMAP_IDENTITY)); - m_program->bind_uniform({ VK_NULL_HANDLE, msaa_view->value, multisampled->current_layout }, "multisampled", VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, m_descriptor_set); - m_program->bind_uniform({ VK_NULL_HANDLE, resolved_view->value, resolve->current_layout }, "resolve", VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, m_descriptor_set); + m_program->bind_uniform({ VK_NULL_HANDLE, msaa_view->value, multisampled->current_layout }, "multisampled", VK_DESCRIPTOR_TYPE_STORAGE_IMAGE); + m_program->bind_uniform({ VK_NULL_HANDLE, resolved_view->value, resolve->current_layout }, "resolve", VK_DESCRIPTOR_TYPE_STORAGE_IMAGE); } void run(const vk::command_buffer& cmd, vk::viewable_image* msaa_image, vk::viewable_image* resolve_image) @@ -116,19 +109,22 @@ namespace vk void build(bool resolve_depth, bool resolve_stencil, bool unresolve); - std::vector get_push_constants() override + std::vector get_fragment_inputs() override { - VkPushConstantRange constant; - constant.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - constant.offset = 0; - constant.size = 16; - - return { constant }; + auto result = overlay_pass::get_fragment_inputs(); + result.push_back(glsl::program_input::make( + ::glsl::glsl_fragment_program, + "push_constants", + glsl::input_type_push_constant, + umax, + glsl::push_constant_ref{ .size = 16 } + )); + return result; } - void update_uniforms(vk::command_buffer& cmd, vk::glsl::program* /*program*/) override + void update_uniforms(vk::command_buffer& cmd, vk::glsl::program* program) override { - vkCmdPushConstants(cmd, m_pipeline_layout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, static_parameters_width * 4, static_parameters); + vkCmdPushConstants(cmd, program->layout(), VK_SHADER_STAGE_FRAGMENT_BIT, 0, static_parameters_width * 4, static_parameters); } void update_sample_configuration(vk::image* msaa_image) @@ -226,16 +222,16 @@ namespace vk state_descriptors.push_back(VK_DYNAMIC_STATE_STENCIL_WRITE_MASK); } - void emit_geometry(vk::command_buffer& cmd) override + void emit_geometry(vk::command_buffer& cmd, glsl::program* program) override { vkCmdClearAttachments(cmd, 1, &clear_info, 1, ®ion); for (s32 write_mask = 0x1; write_mask <= 0x80; write_mask <<= 1) { vkCmdSetStencilWriteMask(cmd, VK_STENCIL_FRONT_AND_BACK, write_mask); - vkCmdPushConstants(cmd, m_pipeline_layout, VK_SHADER_STAGE_FRAGMENT_BIT, 8, 4, &write_mask); + vkCmdPushConstants(cmd, program->layout(), VK_SHADER_STAGE_FRAGMENT_BIT, 8, 4, &write_mask); - overlay_pass::emit_geometry(cmd); + overlay_pass::emit_geometry(cmd, program); } } @@ -285,16 +281,16 @@ namespace vk state_descriptors.push_back(VK_DYNAMIC_STATE_STENCIL_WRITE_MASK); } - void emit_geometry(vk::command_buffer& cmd) override + void emit_geometry(vk::command_buffer& cmd, glsl::program* program) override { vkCmdClearAttachments(cmd, 1, &clear_info, 1, &clear_region); for (s32 write_mask = 0x1; write_mask <= 0x80; write_mask <<= 1) { vkCmdSetStencilWriteMask(cmd, VK_STENCIL_FRONT_AND_BACK, write_mask); - vkCmdPushConstants(cmd, m_pipeline_layout, VK_SHADER_STAGE_FRAGMENT_BIT, 8, 4, &write_mask); + vkCmdPushConstants(cmd, program->layout(), VK_SHADER_STAGE_FRAGMENT_BIT, 8, 4, &write_mask); - overlay_pass::emit_geometry(cmd); + overlay_pass::emit_geometry(cmd, program); } } diff --git a/rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp b/rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp index 3c9188fd60..da10965be9 100644 --- a/rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp +++ b/rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp @@ -254,7 +254,7 @@ namespace vk m_shader_cache[compiler_options].m_fs = std::move(fs); return ret; } - +/* std::pair shader_interpreter::create_layout(VkDevice dev) { const auto& binding_table = vk::get_current_renderer()->get_pipeline_binding_table(); @@ -356,24 +356,16 @@ namespace vk CHECK_RESULT(vkCreatePipelineLayout(dev, &layout_info, nullptr, &result)); return { set_layout, result }; } - - void shader_interpreter::create_descriptor_pools(const vk::render_device& dev) - { - const auto max_draw_calls = dev.get_descriptor_max_draw_calls(); - m_descriptor_pool.create(dev, m_descriptor_pool_sizes, max_draw_calls); - } +*/ void shader_interpreter::init(const vk::render_device& dev) { m_device = dev; - std::tie(m_shared_descriptor_layout, m_shared_pipeline_layout) = create_layout(dev); - create_descriptor_pools(dev); } void shader_interpreter::destroy() { m_program_cache.clear(); - m_descriptor_pool.destroy(); for (auto &fs : m_shader_cache) { @@ -382,18 +374,6 @@ namespace vk } m_shader_cache.clear(); - - if (m_shared_pipeline_layout) - { - vkDestroyPipelineLayout(m_device, m_shared_pipeline_layout, nullptr); - m_shared_pipeline_layout = VK_NULL_HANDLE; - } - - if (m_shared_descriptor_layout) - { - vkDestroyDescriptorSetLayout(m_device, m_shared_descriptor_layout, nullptr); - m_shared_descriptor_layout = VK_NULL_HANDLE; - } } glsl::program* shader_interpreter::link(const vk::pipeline_props& properties, u64 compiler_opt) @@ -478,28 +458,30 @@ namespace vk info.stageCount = 2; info.pStages = shader_stages; info.pDynamicState = &dynamic_state_info; - info.layout = m_shared_pipeline_layout; + info.layout = VK_NULL_HANDLE; info.basePipelineIndex = -1; info.basePipelineHandle = VK_NULL_HANDLE; info.renderPass = vk::get_renderpass(m_device, properties.renderpass_key); auto compiler = vk::get_pipe_compiler(); - auto program = compiler->compile(info, m_shared_pipeline_layout, vk::pipe_compiler::COMPILE_INLINE, {}, m_vs_inputs, m_fs_inputs); + auto program = compiler->compile(info, vk::pipe_compiler::COMPILE_INLINE, {}, m_vs_inputs, m_fs_inputs); return program.release(); } - void shader_interpreter::update_fragment_textures(const std::array& sampled_images, vk::descriptor_set &set) + void shader_interpreter::update_fragment_textures(const std::array& sampled_images) { - const VkDescriptorImageInfo* texture_ptr = sampled_images.data(); - for (u32 i = 0, binding = m_fragment_textures_start; i < 4; ++i, ++binding, texture_ptr += 16) + // FIXME: Cannot use m_fragment_textures.start now since each interpreter has its own binding layout + u32 binding = m_current_interpreter->get_uniform_location(glsl::input_type_texture, "texture1D_array"); + if (binding == umax) { - set.push(texture_ptr, 16, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, binding); + return; } - } - VkDescriptorSet shader_interpreter::allocate_descriptor_set() - { - return m_descriptor_pool.allocate(m_shared_descriptor_layout); + const VkDescriptorImageInfo* texture_ptr = sampled_images.data(); + for (u32 i = 0; i < 4; ++i, ++binding, texture_ptr += 16) + { + m_current_interpreter->bind_uniform_array(texture_ptr, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 16, binding); + } } glsl::program* shader_interpreter::get( diff --git a/rpcs3/Emu/RSX/VK/VKShaderInterpreter.h b/rpcs3/Emu/RSX/VK/VKShaderInterpreter.h index d359ca343e..aeaad698fb 100644 --- a/rpcs3/Emu/RSX/VK/VKShaderInterpreter.h +++ b/rpcs3/Emu/RSX/VK/VKShaderInterpreter.h @@ -16,8 +16,6 @@ namespace vk std::vector m_fs_inputs; VkDevice m_device = VK_NULL_HANDLE; - VkDescriptorSetLayout m_shared_descriptor_layout = VK_NULL_HANDLE; - VkPipelineLayout m_shared_pipeline_layout = VK_NULL_HANDLE; glsl::program* m_current_interpreter = nullptr; struct pipeline_key @@ -47,8 +45,6 @@ namespace vk std::unordered_map, key_hasher> m_program_cache; std::unordered_map m_shader_cache; - rsx::simple_array m_descriptor_pool_sizes; - vk::descriptor_pool m_descriptor_pool; u32 m_vertex_instruction_start = 0; u32 m_fragment_instruction_start = 0; @@ -56,9 +52,6 @@ namespace vk pipeline_key m_current_key{}; - std::pair create_layout(VkDevice dev); - void create_descriptor_pools(const vk::render_device& dev); - glsl::shader* build_vs(u64 compiler_opt); glsl::shader* build_fs(u64 compiler_opt); glsl::program* link(const vk::pipeline_props& properties, u64 compiler_opt); @@ -78,7 +71,6 @@ namespace vk u32 get_vertex_instruction_location() const; u32 get_fragment_instruction_location() const; - void update_fragment_textures(const std::array& sampled_images, vk::descriptor_set &set); - VkDescriptorSet allocate_descriptor_set(); + void update_fragment_textures(const std::array& sampled_images); }; } diff --git a/rpcs3/Emu/RSX/VK/upscalers/fsr1/fsr_pass.cpp b/rpcs3/Emu/RSX/VK/upscalers/fsr1/fsr_pass.cpp index c256070490..d0b972765c 100644 --- a/rpcs3/Emu/RSX/VK/upscalers/fsr1/fsr_pass.cpp +++ b/rpcs3/Emu/RSX/VK/upscalers/fsr1/fsr_pass.cpp @@ -68,36 +68,28 @@ namespace vk create(); } - std::vector> fsr_pass::get_descriptor_layout() - { - return - { - { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1 }, - { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1 } - }; - } - - void fsr_pass::declare_inputs() + std::vector fsr_pass::get_inputs() { std::vector inputs = { - { + glsl::program_input::make( ::glsl::program_domain::glsl_compute_program, - vk::glsl::program_input_type::input_type_texture, - {}, {}, - 0, - "InputTexture" - }, - { + "InputTexture", + vk::glsl::input_type_texture, + 0 + ), + + glsl::program_input::make( ::glsl::program_domain::glsl_compute_program, - vk::glsl::program_input_type::input_type_texture, - {}, {}, - 1, - "OutputTexture" - } + "OutputTexture", + vk::glsl::input_type_storage_texture, + 1 + ), }; - m_program->load_uniforms(inputs); + auto result = compute_task::get_inputs(); + result.insert(result.end(), inputs.begin(), inputs.end()); + return result; } void fsr_pass::bind_resources() @@ -111,8 +103,8 @@ namespace vk VK_FALSE, 0.f, 1.f, 0.f, 0.f, VK_FILTER_LINEAR, VK_FILTER_LINEAR, VK_SAMPLER_MIPMAP_MODE_NEAREST, VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK); } - m_program->bind_uniform({ m_sampler->value, m_input_image->value, m_input_image->image()->current_layout }, "InputTexture", VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, m_descriptor_set); - m_program->bind_uniform({ VK_NULL_HANDLE, m_output_image->value, m_output_image->image()->current_layout }, "OutputTexture", VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, m_descriptor_set); + m_program->bind_uniform({ m_sampler->value, m_input_image->value, m_input_image->image()->current_layout }, "InputTexture", VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER); + m_program->bind_uniform({ VK_NULL_HANDLE, m_output_image->value, m_output_image->image()->current_layout }, "OutputTexture", VK_DESCRIPTOR_TYPE_STORAGE_IMAGE); } void fsr_pass::run(const vk::command_buffer& cmd, vk::viewable_image* src, vk::viewable_image* dst, const size2u& input_size, const size2u& output_size) @@ -158,7 +150,7 @@ namespace vk static_cast(src_image->width()), static_cast(src_image->height()), // Size of the raw image to upscale (in case viewport does not cover it all) static_cast(m_output_size.width), static_cast(m_output_size.height)); // Size of output viewport (target size) - vkCmdPushConstants(cmd, m_pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, push_constants_size, m_constants_buf); + vkCmdPushConstants(cmd, m_program->layout(), VK_SHADER_STAGE_COMPUTE_BIT, 0, push_constants_size, m_constants_buf); } rcas_pass::rcas_pass() @@ -177,7 +169,7 @@ namespace vk auto cas_attenuation = 2.f - (g_cfg.video.vk.rcas_sharpening_intensity / 50.f); FsrRcasCon(&m_constants_buf[0], cas_attenuation); - vkCmdPushConstants(cmd, m_pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, push_constants_size, m_constants_buf); + vkCmdPushConstants(cmd, m_program->layout(), VK_SHADER_STAGE_COMPUTE_BIT, 0, push_constants_size, m_constants_buf); } } // Namespace FidelityFX diff --git a/rpcs3/Emu/RSX/VK/upscalers/fsr_pass.h b/rpcs3/Emu/RSX/VK/upscalers/fsr_pass.h index c5b5b30e73..6d9b15d72a 100644 --- a/rpcs3/Emu/RSX/VK/upscalers/fsr_pass.h +++ b/rpcs3/Emu/RSX/VK/upscalers/fsr_pass.h @@ -19,8 +19,7 @@ namespace vk size2u m_output_size; u32 m_constants_buf[20]; - std::vector> get_descriptor_layout() override; - void declare_inputs() override; + std::vector get_inputs() override; void bind_resources() override; virtual void configure(const vk::command_buffer& cmd) = 0; From 4d493bbb800f38ad57aaac37f289e376e5ccbd2d Mon Sep 17 00:00:00 2001 From: kd-11 Date: Sun, 8 Jun 2025 21:34:57 +0300 Subject: [PATCH 03/37] vk: Fix build --- rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp | 35 +++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp b/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp index 34bb4d1331..2090b6dd26 100644 --- a/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp +++ b/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp @@ -8,7 +8,7 @@ namespace vk { - extern vk::render_device* get_current_renderer(); + extern const vk::render_device* get_current_renderer(); namespace glsl { @@ -331,10 +331,43 @@ namespace vk void program::bind_buffer(const VkDescriptorBufferInfo &buffer_descriptor, u32 binding_point, VkDescriptorType type) { + if (m_descriptor_slots[binding_point].matches(buffer_descriptor)) + { + return; + } + + next_descriptor_set(); m_descriptor_set.push(buffer_descriptor, type, binding_point); m_descriptors_dirty[binding_point] = false; } + void program::bind_uniform_array(const VkDescriptorImageInfo* image_descriptors, VkDescriptorType type, int count, u32 binding_point) + { + // FIXME: Unoptimized... + bool match = true; + for (int i = 0; i < count; ++i) + { + if (!m_descriptor_slots[binding_point + i].matches(image_descriptors[i])) + { + match = false; + break; + } + } + + if (match) + { + return; + } + + next_descriptor_set(); + m_descriptor_set.push(image_descriptors, static_cast(count), type, binding_point); + + for (int i = 0; i < count; ++i) + { + m_descriptors_dirty[binding_point] = false; + } + } + VkDescriptorSet program::allocate_descriptor_set() { if (!m_descriptor_pool) From 356b2f591060f29d0453f4c92a6619fc0e983e83 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Thu, 12 Jun 2025 03:56:30 +0300 Subject: [PATCH 04/37] vk: Rewrite program binding management to use "separate shader objects" concept. --- rpcs3/Emu/RSX/VK/VKCommonDecompiler.cpp | 30 ++ rpcs3/Emu/RSX/VK/VKCommonDecompiler.h | 2 + rpcs3/Emu/RSX/VK/VKCompute.cpp | 10 +- rpcs3/Emu/RSX/VK/VKCompute.h | 12 +- rpcs3/Emu/RSX/VK/VKDraw.cpp | 39 +- rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp | 152 ++++-- rpcs3/Emu/RSX/VK/VKFragmentProgram.h | 17 +- rpcs3/Emu/RSX/VK/VKGSRender.cpp | 29 +- rpcs3/Emu/RSX/VK/VKOverlays.cpp | 15 +- rpcs3/Emu/RSX/VK/VKPipelineCompiler.cpp | 14 +- rpcs3/Emu/RSX/VK/VKPipelineCompiler.h | 7 +- rpcs3/Emu/RSX/VK/VKProgramHelper.hpp | 12 + rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp | 531 +++++++++++-------- rpcs3/Emu/RSX/VK/VKProgramPipeline.h | 105 ++-- rpcs3/Emu/RSX/VK/VKResolveHelper.h | 7 +- rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp | 4 +- rpcs3/Emu/RSX/VK/VKVertexProgram.cpp | 139 +++-- rpcs3/Emu/RSX/VK/VKVertexProgram.h | 16 +- rpcs3/Emu/RSX/VK/upscalers/fsr1/fsr_pass.cpp | 6 +- rpcs3/Emu/RSX/VK/vkutils/descriptors.cpp | 5 - rpcs3/Emu/RSX/VK/vkutils/descriptors.h | 4 +- 21 files changed, 743 insertions(+), 413 deletions(-) create mode 100644 rpcs3/Emu/RSX/VK/VKProgramHelper.hpp diff --git a/rpcs3/Emu/RSX/VK/VKCommonDecompiler.cpp b/rpcs3/Emu/RSX/VK/VKCommonDecompiler.cpp index 01e5cc07aa..1191561625 100644 --- a/rpcs3/Emu/RSX/VK/VKCommonDecompiler.cpp +++ b/rpcs3/Emu/RSX/VK/VKCommonDecompiler.cpp @@ -35,4 +35,34 @@ namespace vk fmt::throw_exception("Unknown register name: %s", varying_register_name); } + + int get_texture_index(std::string_view name) + { + if (name.length() < 2) + { + fmt::throw_exception("Invalid texture name: '%s'", name); + } + +#define IS_DIGIT(x) (x >= '0' && x <= '9') + + constexpr int max_index_length = 2; + std::string index; + + for (int char_idx = name.length() - max_index_length; char_idx < name.length(); ++char_idx) + { + if (IS_DIGIT(name[char_idx])) + { + index += name[char_idx]; + } + } + +#undef IS_DIGIT + + if (index.empty()) + { + fmt::throw_exception("Invalid texture name: '%s'", name); + } + + return std::atoi(index.c_str()); + } } diff --git a/rpcs3/Emu/RSX/VK/VKCommonDecompiler.h b/rpcs3/Emu/RSX/VK/VKCommonDecompiler.h index b0920e27f5..b17eb83b11 100644 --- a/rpcs3/Emu/RSX/VK/VKCommonDecompiler.h +++ b/rpcs3/Emu/RSX/VK/VKCommonDecompiler.h @@ -6,4 +6,6 @@ namespace vk using namespace ::glsl; int get_varying_register_location(std::string_view varying_register_name); + + int get_texture_index(std::string_view name); } diff --git a/rpcs3/Emu/RSX/VK/VKCompute.cpp b/rpcs3/Emu/RSX/VK/VKCompute.cpp index ae36723b81..c164edddd7 100644 --- a/rpcs3/Emu/RSX/VK/VKCompute.cpp +++ b/rpcs3/Emu/RSX/VK/VKCompute.cpp @@ -18,6 +18,7 @@ namespace vk ::glsl::glsl_compute_program, "ssbo" + std::to_string(i), glsl::program_input_type::input_type_storage_buffer, + 0, i ); result.push_back(input); @@ -31,6 +32,7 @@ namespace vk "push_constants", glsl::program_input_type::input_type_push_constant, 0, + 0, glsl::push_constant_ref{ .offset = 0, .size = push_constants_size } ); result.push_back(input); @@ -243,7 +245,7 @@ namespace vk void cs_shuffle_base::bind_resources() { - m_program->bind_buffer({ m_data->value, m_data_offset, m_data_length }, 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + m_program->bind_uniform({ m_data->value, m_data_offset, m_data_length }, 0, 0); } void cs_shuffle_base::set_parameters(const vk::command_buffer& cmd, const u32* params, u8 count) @@ -289,7 +291,7 @@ namespace vk void cs_interleave_task::bind_resources() { - m_program->bind_buffer({ m_data->value, m_data_offset, m_ssbo_length }, 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + m_program->bind_uniform({ m_data->value, 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) @@ -349,8 +351,8 @@ namespace vk void cs_aggregator::bind_resources() { - m_program->bind_buffer({ src->value, 0, block_length }, 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); - m_program->bind_buffer({ dst->value, 0, 4 }, 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + m_program->bind_uniform({ src->value, 0, block_length }, 0, 0); + m_program->bind_uniform({ dst->value, 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 d4e99d8cf3..fa053afe50 100644 --- a/rpcs3/Emu/RSX/VK/VKCompute.h +++ b/rpcs3/Emu/RSX/VK/VKCompute.h @@ -344,7 +344,7 @@ namespace vk void bind_resources() override { - m_program->bind_buffer({ m_data->value, m_data_offset, m_ssbo_length }, 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + m_program->bind_uniform({ m_data->value, 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) @@ -445,8 +445,8 @@ namespace vk void bind_resources() override { - m_program->bind_buffer({ src_buffer->value, in_offset, block_length }, 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); - m_program->bind_buffer({ dst_buffer->value, out_offset, block_length }, 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + 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); } void set_parameters(const vk::command_buffer& cmd) @@ -573,9 +573,9 @@ namespace vk void bind_resources() override { - const auto op = static_cast(Op); - m_program->bind_buffer({ src_buffer->value, in_offset, in_block_length }, 0 ^ op, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); - m_program->bind_buffer({ dst_buffer->value, out_offset, out_block_length }, 1 ^ op, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + 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); } 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 4d1253340d..1e96087694 100644 --- a/rpcs3/Emu/RSX/VK/VKDraw.cpp +++ b/rpcs3/Emu/RSX/VK/VKDraw.cpp @@ -554,8 +554,8 @@ bool VKGSRender::bind_texture_env() if (view) [[likely]] { m_program->bind_uniform({ fs_sampler_handles[i]->value, view->value, view->image()->current_layout }, - i, - ::glsl::program_domain::glsl_fragment_program); + vk::glsl::binding_set_index_fragment, + m_fragment_prog->binding_table.ftex_location[i]); if (current_fragment_program.texture_state.redirected_textures & (1 << i)) { @@ -575,24 +575,22 @@ bool VKGSRender::bind_texture_env() } m_program->bind_uniform({ m_stencil_mirror_sampler->value, stencil_view->value, stencil_view->image()->current_layout }, - i, - ::glsl::program_domain::glsl_fragment_program, - true); + vk::glsl::binding_set_index_fragment, + m_fragment_prog->binding_table.ftex_stencil_location[i]); } } else { const VkImageViewType view_type = vk::get_view_type(current_fragment_program.get_texture_dimension(i)); m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer, view_type)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, - i, - ::glsl::program_domain::glsl_fragment_program); + vk::glsl::binding_set_index_fragment, + m_fragment_prog->binding_table.ftex_location[i]); if (current_fragment_program.texture_state.redirected_textures & (1 << i)) { m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer, view_type)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, - i, - ::glsl::program_domain::glsl_fragment_program, - true); + vk::glsl::binding_set_index_fragment, + m_fragment_prog->binding_table.ftex_stencil_location[i]); } } } @@ -606,8 +604,8 @@ bool VKGSRender::bind_texture_env() { const auto view_type = vk::get_view_type(current_vertex_program.get_texture_dimension(i)); m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer, view_type)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, - i, - ::glsl::program_domain::glsl_vertex_program); + vk::glsl::binding_set_index_vertex, + m_vertex_prog->binding_table.vtex_location[i]); continue; } @@ -629,8 +627,8 @@ bool VKGSRender::bind_texture_env() const auto view_type = vk::get_view_type(current_vertex_program.get_texture_dimension(i)); m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer, view_type)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, - i, - ::glsl::program_domain::glsl_vertex_program); + vk::glsl::binding_set_index_vertex, + m_vertex_prog->binding_table.vtex_location[i]); continue; } @@ -638,8 +636,8 @@ bool VKGSRender::bind_texture_env() validate_image_layout_for_read_access(*m_current_command_buffer, image_ptr, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, sampler_state); m_program->bind_uniform({ vs_sampler_handles[i]->value, image_ptr->value, image_ptr->image()->current_layout }, - i, - ::glsl::program_domain::glsl_vertex_program); + vk::glsl::binding_set_index_vertex, + m_vertex_prog->binding_table.vtex_location[i]); } return out_of_memory; @@ -820,8 +818,6 @@ void VKGSRender::emit_geometry(u32 sub_index) auto volatile_buffer = m_volatile_attribute_storage ? m_volatile_attribute_storage->value : null_buffer_view->value; bool update_descriptors = false; - const auto& binding_table = m_device->get_pipeline_binding_table(); - if (m_current_draw.subdraw_id == 0) { update_descriptors = true; @@ -878,9 +874,10 @@ void VKGSRender::emit_geometry(u32 sub_index) ensure(m_vertex_layout_storage); if (update_descriptors) { - m_program->bind_uniform(persistent_buffer, binding_table.vertex_buffers_first_bind_slot); - m_program->bind_uniform(volatile_buffer, binding_table.vertex_buffers_first_bind_slot + 1); - m_program->bind_uniform(m_vertex_layout_storage->value, binding_table.vertex_buffers_first_bind_slot + 2); + const auto& binding_table = m_vertex_prog->binding_table; + m_program->bind_uniform(persistent_buffer, vk::glsl::binding_set_index_vertex, binding_table.vertex_buffers_location); + m_program->bind_uniform(volatile_buffer, vk::glsl::binding_set_index_vertex, binding_table.vertex_buffers_location + 1); + m_program->bind_uniform(m_vertex_layout_storage->value, vk::glsl::binding_set_index_vertex, binding_table.vertex_buffers_location + 2); } bool reload_state = (!m_current_draw.subdraw_id++); diff --git a/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp b/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp index dd654a6736..25f4297dee 100644 --- a/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp +++ b/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp @@ -26,8 +26,85 @@ std::string VKFragmentDecompilerThread::compareFunction(COMPARE f, const std::st return glsl::compareFunctionImpl(f, Op0, Op1); } +void VKFragmentDecompilerThread::prepareBindingTable() +{ + // First check if we have constants and textures as those need extra work + bool has_constants = false, has_textures = false; + for (const ParamType& PT : m_parr.params[PF_PARAM_UNIFORM]) + { + if (has_constants && has_textures) + { + break; + } + + if (PT.type.starts_with("sampler")) + { + has_textures = true; + continue; + } + + ensure(PT.type.starts_with("vec")); + has_constants = true; + } + + unsigned location = 0; // All bindings must be set from this var + vk_prog->binding_table.context_buffer_location = location++; + if (has_constants) + { + vk_prog->binding_table.cbuf_location = location++; + } + + vk_prog->binding_table.tex_param_location = location++; + vk_prog->binding_table.polygon_stipple_params_location = location++; + + if (has_textures) [[ likely ]] + { + unsigned num_textures = 0; + for (const ParamType& PT : m_parr.params[PF_PARAM_UNIFORM]) + { + if (!PT.type.starts_with("sampler")) + { + continue; + } + + for (const ParamItem& PI : PT.items) + { + num_textures++; + + const auto texture_id = vk::get_texture_index(PI.name); + const auto mask = 1u << texture_id; + + // Allocate real binding + vk_prog->binding_table.ftex_location[texture_id] = location++; + + // Tag the stencil mirror if required + if (properties.redirected_sampler_mask & mask) [[ unlikely ]] + { + vk_prog->binding_table.ftex_stencil_location[texture_id] = 0; + } + } + + // Normalize stencil offsets + if (properties.redirected_sampler_mask != 0) [[ unlikely ]] + { + for (auto& stencil_location : vk_prog->binding_table.ftex_stencil_location) + { + if (stencil_location == umax) + { + continue; + } + + stencil_location = location++; + } + } + } + } +} + void VKFragmentDecompilerThread::insertHeader(std::stringstream & OS) { + prepareBindingTable(); + std::vector required_extensions; if (device_props.has_native_half_support) @@ -97,21 +174,18 @@ void VKFragmentDecompilerThread::insertOutputs(std::stringstream & OS) void VKFragmentDecompilerThread::insertConstants(std::stringstream & OS) { - u32 location = m_binding_table.textures_first_bind_slot; for (const ParamType& PT : m_parr.params[PF_PARAM_UNIFORM]) { - if (PT.type != "sampler1D" && - PT.type != "sampler2D" && - PT.type != "sampler3D" && - PT.type != "samplerCube") + if (PT.type.starts_with("sampler1D")) + { continue; + } for (const ParamItem& PI : PT.items) { std::string samplerType = PT.type; - ensure(PI.name.length() > 3); - int index = atoi(&PI.name[3]); + const int index = vk::get_texture_index(PI.name); const auto mask = (1 << index); if (properties.multisampled_sampler_mask & mask) @@ -135,39 +209,37 @@ void VKFragmentDecompilerThread::insertConstants(std::stringstream & OS) } } - vk::glsl::program_input in; - in.location = location; - in.domain = glsl::glsl_fragment_program; - in.name = PI.name; - in.type = vk::glsl::input_type_texture; - + const int id = vk::get_texture_index(PI.name); + auto in = vk::glsl::program_input::make( + glsl::glsl_fragment_program, + PI.name, + vk::glsl::input_type_texture, + vk::glsl::binding_set_index_fragment, + vk_prog->binding_table.ftex_location[id] + ); inputs.push_back(in); - OS << "layout(set=0, binding=" << location++ << ") uniform " << samplerType << " " << PI.name << ";\n"; + OS << "layout(set=0, binding=" << in.location << ") uniform " << samplerType << " " << PI.name << ";\n"; if (properties.redirected_sampler_mask & mask) { // Insert stencil mirror declaration in.name += "_stencil"; - in.location = location; - + in.location = vk_prog->binding_table.ftex_stencil_location[id]; inputs.push_back(in); - OS << "layout(set=0, binding=" << location++ << ") uniform u" << samplerType << " " << in.name << ";\n"; + OS << "layout(set=0, binding=" << in.location << ") uniform u" << samplerType << " " << in.name << ";\n"; } } } - ensure(location <= m_binding_table.vertex_textures_first_bind_slot); // "Too many sampler descriptors!" - std::string constants_block; for (const ParamType& PT : m_parr.params[PF_PARAM_UNIFORM]) { - if (PT.type == "sampler1D" || - PT.type == "sampler2D" || - PT.type == "sampler3D" || - PT.type == "samplerCube") + if (PT.type.starts_with("sampler1D")) + { continue; + } for (const ParamItem& PI : PT.items) { @@ -177,13 +249,13 @@ void VKFragmentDecompilerThread::insertConstants(std::stringstream & OS) if (!constants_block.empty()) { - OS << "layout(std140, set = 0, binding = 2) uniform FragmentConstantsBuffer\n"; + OS << "layout(std140, set = 1, binding = " << vk_prog->binding_table.cbuf_location << ") uniform FragmentConstantsBuffer\n"; OS << "{\n"; OS << constants_block; OS << "};\n\n"; } - OS << "layout(std140, set = 0, binding = 3) uniform FragmentStateBuffer\n"; + OS << "layout(std140, set = 1, binding = " << vk_prog->binding_table.context_buffer_location << ") uniform FragmentStateBuffer\n"; OS << "{\n"; OS << " float fog_param0;\n"; OS << " float fog_param1;\n"; @@ -195,32 +267,39 @@ void VKFragmentDecompilerThread::insertConstants(std::stringstream & OS) OS << " float wpos_bias;\n"; OS << "};\n\n"; - OS << "layout(std140, set = 0, binding = 4) uniform TextureParametersBuffer\n"; + OS << "layout(std140, set = 1, binding = " << vk_prog->binding_table.tex_param_location << ") uniform TextureParametersBuffer\n"; OS << "{\n"; OS << " sampler_info texture_parameters[16];\n"; OS << "};\n\n"; - OS << "layout(std140, set = 0, binding = " << std::to_string(m_binding_table.rasterizer_env_bind_slot) << ") uniform RasterizerHeap\n"; + OS << "layout(std140, set = 1, binding = " << vk_prog->binding_table.polygon_stipple_params_location << ") uniform RasterizerHeap\n"; OS << "{\n"; OS << " uvec4 stipple_pattern[8];\n"; OS << "};\n\n"; - vk::glsl::program_input in; - in.location = m_binding_table.fragment_constant_buffers_bind_slot; - in.domain = glsl::glsl_fragment_program; - in.name = "FragmentConstantsBuffer"; - in.type = vk::glsl::input_type_uniform_buffer; - inputs.push_back(in); + vk::glsl::program_input in + { + .domain = glsl::glsl_fragment_program, + .type = vk::glsl::input_type_uniform_buffer, + .set = vk::glsl::binding_set_index_fragment + }; - in.location = m_binding_table.fragment_state_bind_slot; + if (!constants_block.empty()) + { + in.location = vk_prog->binding_table.cbuf_location; + in.name = "FragmentConstantsBuffer"; + inputs.push_back(in); + } + + in.location = vk_prog->binding_table.context_buffer_location; in.name = "FragmentStateBuffer"; inputs.push_back(in); - in.location = m_binding_table.fragment_texture_params_bind_slot; + in.location = vk_prog->binding_table.tex_param_location; in.name = "TextureParametersBuffer"; inputs.push_back(in); - in.location = m_binding_table.rasterizer_env_bind_slot; + in.location = vk_prog->binding_table.polygon_stipple_params_location; in.name = "RasterizerHeap"; inputs.push_back(in); } @@ -372,7 +451,6 @@ void VKFragmentDecompilerThread::insertMainEnd(std::stringstream & OS) void VKFragmentDecompilerThread::Task() { - m_binding_table = vk::g_render_device->get_pipeline_binding_table(); m_shader = Decompile(); vk_prog->SetInputs(inputs); } diff --git a/rpcs3/Emu/RSX/VK/VKFragmentProgram.h b/rpcs3/Emu/RSX/VK/VKFragmentProgram.h index 787f38ec05..049455a866 100644 --- a/rpcs3/Emu/RSX/VK/VKFragmentProgram.h +++ b/rpcs3/Emu/RSX/VK/VKFragmentProgram.h @@ -19,7 +19,8 @@ struct VKFragmentDecompilerThread : public FragmentProgramDecompiler std::vector inputs; class VKFragmentProgram *vk_prog; glsl::shader_properties m_shader_props{}; - vk::pipeline_binding_table m_binding_table{}; + + void prepareBindingTable(); public: VKFragmentDecompilerThread(std::string& shader, ParamArray& parr, const RSXFragmentProgram &prog, u32& size, class VKFragmentProgram& dst) @@ -32,6 +33,7 @@ public: void Task(); const std::vector& get_inputs() { return inputs; } + protected: std::string getFloatTypeName(usz elementCount) override; std::string getHalfTypeName(usz elementCount) override; @@ -63,8 +65,19 @@ public: std::vector FragmentConstantOffsetCache; std::array output_color_masks{ {} }; - std::vector uniforms; + + struct + { + u32 context_buffer_location = umax; // Rasterizer context + u32 cbuf_location = umax; // Constants register file + u32 tex_param_location = umax; // Texture configuration data + u32 polygon_stipple_params_location = umax; // Polygon stipple settings + u32 ftex_location[16]; // Texture locations array + u32 ftex_stencil_location[16]; // Texture stencil mirror array + + } binding_table; + void SetInputs(std::vector& inputs); /** * Decompile a fragment shader located in the PS3's Memory. This function operates synchronously. diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index 17f42f45e8..d64551f7e9 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -2074,34 +2074,35 @@ void VKGSRender::load_program_env() } } - const auto& binding_table = m_device->get_pipeline_binding_table(); + const auto& vs_binding_table = m_vertex_prog->binding_table; + const auto& fs_binding_table = m_fragment_prog->binding_table; - m_program->bind_uniform(m_vertex_env_buffer_info, binding_table.vertex_params_bind_slot); - m_program->bind_buffer(m_vertex_constants_buffer_info, binding_table.vertex_constant_buffers_bind_slot, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); - m_program->bind_uniform(m_fragment_env_buffer_info, binding_table.fragment_state_bind_slot); - m_program->bind_uniform(m_fragment_texture_params_buffer_info, binding_table.fragment_texture_params_bind_slot); - m_program->bind_uniform(m_raster_env_buffer_info, binding_table.rasterizer_env_bind_slot); + m_program->bind_uniform(m_vertex_env_buffer_info, vk::glsl::binding_set_index_vertex, vs_binding_table.context_buffer_location); + m_program->bind_uniform(m_vertex_constants_buffer_info, vk::glsl::binding_set_index_vertex, vs_binding_table.cbuf_location); + m_program->bind_uniform(m_fragment_env_buffer_info, vk::glsl::binding_set_index_fragment, fs_binding_table.context_buffer_location); + m_program->bind_uniform(m_fragment_texture_params_buffer_info, vk::glsl::binding_set_index_fragment, fs_binding_table.tex_param_location); + m_program->bind_uniform(m_raster_env_buffer_info, vk::glsl::binding_set_index_fragment, fs_binding_table.polygon_stipple_params_location); - if (!m_shader_interpreter.is_interpreter(m_program)) + if (m_shader_interpreter.is_interpreter(m_program)) { - m_program->bind_uniform(m_fragment_constants_buffer_info, binding_table.fragment_constant_buffers_bind_slot); + m_program->bind_uniform(m_vertex_instructions_buffer_info, vk::glsl::binding_set_index_vertex, m_shader_interpreter.get_vertex_instruction_location()); + m_program->bind_uniform(m_fragment_instructions_buffer_info, vk::glsl::binding_set_index_fragment, m_shader_interpreter.get_fragment_instruction_location()); } - else + else if (fs_binding_table.cbuf_location != umax) { - m_program->bind_buffer(m_vertex_instructions_buffer_info, m_shader_interpreter.get_vertex_instruction_location(), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); - m_program->bind_buffer(m_fragment_instructions_buffer_info, m_shader_interpreter.get_fragment_instruction_location(), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + m_program->bind_uniform(m_fragment_constants_buffer_info, vk::glsl::binding_set_index_fragment, fs_binding_table.cbuf_location); } if (vk::emulate_conditional_rendering()) { auto predicate = m_cond_render_buffer ? m_cond_render_buffer->value : vk::get_scratch_buffer(*m_current_command_buffer, 4)->value; - m_program->bind_buffer({ predicate, 0, 4 }, binding_table.conditional_render_predicate_slot, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + m_program->bind_uniform({ predicate, 0, 4 }, vk::glsl::binding_set_index_vertex, vs_binding_table.cr_pred_buffer_location); } if (current_vertex_program.ctrl & RSX_SHADER_CONTROL_INSTANCED_CONSTANTS) { - m_program->bind_buffer(m_instancing_indirection_buffer_info, binding_table.instancing_lookup_table_bind_slot, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); - m_program->bind_buffer(m_instancing_constants_array_buffer_info, binding_table.instancing_constants_buffer_slot, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + m_program->bind_uniform(m_instancing_indirection_buffer_info, vk::glsl::binding_set_index_vertex, vs_binding_table.instanced_lut_buffer_location); + m_program->bind_uniform(m_instancing_constants_array_buffer_info, vk::glsl::binding_set_index_vertex, vs_binding_table.instanced_cbuf_location); } // Clear flags diff --git a/rpcs3/Emu/RSX/VK/VKOverlays.cpp b/rpcs3/Emu/RSX/VK/VKOverlays.cpp index 5cd4761983..6a74f8e646 100644 --- a/rpcs3/Emu/RSX/VK/VKOverlays.cpp +++ b/rpcs3/Emu/RSX/VK/VKOverlays.cpp @@ -63,21 +63,21 @@ namespace vk for (u32 n = 0; n < m_num_uniform_buffers; ++n, ++binding) { const std::string name = std::string("static_data") + (n > 0 ? std::to_string(n) : ""); - const auto input = program_input::make(::glsl::program_domain::glsl_fragment_program, name, program_input_type::input_type_uniform_buffer, 0); + const auto input = program_input::make(::glsl::program_domain::glsl_fragment_program, name, program_input_type::input_type_uniform_buffer, 0, 0); fs_inputs.push_back(input); } for (u32 n = 0; n < m_num_usable_samplers; ++n, ++binding) { const std::string name = "fs" + std::to_string(n); - const auto input = program_input::make(::glsl::program_domain::glsl_fragment_program, name, program_input_type::input_type_texture, binding); + const auto input = program_input::make(::glsl::program_domain::glsl_fragment_program, name, program_input_type::input_type_texture, 0, binding); fs_inputs.push_back(input); } for (u32 n = 0; n < m_num_input_attachments; ++n, ++binding) { const std::string name = "sp" + std::to_string(n); - const auto input = program_input::make(::glsl::program_domain::glsl_fragment_program, name, program_input_type::input_type_texture, binding); + const auto input = program_input::make(::glsl::program_domain::glsl_fragment_program, name, program_input_type::input_type_texture, 0, binding); fs_inputs.push_back(input); } @@ -179,13 +179,14 @@ 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); + program->bind_uniform({ m_ubo.heap->value, m_ubo_offset, std::max(m_ubo_length, 4u) }, 0, 0); } for (uint n = 0; n < src.size(); ++n) { VkDescriptorImageInfo info = { m_sampler->value, src[n]->value, src[n]->image()->current_layout }; - program->bind_uniform(info, "fs" + std::to_string(n), VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER); + const auto [set, location] = program->get_uniform_location(::glsl::glsl_fragment_program, glsl::input_type_texture, "fs" + std::to_string(n)); + program->bind_uniform(info, set, location); } program->bind(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS); @@ -488,6 +489,7 @@ namespace vk "push_constants", glsl::input_type_push_constant, 0, + 0, glsl::push_constant_ref { .size = 68 } ) ); @@ -503,6 +505,7 @@ namespace vk "push_constants", glsl::input_type_push_constant, 0, + 0, glsl::push_constant_ref {.offset = 68, .size = 12 } ) ); @@ -715,6 +718,7 @@ namespace vk "push_constants", vk::glsl::input_type_push_constant, 0, + 0, glsl::push_constant_ref{ .size = 32 }) }; } @@ -864,6 +868,7 @@ namespace vk "push_constants", vk::glsl::input_type_push_constant, 0, + 0, glsl::push_constant_ref{ .size = 16 } ) ); diff --git a/rpcs3/Emu/RSX/VK/VKPipelineCompiler.cpp b/rpcs3/Emu/RSX/VK/VKPipelineCompiler.cpp index 13c16513d3..884841ec4b 100644 --- a/rpcs3/Emu/RSX/VK/VKPipelineCompiler.cpp +++ b/rpcs3/Emu/RSX/VK/VKPipelineCompiler.cpp @@ -54,7 +54,9 @@ namespace vk const VkComputePipelineCreateInfo& create_info, const std::vector& cs_inputs) { - return std::make_unique(*m_device, create_info, cs_inputs); + auto program = std::make_unique(*m_device, create_info, cs_inputs); + program->link(false); + return program; } std::unique_ptr pipe_compiler::int_compile_graphics_pipe( @@ -62,7 +64,9 @@ namespace vk const std::vector& vs_inputs, const std::vector& fs_inputs) { - return std::make_unique(*m_device, create_info, vs_inputs, fs_inputs); + auto program = std::make_unique(*m_device, create_info, vs_inputs, fs_inputs); + program->link(true); + return program; } std::unique_ptr pipe_compiler::int_compile_graphics_pipe( @@ -171,7 +175,7 @@ namespace vk op_flags flags, callback_t callback, const std::vector& cs_inputs) { - if (flags == COMPILE_INLINE) + if (flags & COMPILE_INLINE) { return int_compile_compute_pipe(create_info, cs_inputs); } @@ -187,7 +191,7 @@ namespace vk const std::vector& fs_inputs) { // It is very inefficient to defer this as all pointers need to be saved - ensure(flags == COMPILE_INLINE); + ensure(flags & COMPILE_INLINE); return int_compile_graphics_pipe(create_info, vs_inputs, fs_inputs); } @@ -200,7 +204,7 @@ namespace vk const std::vector& fs_inputs) { VkShaderModule modules[] = { vs, fs }; - if (flags == COMPILE_INLINE) + if (flags & COMPILE_INLINE) { return int_compile_graphics_pipe(create_info, modules, vs_inputs, fs_inputs); } diff --git a/rpcs3/Emu/RSX/VK/VKPipelineCompiler.h b/rpcs3/Emu/RSX/VK/VKPipelineCompiler.h index a915595e62..25c0b8e1c0 100644 --- a/rpcs3/Emu/RSX/VK/VKPipelineCompiler.h +++ b/rpcs3/Emu/RSX/VK/VKPipelineCompiler.h @@ -53,13 +53,16 @@ namespace vk class pipe_compiler { public: - enum op_flags + enum op_flag_bits { COMPILE_DEFAULT = 0, COMPILE_INLINE = 1, - COMPILE_DEFERRED = 2 + COMPILE_DEFERRED = 2, + SEPARATE_SHADER_OBJECTS = 4 }; + using op_flags = rsx::flags32_t; + using callback_t = std::function&)>; pipe_compiler(); diff --git a/rpcs3/Emu/RSX/VK/VKProgramHelper.hpp b/rpcs3/Emu/RSX/VK/VKProgramHelper.hpp new file mode 100644 index 0000000000..328df80f1d --- /dev/null +++ b/rpcs3/Emu/RSX/VK/VKProgramHelper.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include "VKProgramPipeline.h" + +namespace vk +{ + namespace glsl + { + + } +} + diff --git a/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp b/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp index 2090b6dd26..5ac4bd9c26 100644 --- a/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp +++ b/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp @@ -14,6 +14,30 @@ namespace vk { using namespace ::glsl; + bool operator == (const descriptor_slot_t& a, const VkDescriptorImageInfo& b) + { + const auto ptr = std::get_if(&a); + return !!ptr && + ptr->imageView == b.imageView && + ptr->sampler == b.sampler && + ptr->imageLayout == b.imageLayout; + } + + bool operator == (const descriptor_slot_t& a, const VkDescriptorBufferInfo& b) + { + const auto ptr = std::get_if(&a); + return !!ptr && + ptr->buffer == b.buffer && + ptr->offset == b.offset && + ptr->range == b.range; + } + + bool operator == (const descriptor_slot_t& a, const VkBufferView& b) + { + const auto ptr = std::get_if(&a); + return !!ptr && *ptr == b; + } + VkDescriptorType to_descriptor_type(program_input_type type) { switch (type) @@ -120,42 +144,24 @@ namespace vk void program::init() { - linked = false; - - fs_texture_bindings.fill(~0u); - fs_texture_mirror_bindings.fill(~0u); - vs_texture_bindings.fill(~0u); + m_linked = false; } program::program(VkDevice dev, const VkGraphicsPipelineCreateInfo& create_info, const std::vector &vertex_inputs, const std::vector& fragment_inputs) - : m_device(dev) + : m_device(dev), m_info(create_info) { init(); load_uniforms(vertex_inputs); load_uniforms(fragment_inputs); - - create_pipeline_layout(); - ensure(m_pipeline_layout); - - auto _create_info = create_info; - _create_info.layout = m_pipeline_layout; - CHECK_RESULT(vkCreateGraphicsPipelines(dev, nullptr, 1, &create_info, nullptr, &m_pipeline)); } program::program(VkDevice dev, const VkComputePipelineCreateInfo& create_info, const std::vector& compute_inputs) - : m_device(dev) + : m_device(dev), m_info(create_info) { init(); load_uniforms(compute_inputs); - - create_pipeline_layout(); - ensure(m_pipeline_layout); - - auto _create_info = create_info; - _create_info.layout = m_pipeline_layout; - CHECK_RESULT(vkCreateComputePipelines(dev, nullptr, 1, &create_info, nullptr, &m_pipeline)); } program::~program() @@ -165,257 +171,352 @@ namespace vk if (m_pipeline_layout) { vkDestroyPipelineLayout(m_device, m_pipeline_layout, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_descriptor_set_layout, nullptr); - vk::get_resource_manager()->dispose(m_descriptor_pool); + + for (auto& set : m_sets) + { + set.destroy(); + } } } program& program::load_uniforms(const std::vector& inputs) { - ensure(!linked); // "Cannot change uniforms in already linked program!" + ensure(!m_linked); // "Cannot change uniforms in already linked program!" for (auto &item : inputs) { - uniforms[item.type].push_back(item); + ensure(item.set < binding_set_index_max_enum); // Ensure we have a valid set id + ensure(item.location < 128u || item.type == input_type_push_constant); // Arbitrary limit but useful to catch possibly uninitialized values + m_sets[item.set].m_inputs[item.type].push_back(item); } return *this; } - program& program::link() + program& program::link(bool separate_objects) { - // Preprocess texture bindings - // Link step is only useful for rasterizer programs, compute programs do not need this - for (const auto &uniform : uniforms[program_input_type::input_type_texture]) - { - if (const auto name_start = uniform.name.find("tex"); name_start != umax) - { - const auto name_end = uniform.name.find("_stencil"); - const auto index_start = name_start + 3; // Skip 'tex' part - const auto index_length = (name_end != umax) ? name_end - index_start : name_end; - const auto index_part = uniform.name.substr(index_start, index_length); - const auto index = std::stoi(index_part); + auto p_graphics_info = std::get_if(&m_info); + auto p_compute_info = !p_graphics_info ? std::get_if(&m_info) : nullptr; + const bool is_graphics_pipe = p_graphics_info != nullptr; - if (name_start == 0) + if (!is_graphics_pipe) [[ likely ]] + { + // We only support compute and graphics, so disable this for compute + separate_objects = false; + } + + if (!separate_objects) + { + // Collapse all sets into set 0 if validation passed + auto& sink = m_sets[0]; + for (auto& set : m_sets) + { + for (auto& type_arr : set.m_inputs) { - // Fragment texture (tex...) - if (name_end == umax) + if (type_arr.empty()) { - // Normal texture - fs_texture_bindings[index] = uniform.location; - } - else - { - // Stencil mirror - fs_texture_mirror_bindings[index] = uniform.location; + continue; } + + auto type = type_arr.front().type; + auto& dst = sink.m_inputs[type]; + dst.insert(dst.end(), type_arr.begin(), type_arr.end()); + + // Clear + type_arr.clear(); } - else + } + + sink.validate(); + sink.init(m_device); + } + else + { + for (auto& set : m_sets) + { + for (auto& type_arr : set.m_inputs) { - // Vertex texture (vtex...) - vs_texture_bindings[index] = uniform.location; + if (type_arr.empty()) + { + continue; + } + + // Real set + set.validate(); + set.init(m_device); + break; } } } - linked = true; + create_pipeline_layout(); + ensure(m_pipeline_layout); + + if (is_graphics_pipe) + { + VkGraphicsPipelineCreateInfo create_info = *p_graphics_info; + create_info.layout = m_pipeline_layout; + CHECK_RESULT(vkCreateGraphicsPipelines(m_device, nullptr, 1, &create_info, nullptr, &m_pipeline)); + } + else + { + VkComputePipelineCreateInfo create_info = *p_compute_info; + create_info.layout = m_pipeline_layout; + CHECK_RESULT(vkCreateComputePipelines(m_device, nullptr, 1, &create_info, nullptr, &m_pipeline)); + } + + m_linked = true; return *this; } bool program::has_uniform(program_input_type type, const std::string& uniform_name) { - const auto& uniform = uniforms[type]; - return std::any_of(uniform.cbegin(), uniform.cend(), [&uniform_name](const auto& u) + for (auto& set : m_sets) { - return u.name == uniform_name; - }); - } - - u32 program::get_uniform_location(program_input_type type, const std::string& uniform_name) - { - const auto& uniform = uniforms[type]; - const auto result = std::find_if(uniform.cbegin(), uniform.cend(), [&uniform_name](const auto& u) - { - return u.name == uniform_name; - }); - - if (result == uniform.end()) - { - return { umax }; - } - - return result->location; - } - - void program::bind_uniform(const VkDescriptorImageInfo &image_descriptor, const std::string& uniform_name, VkDescriptorType type) - { - for (const auto &uniform : uniforms[program_input_type::input_type_texture]) - { - if (uniform.name == uniform_name) + const auto& uniform = set.m_inputs[type]; + return std::any_of(uniform.cbegin(), uniform.cend(), [&uniform_name](const auto& u) { - if (m_descriptor_slots[uniform.location].matches(image_descriptor)) - { - return; - } + return u.name == uniform_name; + }); + } + } - next_descriptor_set(); - m_descriptor_set.push(image_descriptor, type, uniform.location); - m_descriptors_dirty[uniform.location] = false; - return; + std::pair program::get_uniform_location(::glsl::program_domain domain, program_input_type type, const std::string& uniform_name) + { + for (unsigned i = 0; i < ::size32(m_sets); ++i) + { + const auto& type_arr = m_sets[i].m_inputs[type]; + const auto result = std::find_if(type_arr.cbegin(), type_arr.cend(), [&](const auto& u) + { + return u.domain == domain && u.name == uniform_name; + }); + + if (result != type_arr.end()) + { + return { i, result->location }; } } - rsx_log.notice("texture not found in program: %s", uniform_name.c_str()); + return { umax, umax }; } - void program::bind_uniform(const VkDescriptorImageInfo & image_descriptor, int texture_unit, ::glsl::program_domain domain, bool is_stencil_mirror) + void program::bind_uniform(const VkDescriptorImageInfo& image_descriptor, u32 set_id, u32 binding_point) { - ensure(domain != ::glsl::program_domain::glsl_compute_program); - - u32 binding; - if (domain == ::glsl::program_domain::glsl_fragment_program) - { - binding = (is_stencil_mirror) ? fs_texture_mirror_bindings[texture_unit] : fs_texture_bindings[texture_unit]; - } - else - { - binding = vs_texture_bindings[texture_unit]; - } - - if (binding == ~0u) [[ unlikely ]] - { - rsx_log.notice("texture not found in program: %stex%u", (domain == ::glsl::program_domain::glsl_vertex_program) ? "v" : "", texture_unit); - return; - } - - if (m_descriptor_slots[binding].matches(image_descriptor)) + if (m_sets[set_id].m_descriptor_slots[binding_point] == image_descriptor) { return; } - next_descriptor_set(); - m_descriptor_set.push(image_descriptor, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, binding); - m_descriptors_dirty[binding] = false; + m_sets[set_id].notify_descriptor_slot_updated(binding_point, image_descriptor); } - void program::bind_uniform(const VkDescriptorBufferInfo &buffer_descriptor, u32 binding_point) + void program::bind_uniform(const VkDescriptorBufferInfo &buffer_descriptor, u32 set_id, u32 binding_point) { - bind_buffer(buffer_descriptor, binding_point, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER); - } - - void program::bind_uniform(const VkBufferView &buffer_view, u32 binding_point) - { - if (m_descriptor_slots[binding_point].matches(buffer_view)) + if (m_sets[set_id].m_descriptor_slots[binding_point] == buffer_descriptor) { return; } - next_descriptor_set(); - m_descriptor_set.push(buffer_view, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, binding_point); - m_descriptors_dirty[binding_point] = false; + m_sets[set_id].notify_descriptor_slot_updated(binding_point, buffer_descriptor); } - void program::bind_uniform(const VkBufferView &buffer_view, program_input_type type, const std::string &binding_name) + void program::bind_uniform(const VkBufferView &buffer_view, u32 set_id, u32 binding_point) { - for (const auto &uniform : uniforms[type]) - { - if (uniform.name == binding_name) - { - bind_uniform(buffer_view, uniform.location); - return; - } - } - - rsx_log.notice("vertex buffer not found in program: %s", binding_name.c_str()); - } - - void program::bind_buffer(const VkDescriptorBufferInfo &buffer_descriptor, u32 binding_point, VkDescriptorType type) - { - if (m_descriptor_slots[binding_point].matches(buffer_descriptor)) + if (m_sets[set_id].m_descriptor_slots[binding_point] == buffer_view) { return; } - next_descriptor_set(); - m_descriptor_set.push(buffer_descriptor, type, binding_point); - m_descriptors_dirty[binding_point] = false; + m_sets[set_id].notify_descriptor_slot_updated(binding_point, buffer_view); } - void program::bind_uniform_array(const VkDescriptorImageInfo* image_descriptors, VkDescriptorType type, int count, u32 binding_point) + void program::bind_uniform_array(const VkDescriptorImageInfo* image_descriptors, VkDescriptorType type, int count, u32 set_id, u32 binding_point) { - // FIXME: Unoptimized... - bool match = true; + auto& set = m_sets[set_id]; for (int i = 0; i < count; ++i) { - if (!m_descriptor_slots[binding_point + i].matches(image_descriptors[i])) + if (set.m_descriptor_slots[binding_point + i] != image_descriptors[i]) + { + set.notify_descriptor_slot_updated(binding_point + i, image_descriptors[i]); + } + } + } + + void program::create_pipeline_layout() + { + ensure(!m_linked); + ensure(m_pipeline_layout == VK_NULL_HANDLE); + + rsx::simple_array push_constants{}; + rsx::simple_array set_layouts{}; + + for (auto& set : m_sets) + { + if (!set.m_device) { - match = false; break; } + + set.next_descriptor_set(); // Initializes the set layout and allocates first set + set_layouts.push_back(set.m_descriptor_set_layout); + + for (const auto& input : set.m_inputs[input_type_push_constant]) + { + const auto& range = input.as_push_constant(); + push_constants.push_back({ + .stageFlags = to_shader_stage_flags(input.domain), + .offset = range.offset, + .size = range.size + }); + } } - if (match) + VkPipelineLayoutCreateInfo create_info + { + .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + .flags = 0, + .setLayoutCount = set_layouts.size(), + .pSetLayouts = set_layouts.data(), + .pushConstantRangeCount = push_constants.size(), + .pPushConstantRanges = push_constants.data() + }; + CHECK_RESULT(vkCreatePipelineLayout(m_device, &create_info, nullptr, &m_pipeline_layout)); + } + + program& program::bind(const vk::command_buffer& cmd, VkPipelineBindPoint bind_point) + { + VkDescriptorSet bind_sets[binding_set_index_max_enum]; + unsigned count = 0; + + for (auto& set : m_sets) + { + if (!set.m_device) + { + break; + } + + bind_sets[count++] = set.m_descriptor_set.value(); // Current set pointer for binding + set.next_descriptor_set(); // Flush queue and update pointers + } + + vkCmdBindPipeline(cmd, bind_point, m_pipeline); + vkCmdBindDescriptorSets(cmd, bind_point, m_pipeline_layout, 0, count, bind_sets, 0, nullptr); + return *this; + } + + void descriptor_table_t::destroy() + { + if (!m_device) { return; } - next_descriptor_set(); - m_descriptor_set.push(image_descriptors, static_cast(count), type, binding_point); - - for (int i = 0; i < count; ++i) - { - m_descriptors_dirty[binding_point] = false; - } + vkDestroyDescriptorSetLayout(m_device, m_descriptor_set_layout, nullptr); + vk::get_resource_manager()->dispose(m_descriptor_pool); } - VkDescriptorSet program::allocate_descriptor_set() + void descriptor_table_t::init(VkDevice dev) + { + m_device = dev; + + size_t bind_slots_count = 0; + for (auto& type_arr : m_inputs) + { + if (type_arr.empty() || type_arr.front().type == input_type_push_constant) + { + continue; + } + + bind_slots_count += type_arr.size(); + } + + m_descriptor_slots.resize(bind_slots_count); + std::memset(m_descriptor_slots.data(), 0, sizeof(descriptor_slot_t) * bind_slots_count); + + m_descriptors_dirty.resize(bind_slots_count); + std::fill(m_descriptors_dirty.begin(), m_descriptors_dirty.end(), false); + } + + VkDescriptorSet descriptor_table_t::allocate_descriptor_set() { if (!m_descriptor_pool) { create_descriptor_pool(); + create_descriptor_set_layout(); } return m_descriptor_pool->allocate(m_descriptor_set_layout); } - void program::next_descriptor_set() + void descriptor_table_t::next_descriptor_set() { - const auto new_set = allocate_descriptor_set(); - const auto old_set = m_descriptor_set.value(); - - if (old_set) + if (!m_descriptor_set) { - m_copy_cmds.clear(); - for (unsigned i = 0; i < m_copy_cmds.size(); ++i) - { - if (!m_descriptors_dirty[i]) - { - continue; - } - - // Reuse already initialized memory. Each command is the same anyway. - m_copy_cmds.resize(m_copy_cmds.size() + 1); - auto& cmd = m_copy_cmds.back(); - cmd.srcBinding = cmd.dstBinding = i; - cmd.srcSet = old_set; - cmd.dstSet = new_set; - } - - m_descriptor_set.push(m_copy_cmds); + m_descriptor_set = allocate_descriptor_set(); + std::fill(m_descriptors_dirty.begin(), m_descriptors_dirty.end(), false); + return; } - m_descriptor_set = allocate_descriptor_set(); + // Check if we need to actually open a new set + if (!m_any_descriptors_dirty) + { + return; + } + + auto old_set = m_descriptor_set.value(); + auto new_set = allocate_descriptor_set(); + + auto push_descriptor_slot = [this](unsigned idx) + { + const auto& slot = m_descriptor_slots[idx]; + const VkDescriptorType type = m_descriptor_types[idx]; + if (auto ptr = std::get_if(&slot)) + { + m_descriptor_set.push(*ptr, type, idx); + return; + } + + if (auto ptr = std::get_if(&slot)) + { + m_descriptor_set.push(*ptr, type, idx); + return; + } + + if (auto ptr = std::get_if(&slot)) + { + m_descriptor_set.push(*ptr, type, idx); + return; + } + + fmt::throw_exception("Unexpected descriptor structure at index %u", idx); + }; + + m_copy_cmds.clear(); + for (unsigned i = 0; i < m_descriptor_slots.size(); ++i) + { + if (m_descriptors_dirty[i]) + { + // Push + push_descriptor_slot(i); + m_descriptors_dirty[i] = false; + continue; + } + + m_copy_cmds.push_back({ + .sType = VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET, + .srcSet = old_set, + .srcBinding = i, + .dstSet = new_set, + .dstBinding = i, + .descriptorCount = 1 + }); + } + + m_descriptor_set.push(m_copy_cmds); // Write previous state + m_descriptor_set = new_set; } - program& program::bind(const vk::command_buffer& cmd, VkPipelineBindPoint bind_point) - { - VkDescriptorSet set = m_descriptor_set.value(); - vkCmdBindPipeline(cmd, bind_point, m_pipeline); - vkCmdBindDescriptorSets(cmd, bind_point, m_pipeline_layout, 0, 1, &set, 0, nullptr); - return *this; - } - - void program::create_descriptor_set_layout() + void descriptor_table_t::create_descriptor_set_layout() { ensure(m_descriptor_set_layout == VK_NULL_HANDLE); @@ -425,7 +526,7 @@ namespace vk m_descriptor_pool_sizes.clear(); m_descriptor_pool_sizes.reserve(input_type_max_enum); - for (const auto& type_arr : uniforms) + for (const auto& type_arr : m_inputs) { if (type_arr.empty() || type_arr.front().type == input_type_push_constant) { @@ -445,6 +546,13 @@ namespace vk .stageFlags = to_shader_stage_flags(input.domain) }; bindings.push_back(binding); + + if (m_descriptor_types.size() < (input.location + 1)) + { + m_descriptor_types.resize((input.location + 1)); + } + + m_descriptor_types[input.location] = type; m_descriptor_pool_sizes.back().descriptorCount++; } } @@ -459,38 +567,31 @@ namespace vk CHECK_RESULT(vkCreateDescriptorSetLayout(m_device, &set_layout_create_info, nullptr, &m_descriptor_set_layout)); } - void program::create_pipeline_layout() + void descriptor_table_t::create_descriptor_pool() { - ensure(!linked); - ensure(m_pipeline_layout == VK_NULL_HANDLE); - - create_descriptor_set_layout(); - - rsx::simple_array push_constants{}; - for (const auto& input : uniforms[input_type_push_constant]) - { - const auto& range = input.as_push_constant(); - push_constants.push_back({ .offset = range.offset, .size = range.size }); - } - - VkPipelineLayoutCreateInfo create_info - { - .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, - .flags = 0, - .setLayoutCount = 1, - .pSetLayouts = &m_descriptor_set_layout, - .pushConstantRangeCount = ::size32(push_constants), - .pPushConstantRanges = push_constants.data() - }; - CHECK_RESULT(vkCreatePipelineLayout(m_device, &create_info, nullptr, &m_pipeline_layout)); - } - - void program::create_descriptor_pool() - { - ensure(linked); - m_descriptor_pool = std::make_unique(); m_descriptor_pool->create(*vk::get_current_renderer(), m_descriptor_pool_sizes); } + + void descriptor_table_t::validate() const + { + // Check for overlapping locations + std::set taken_locations; + + for (auto& type_arr : m_inputs) + { + if (type_arr.empty() || + type_arr.front().type == input_type_push_constant) + { + continue; + } + + for (const auto& input : type_arr) + { + ensure(taken_locations.find(input.location) == taken_locations.end(), "Overlapping input locations found."); + taken_locations.insert(input.location); + } + } + } } } diff --git a/rpcs3/Emu/RSX/VK/VKProgramPipeline.h b/rpcs3/Emu/RSX/VK/VKProgramPipeline.h index 0b3e8ed7d1..96940a8efe 100644 --- a/rpcs3/Emu/RSX/VK/VKProgramPipeline.h +++ b/rpcs3/Emu/RSX/VK/VKProgramPipeline.h @@ -54,7 +54,8 @@ namespace vk using bound_data_t = std::variant; bound_data_t bound_data; - u32 location; + u32 set = 0; + u32 location = umax; std::string name; inline bound_buffer& as_buffer() { return *std::get_if(&bound_data); } @@ -69,6 +70,7 @@ namespace vk ::glsl::program_domain domain, const std::string& name, program_input_type type, + u32 set, u32 location, const bound_data_t& data = bound_buffer{}) { @@ -77,38 +79,13 @@ namespace vk .domain = domain, .type = type, .bound_data = data, + .set = set, .location = location, .name = name }; } }; - union descriptor_slot_t - { - VkDescriptorImageInfo image_info; - VkDescriptorBufferInfo buffer_info; - VkBufferView buffer_view; - - bool matches(const VkDescriptorImageInfo& test) const - { - return test.imageView == image_info.imageView && - test.sampler == image_info.sampler && - test.imageLayout == image_info.imageLayout; - } - - bool matches(const VkDescriptorBufferInfo& test) const - { - return test.buffer == buffer_info.buffer && - test.offset == buffer_info.offset && - test.range == buffer_info.range; - } - - bool matches(VkBufferView test) const - { - return test == buffer_view; - } - }; - class shader { ::glsl::program_domain type = ::glsl::program_domain::glsl_vertex_program; @@ -132,37 +109,71 @@ namespace vk VkShaderModule get_handle() const; }; - class program + using descriptor_slot_t = std::variant; + + struct descriptor_table_t { - std::array, input_type_max_enum> uniforms; VkDevice m_device = VK_NULL_HANDLE; - - VkPipeline m_pipeline = VK_NULL_HANDLE; - VkPipelineLayout m_pipeline_layout = VK_NULL_HANDLE; - - std::array fs_texture_bindings; - std::array fs_texture_mirror_bindings; - std::array vs_texture_bindings; - bool linked = false; + std::array, input_type_max_enum> m_inputs; std::unique_ptr m_descriptor_pool; VkDescriptorSetLayout m_descriptor_set_layout = VK_NULL_HANDLE; vk::descriptor_set m_descriptor_set{}; rsx::simple_array m_descriptor_pool_sizes; + rsx::simple_array m_descriptor_types; std::vector m_descriptor_slots; std::vector m_descriptors_dirty; rsx::simple_array m_copy_cmds; + bool m_any_descriptors_dirty = false; - void init(); + void init(VkDevice dev); + void destroy(); + + void validate() const; void create_descriptor_set_layout(); - void create_pipeline_layout(); void create_descriptor_pool(); VkDescriptorSet allocate_descriptor_set(); void next_descriptor_set(); + template + inline void notify_descriptor_slot_updated(u32 slot, const T& data) + { + m_descriptors_dirty[slot] = true; + m_descriptor_slots[slot] = data; + m_any_descriptors_dirty = true; + } + }; + + enum binding_set_index : u32 + { + // For separate shader objects + binding_set_index_vertex = 0, + binding_set_index_fragment = 1, + + // Aliases + binding_set_index_compute = 0, + binding_set_index_unified = 0, + + // Meta + binding_set_index_max_enum = 2, + }; + + class program + { + VkDevice m_device = VK_NULL_HANDLE; + VkPipeline m_pipeline = VK_NULL_HANDLE; + VkPipelineLayout m_pipeline_layout = VK_NULL_HANDLE; + + std::variant m_info; + std::array m_sets; + bool m_linked = false; + + void init(); + void create_pipeline_layout(); + program& load_uniforms(const std::vector& inputs); public: @@ -173,20 +184,18 @@ namespace vk program(program&& other) = delete; ~program(); - program& link(); + program& link(bool separate_stages); program& bind(const vk::command_buffer& cmd, VkPipelineBindPoint bind_point); bool has_uniform(program_input_type type, const std::string &uniform_name); - u32 get_uniform_location(program_input_type type, const std::string& uniform_name); + std::pair get_uniform_location(::glsl::program_domain domain, program_input_type type, const std::string& uniform_name); - void bind_uniform(const VkDescriptorImageInfo &image_descriptor, const std::string &uniform_name, VkDescriptorType type); - void bind_uniform(const VkDescriptorImageInfo &image_descriptor, int texture_unit, ::glsl::program_domain domain, bool is_stencil_mirror = false); - void bind_uniform(const VkDescriptorBufferInfo &buffer_descriptor, u32 binding_point); - void bind_uniform(const VkBufferView &buffer_view, u32 binding_point); - void bind_uniform(const VkBufferView &buffer_view, program_input_type type, const std::string &binding_name); - void bind_buffer(const VkDescriptorBufferInfo &buffer_descriptor, u32 binding_point, VkDescriptorType type); + void bind_uniform(const VkDescriptorImageInfo &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_array(const VkDescriptorImageInfo* image_descriptors, VkDescriptorType type, int count, u32 binding_point); + void bind_uniform_array(const VkDescriptorImageInfo* image_descriptors, VkDescriptorType type, int count, u32 set_id, u32 binding_point); inline VkPipelineLayout layout() const { return m_pipeline_layout; } inline VkPipeline value() const { return m_pipeline; } diff --git a/rpcs3/Emu/RSX/VK/VKResolveHelper.h b/rpcs3/Emu/RSX/VK/VKResolveHelper.h index 2403f5bc59..9bc9e4f532 100644 --- a/rpcs3/Emu/RSX/VK/VKResolveHelper.h +++ b/rpcs3/Emu/RSX/VK/VKResolveHelper.h @@ -31,6 +31,7 @@ namespace vk ::glsl::program_domain::glsl_compute_program, "multisampled", glsl::input_type_storage_texture, + 0, 0 ), @@ -38,6 +39,7 @@ namespace vk ::glsl::program_domain::glsl_compute_program, "resolve", glsl::input_type_storage_texture, + 0, 1 ), }; @@ -51,8 +53,8 @@ namespace vk { auto msaa_view = multisampled->get_view(rsx::default_remap_vector.with_encoding(VK_REMAP_VIEW_MULTISAMPLED)); auto resolved_view = resolve->get_view(rsx::default_remap_vector.with_encoding(VK_REMAP_IDENTITY)); - m_program->bind_uniform({ VK_NULL_HANDLE, msaa_view->value, multisampled->current_layout }, "multisampled", VK_DESCRIPTOR_TYPE_STORAGE_IMAGE); - m_program->bind_uniform({ VK_NULL_HANDLE, resolved_view->value, resolve->current_layout }, "resolve", VK_DESCRIPTOR_TYPE_STORAGE_IMAGE); + m_program->bind_uniform({ VK_NULL_HANDLE, msaa_view->value, multisampled->current_layout }, 0, 0); + m_program->bind_uniform({ VK_NULL_HANDLE, resolved_view->value, resolve->current_layout }, 0, 1); } void run(const vk::command_buffer& cmd, vk::viewable_image* msaa_image, vk::viewable_image* resolve_image) @@ -116,6 +118,7 @@ namespace vk ::glsl::glsl_fragment_program, "push_constants", glsl::input_type_push_constant, + 0, umax, glsl::push_constant_ref{ .size = 16 } )); diff --git a/rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp b/rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp index da10965be9..e7c4862dbc 100644 --- a/rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp +++ b/rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp @@ -471,7 +471,7 @@ namespace vk void shader_interpreter::update_fragment_textures(const std::array& sampled_images) { // FIXME: Cannot use m_fragment_textures.start now since each interpreter has its own binding layout - u32 binding = m_current_interpreter->get_uniform_location(glsl::input_type_texture, "texture1D_array"); + auto [set, binding] = m_current_interpreter->get_uniform_location(::glsl::glsl_fragment_program, glsl::input_type_texture, "texture1D_array"); if (binding == umax) { return; @@ -480,7 +480,7 @@ namespace vk const VkDescriptorImageInfo* texture_ptr = sampled_images.data(); for (u32 i = 0; i < 4; ++i, ++binding, texture_ptr += 16) { - m_current_interpreter->bind_uniform_array(texture_ptr, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 16, binding); + m_current_interpreter->bind_uniform_array(texture_ptr, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 16, set, binding); } } diff --git a/rpcs3/Emu/RSX/VK/VKVertexProgram.cpp b/rpcs3/Emu/RSX/VK/VKVertexProgram.cpp index 60f33f49c5..b6def63136 100644 --- a/rpcs3/Emu/RSX/VK/VKVertexProgram.cpp +++ b/rpcs3/Emu/RSX/VK/VKVertexProgram.cpp @@ -6,7 +6,6 @@ #include "vkutils/device.h" #include "../Program/GLSLCommon.h" - std::string VKVertexDecompilerThread::getFloatTypeName(usz elementCount) { return glsl::getFloatTypeNameImpl(elementCount); @@ -27,14 +26,57 @@ std::string VKVertexDecompilerThread::compareFunction(COMPARE f, const std::stri return glsl::compareFunctionImpl(f, Op0, Op1, scalar); } +void VKVertexDecompilerThread::prepareBindingTable() +{ + u32 location = 0; + vk_prog->binding_table.vertex_buffers_location = location; + location += 3; // Persistent verts, volatile and layout data + + vk_prog->binding_table.context_buffer_location = location++; + if (m_device_props.emulate_conditional_rendering) + { + vk_prog->binding_table.cr_pred_buffer_location = location++; + } + + for (const ParamType& PT : m_parr.params[PF_PARAM_UNIFORM]) + { + const bool is_texture_type = PT.type.starts_with("sampler"); + + for (const ParamItem& PI : PT.items) + { + if (is_texture_type) + { + const int id = vk::get_texture_index(PI.name); + vk_prog->binding_table.vtex_location[id] = location++; + continue; + } + + if (PI.name.starts_with("vc[")) + { + if (!(m_prog.ctrl & RSX_SHADER_CONTROL_INSTANCED_CONSTANTS)) + { + vk_prog->binding_table.cbuf_location = location++; + continue; + } + + vk_prog->binding_table.instanced_lut_buffer_location = location++; + vk_prog->binding_table.instanced_cbuf_location = location++; + continue; + } + } + } +} + void VKVertexDecompilerThread::insertHeader(std::stringstream &OS) { + prepareBindingTable(); + OS << "#version 450\n\n" "#extension GL_ARB_separate_shader_objects : enable\n\n"; OS << - "layout(std140, set = 0, binding = 0) uniform VertexContextBuffer\n" + "layout(std140, set = 0, binding = " << vk_prog->binding_table.context_buffer_location << " ) uniform VertexContextBuffer\n" "{\n" " mat4 scale_offset_mat;\n" " ivec4 user_clip_enabled[2];\n" @@ -45,13 +87,31 @@ void VKVertexDecompilerThread::insertHeader(std::stringstream &OS) " float z_far;\n" "};\n\n"; + vk::glsl::program_input context_input = + { + .domain = glsl::glsl_vertex_program, + .type = vk::glsl::input_type_uniform_buffer, + .location = vk_prog->binding_table.context_buffer_location, + .name = "VertexContextBuffer" + }; + inputs.push_back(context_input); + if (m_device_props.emulate_conditional_rendering) { OS << - "layout(std430, set = 0, binding = 8) readonly buffer EXT_Conditional_Rendering\n" + "layout(std430, set = 0, binding = " << vk_prog->binding_table.cr_pred_buffer_location << ") readonly buffer EXT_Conditional_Rendering\n" "{\n" " uint conditional_rendering_predicate;\n" "};\n\n"; + + vk::glsl::program_input predicate_input = + { + .domain = glsl::glsl_vertex_program, + .type = vk::glsl::input_type_storage_buffer, + .location = vk_prog->binding_table.cr_pred_buffer_location, + .name = "EXT_Conditional_Rendering" + }; + inputs.push_back(predicate_input); } OS << @@ -63,52 +123,50 @@ void VKVertexDecompilerThread::insertHeader(std::stringstream &OS) " uint layout_ptr_offset;\n" " uint xform_constants_offset;\n"; + u32 push_constants_size = 5 * sizeof(u32); if (m_device_props.emulate_conditional_rendering) { + push_constants_size += sizeof(u32); OS << " uint conditional_rendering_enabled;\n"; } OS << "};\n\n"; - vk::glsl::program_input in; - in.location = m_binding_table.vertex_params_bind_slot; - in.domain = glsl::glsl_vertex_program; - in.name = "VertexContextBuffer"; - in.type = vk::glsl::input_type_uniform_buffer; - inputs.push_back(in); + vk::glsl::program_input push_constants = + { + .domain = glsl::glsl_vertex_program, + .type = vk::glsl::input_type_push_constant, + .bound_data = vk::glsl::push_constant_ref{ .offset = 0, .size = push_constants_size } + }; + inputs.push_back(push_constants); } void VKVertexDecompilerThread::insertInputs(std::stringstream& OS, const std::vector& /*inputs*/) { - OS << "layout(set=0, binding=5) uniform usamplerBuffer persistent_input_stream;\n"; // Data stream with persistent vertex data (cacheable) - OS << "layout(set=0, binding=6) uniform usamplerBuffer volatile_input_stream;\n"; // Data stream with per-draw data (registers and immediate draw data) - OS << "layout(set=0, binding=7) uniform usamplerBuffer vertex_layout_stream;\n"; // Data stream defining vertex data layout + static const char* input_streams[] = + { + "persistent_input_stream", // Data stream with persistent vertex data (cacheable) + "volatile_input_stream", // Data stream with per-draw data (registers and immediate draw data) + "vertex_layout_stream" // Data stream defining vertex data layout" + }; - vk::glsl::program_input in; - in.location = m_binding_table.vertex_buffers_first_bind_slot; - in.domain = glsl::glsl_vertex_program; - in.name = "persistent_input_stream"; - in.type = vk::glsl::input_type_texel_buffer; - this->inputs.push_back(in); + int location = vk_prog->binding_table.vertex_buffers_location; + for (const auto& stream : input_streams) + { + OS << "layout(set=0, binding=" << location << ") uniform usamplerBuffer " << stream << ";\n"; - in.location = m_binding_table.vertex_buffers_first_bind_slot + 1; - in.domain = glsl::glsl_vertex_program; - in.name = "volatile_input_stream"; - in.type = vk::glsl::input_type_texel_buffer; - this->inputs.push_back(in); - - in.location = m_binding_table.vertex_buffers_first_bind_slot + 2; - in.domain = glsl::glsl_vertex_program; - in.name = "vertex_layout_stream"; - in.type = vk::glsl::input_type_texel_buffer; - this->inputs.push_back(in); + vk::glsl::program_input in; + in.location = location++; + in.domain = glsl::glsl_vertex_program; + in.name = stream; + in.type = vk::glsl::input_type_texel_buffer; + this->inputs.push_back(in); + } } void VKVertexDecompilerThread::insertConstants(std::stringstream & OS, const std::vector & constants) { vk::glsl::program_input in; - u32 location = m_binding_table.vertex_textures_first_bind_slot; - for (const ParamType &PT : constants) { for (const ParamItem &PI : PT.items) @@ -117,12 +175,12 @@ void VKVertexDecompilerThread::insertConstants(std::stringstream & OS, const std { if (!(m_prog.ctrl & RSX_SHADER_CONTROL_INSTANCED_CONSTANTS)) { - OS << "layout(std430, set=0, binding=" << static_cast(m_binding_table.vertex_constant_buffers_bind_slot) << ") readonly buffer VertexConstantsBuffer\n"; + OS << "layout(std430, set=0, binding=" << vk_prog->binding_table.cbuf_location << ") readonly buffer VertexConstantsBuffer\n"; OS << "{\n"; OS << " vec4 vc[];\n"; OS << "};\n\n"; - in.location = m_binding_table.vertex_constant_buffers_bind_slot; + in.location = vk_prog->binding_table.cbuf_location; in.domain = glsl::glsl_vertex_program; in.name = "VertexConstantsBuffer"; in.type = vk::glsl::input_type_storage_buffer; @@ -133,26 +191,26 @@ void VKVertexDecompilerThread::insertConstants(std::stringstream & OS, const std else { // 1. Bind indirection lookup buffer - OS << "layout(std430, set=0, binding=" << static_cast(m_binding_table.instancing_lookup_table_bind_slot) << ") readonly buffer InstancingData\n"; + OS << "layout(std430, set=0, binding=" << vk_prog->binding_table.instanced_lut_buffer_location << ") readonly buffer InstancingData\n"; OS << "{\n"; OS << " int constants_addressing_lookup[];\n"; OS << "};\n\n"; - in.location = m_binding_table.instancing_lookup_table_bind_slot; + in.location = vk_prog->binding_table.instanced_lut_buffer_location; in.domain = glsl::glsl_vertex_program; in.name = "InstancingData"; in.type = vk::glsl::input_type_storage_buffer; inputs.push_back(in); // 2. Bind actual constants buffer - OS << "layout(std430, set=0, binding=" << static_cast(m_binding_table.instancing_constants_buffer_slot) << ") readonly buffer VertexConstantsBuffer\n"; + OS << "layout(std430, set=0, binding=" << vk_prog->binding_table.instanced_cbuf_location << ") readonly buffer VertexConstantsBuffer\n"; OS << "{\n"; OS << " vec4 instanced_constants_array[];\n"; OS << "};\n\n"; OS << "#define CONSTANTS_ARRAY_LENGTH " << (properties.has_indexed_constants ? 468 : ::size32(m_constant_ids)) << "\n\n"; - in.location = m_binding_table.instancing_constants_buffer_slot; + in.location = vk_prog->binding_table.instanced_cbuf_location; in.domain = glsl::glsl_vertex_program; in.name = "VertexConstantsBuffer"; in.type = vk::glsl::input_type_storage_buffer; @@ -166,7 +224,8 @@ void VKVertexDecompilerThread::insertConstants(std::stringstream & OS, const std PT.type == "sampler1D" || PT.type == "sampler3D") { - in.location = location; + const int id = vk::get_texture_index(PI.name); + in.location = vk_prog->binding_table.vtex_location[id]; in.name = PI.name; in.type = vk::glsl::input_type_texture; @@ -190,7 +249,7 @@ void VKVertexDecompilerThread::insertConstants(std::stringstream & OS, const std } } - OS << "layout(set = 0, binding=" << location++ << ") uniform " << samplerType << " " << PI.name << ";\n"; + OS << "layout(set = 0, binding=" << in.location << ") uniform " << samplerType << " " << PI.name << ";\n"; } } } @@ -371,8 +430,6 @@ void VKVertexDecompilerThread::insertMainEnd(std::stringstream & OS) void VKVertexDecompilerThread::Task() { m_device_props.emulate_conditional_rendering = vk::emulate_conditional_rendering(); - m_binding_table = vk::g_render_device->get_pipeline_binding_table(); - m_shader = Decompile(); vk_prog->SetInputs(inputs); } diff --git a/rpcs3/Emu/RSX/VK/VKVertexProgram.h b/rpcs3/Emu/RSX/VK/VKVertexProgram.h index 1bb6dfd91c..3422333fc6 100644 --- a/rpcs3/Emu/RSX/VK/VKVertexProgram.h +++ b/rpcs3/Emu/RSX/VK/VKVertexProgram.h @@ -15,7 +15,6 @@ struct VKVertexDecompilerThread : public VertexProgramDecompiler std::string &m_shader; std::vector inputs; class VKVertexProgram *vk_prog; - vk::pipeline_binding_table m_binding_table{}; struct { @@ -36,6 +35,8 @@ protected: void insertMainStart(std::stringstream &OS) override; void insertMainEnd(std::stringstream &OS) override; + void prepareBindingTable(); + const RSXVertexProgram &rsx_vertex_program; public: VKVertexDecompilerThread(const RSXVertexProgram &prog, std::string& shader, ParamArray&, class VKVertexProgram &dst) @@ -61,6 +62,19 @@ public: vk::glsl::shader shader; std::vector uniforms; + // Quick attribute indices + struct + { + u32 context_buffer_location = umax; // Vertex program context + u32 cr_pred_buffer_location = umax; // Conditional rendering predicate + u32 vertex_buffers_location = umax; // Vertex input streams (3) + u32 cbuf_location = umax; // Vertex program constants register file + u32 instanced_lut_buffer_location = umax; // Instancing redirection table + u32 instanced_cbuf_location = umax; // Instancing constants register file + u32 vtex_location[4]; // Vertex textures (inf) + + } binding_table; + void Decompile(const RSXVertexProgram& prog); void Compile(); void SetInputs(std::vector& inputs); diff --git a/rpcs3/Emu/RSX/VK/upscalers/fsr1/fsr_pass.cpp b/rpcs3/Emu/RSX/VK/upscalers/fsr1/fsr_pass.cpp index d0b972765c..01a05bf598 100644 --- a/rpcs3/Emu/RSX/VK/upscalers/fsr1/fsr_pass.cpp +++ b/rpcs3/Emu/RSX/VK/upscalers/fsr1/fsr_pass.cpp @@ -76,6 +76,7 @@ namespace vk ::glsl::program_domain::glsl_compute_program, "InputTexture", vk::glsl::input_type_texture, + 0, 0 ), @@ -83,6 +84,7 @@ namespace vk ::glsl::program_domain::glsl_compute_program, "OutputTexture", vk::glsl::input_type_storage_texture, + 0, 1 ), }; @@ -103,8 +105,8 @@ namespace vk VK_FALSE, 0.f, 1.f, 0.f, 0.f, VK_FILTER_LINEAR, VK_FILTER_LINEAR, VK_SAMPLER_MIPMAP_MODE_NEAREST, VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK); } - m_program->bind_uniform({ m_sampler->value, m_input_image->value, m_input_image->image()->current_layout }, "InputTexture", VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER); - m_program->bind_uniform({ VK_NULL_HANDLE, m_output_image->value, m_output_image->image()->current_layout }, "OutputTexture", VK_DESCRIPTOR_TYPE_STORAGE_IMAGE); + m_program->bind_uniform({ m_sampler->value, m_input_image->value, m_input_image->image()->current_layout }, 0, 0); + m_program->bind_uniform({ VK_NULL_HANDLE, m_output_image->value, m_output_image->image()->current_layout }, 0, 1); } void fsr_pass::run(const vk::command_buffer& cmd, vk::viewable_image* src, vk::viewable_image* dst, const size2u& input_size, const size2u& output_size) diff --git a/rpcs3/Emu/RSX/VK/vkutils/descriptors.cpp b/rpcs3/Emu/RSX/VK/vkutils/descriptors.cpp index 7293180e08..9bc57b0987 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/descriptors.cpp +++ b/rpcs3/Emu/RSX/VK/vkutils/descriptors.cpp @@ -333,11 +333,6 @@ namespace vk return &m_handle; } - VkDescriptorSet descriptor_set::value() const - { - return m_handle; - } - void descriptor_set::push(const VkBufferView& buffer_view, VkDescriptorType type, u32 binding) { m_push_type_mask |= (1ull << type); diff --git a/rpcs3/Emu/RSX/VK/vkutils/descriptors.h b/rpcs3/Emu/RSX/VK/vkutils/descriptors.h index 6c61488b6e..9fd0b436a9 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/descriptors.h +++ b/rpcs3/Emu/RSX/VK/vkutils/descriptors.h @@ -94,8 +94,10 @@ namespace vk void swap(descriptor_set& other); descriptor_set& operator = (VkDescriptorSet set); + VkDescriptorSet value() const { return m_handle; } + operator bool() const { return m_handle != VK_NULL_HANDLE; } + VkDescriptorSet* ptr(); - VkDescriptorSet value() const; void push(const VkBufferView& buffer_view, VkDescriptorType type, u32 binding); void push(const VkDescriptorBufferInfo& buffer_info, VkDescriptorType type, u32 binding); void push(const VkDescriptorImageInfo& image_info, VkDescriptorType type, u32 binding); From aac4fbe941c6cebb6a298cb3a3702db08fcc6dca Mon Sep 17 00:00:00 2001 From: kd-11 Date: Thu, 12 Jun 2025 14:35:00 +0300 Subject: [PATCH 05/37] vk: Fix graphical bugs and crashes --- rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp | 21 +++++++++------------ rpcs3/Emu/RSX/VK/VKGSRender.cpp | 6 +++++- rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp | 20 +++++++++++++------- rpcs3/Emu/RSX/VK/VKProgramPipeline.h | 1 + rpcs3/Emu/RSX/VK/VKVertexProgram.cpp | 11 ++++------- rpcs3/Emu/RSX/VK/vkutils/descriptors.cpp | 3 ++- 6 files changed, 34 insertions(+), 28 deletions(-) diff --git a/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp b/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp index 25f4297dee..dc5ff8640f 100644 --- a/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp +++ b/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp @@ -176,7 +176,7 @@ void VKFragmentDecompilerThread::insertConstants(std::stringstream & OS) { for (const ParamType& PT : m_parr.params[PF_PARAM_UNIFORM]) { - if (PT.type.starts_with("sampler1D")) + if (!PT.type.starts_with("sampler")) { continue; } @@ -219,7 +219,7 @@ void VKFragmentDecompilerThread::insertConstants(std::stringstream & OS) ); inputs.push_back(in); - OS << "layout(set=0, binding=" << in.location << ") uniform " << samplerType << " " << PI.name << ";\n"; + OS << "layout(set=1, binding=" << in.location << ") uniform " << samplerType << " " << PI.name << ";\n"; if (properties.redirected_sampler_mask & mask) { @@ -228,7 +228,7 @@ void VKFragmentDecompilerThread::insertConstants(std::stringstream & OS) in.location = vk_prog->binding_table.ftex_stencil_location[id]; inputs.push_back(in); - OS << "layout(set=0, binding=" << in.location << ") uniform u" << samplerType << " " << in.name << ";\n"; + OS << "layout(set=1, binding=" << in.location << ") uniform u" << samplerType << " " << in.name << ";\n"; } } } @@ -236,7 +236,7 @@ void VKFragmentDecompilerThread::insertConstants(std::stringstream & OS) std::string constants_block; for (const ParamType& PT : m_parr.params[PF_PARAM_UNIFORM]) { - if (PT.type.starts_with("sampler1D")) + if (PT.type.starts_with("sampler")) { continue; } @@ -249,13 +249,13 @@ void VKFragmentDecompilerThread::insertConstants(std::stringstream & OS) if (!constants_block.empty()) { - OS << "layout(std140, set = 1, binding = " << vk_prog->binding_table.cbuf_location << ") uniform FragmentConstantsBuffer\n"; + OS << "layout(std140, set=1, binding=" << vk_prog->binding_table.cbuf_location << ") uniform FragmentConstantsBuffer\n"; OS << "{\n"; OS << constants_block; OS << "};\n\n"; } - OS << "layout(std140, set = 1, binding = " << vk_prog->binding_table.context_buffer_location << ") uniform FragmentStateBuffer\n"; + OS << "layout(std140, set=1, binding=" << vk_prog->binding_table.context_buffer_location << ") uniform FragmentStateBuffer\n"; OS << "{\n"; OS << " float fog_param0;\n"; OS << " float fog_param1;\n"; @@ -267,12 +267,12 @@ void VKFragmentDecompilerThread::insertConstants(std::stringstream & OS) OS << " float wpos_bias;\n"; OS << "};\n\n"; - OS << "layout(std140, set = 1, binding = " << vk_prog->binding_table.tex_param_location << ") uniform TextureParametersBuffer\n"; + OS << "layout(std140, set=1, binding=" << vk_prog->binding_table.tex_param_location << ") uniform TextureParametersBuffer\n"; OS << "{\n"; OS << " sampler_info texture_parameters[16];\n"; OS << "};\n\n"; - OS << "layout(std140, set = 1, binding = " << vk_prog->binding_table.polygon_stipple_params_location << ") uniform RasterizerHeap\n"; + OS << "layout(std140, set=1, binding=" << vk_prog->binding_table.polygon_stipple_params_location << ") uniform RasterizerHeap\n"; OS << "{\n"; OS << " uvec4 stipple_pattern[8];\n"; OS << "};\n\n"; @@ -484,10 +484,7 @@ void VKFragmentProgram::Decompile(const RSXFragmentProgram& prog) { for (const ParamItem& PI : PT.items) { - if (PT.type == "sampler1D" || - PT.type == "sampler2D" || - PT.type == "sampler3D" || - PT.type == "samplerCube") + if (PT.type.starts_with("sampler")) continue; usz offset = atoi(PI.name.c_str() + 2); diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index d64551f7e9..c1d560a637 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -2078,11 +2078,15 @@ void VKGSRender::load_program_env() const auto& fs_binding_table = m_fragment_prog->binding_table; m_program->bind_uniform(m_vertex_env_buffer_info, vk::glsl::binding_set_index_vertex, vs_binding_table.context_buffer_location); - m_program->bind_uniform(m_vertex_constants_buffer_info, vk::glsl::binding_set_index_vertex, vs_binding_table.cbuf_location); m_program->bind_uniform(m_fragment_env_buffer_info, vk::glsl::binding_set_index_fragment, fs_binding_table.context_buffer_location); m_program->bind_uniform(m_fragment_texture_params_buffer_info, vk::glsl::binding_set_index_fragment, fs_binding_table.tex_param_location); m_program->bind_uniform(m_raster_env_buffer_info, vk::glsl::binding_set_index_fragment, fs_binding_table.polygon_stipple_params_location); + if (vs_binding_table.cbuf_location != umax) + { + m_program->bind_uniform(m_vertex_constants_buffer_info, vk::glsl::binding_set_index_vertex, vs_binding_table.cbuf_location); + } + if (m_shader_interpreter.is_interpreter(m_program)) { m_program->bind_uniform(m_vertex_instructions_buffer_info, vk::glsl::binding_set_index_vertex, m_shader_interpreter.get_vertex_instruction_location()); diff --git a/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp b/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp index 5ac4bd9c26..27caf615d2 100644 --- a/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp +++ b/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp @@ -211,6 +211,11 @@ namespace vk auto& sink = m_sets[0]; for (auto& set : m_sets) { + if (&set == &sink) + { + continue; + } + for (auto& type_arr : set.m_inputs) { if (type_arr.empty()) @@ -279,6 +284,8 @@ namespace vk return u.name == uniform_name; }); } + + return false; } std::pair program::get_uniform_location(::glsl::program_domain domain, program_input_type type, const std::string& uniform_name) @@ -441,8 +448,8 @@ namespace vk { if (!m_descriptor_pool) { - create_descriptor_pool(); create_descriptor_set_layout(); + create_descriptor_pool(); } return m_descriptor_pool->allocate(m_descriptor_set_layout); @@ -463,9 +470,6 @@ namespace vk return; } - auto old_set = m_descriptor_set.value(); - auto new_set = allocate_descriptor_set(); - auto push_descriptor_slot = [this](unsigned idx) { const auto& slot = m_descriptor_slots[idx]; @@ -504,16 +508,18 @@ namespace vk m_copy_cmds.push_back({ .sType = VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET, - .srcSet = old_set, + .srcSet = m_previous_set, .srcBinding = i, - .dstSet = new_set, + .dstSet = m_descriptor_set.value(), .dstBinding = i, .descriptorCount = 1 }); } m_descriptor_set.push(m_copy_cmds); // Write previous state - m_descriptor_set = new_set; + + m_previous_set = m_descriptor_set.value(); + m_descriptor_set = allocate_descriptor_set(); } void descriptor_table_t::create_descriptor_set_layout() diff --git a/rpcs3/Emu/RSX/VK/VKProgramPipeline.h b/rpcs3/Emu/RSX/VK/VKProgramPipeline.h index 96940a8efe..785a7f9529 100644 --- a/rpcs3/Emu/RSX/VK/VKProgramPipeline.h +++ b/rpcs3/Emu/RSX/VK/VKProgramPipeline.h @@ -121,6 +121,7 @@ namespace vk vk::descriptor_set m_descriptor_set{}; rsx::simple_array m_descriptor_pool_sizes; rsx::simple_array m_descriptor_types; + VkDescriptorSet m_previous_set = VK_NULL_HANDLE; std::vector m_descriptor_slots; std::vector m_descriptors_dirty; diff --git a/rpcs3/Emu/RSX/VK/VKVertexProgram.cpp b/rpcs3/Emu/RSX/VK/VKVertexProgram.cpp index b6def63136..a45eb0e2bc 100644 --- a/rpcs3/Emu/RSX/VK/VKVertexProgram.cpp +++ b/rpcs3/Emu/RSX/VK/VKVertexProgram.cpp @@ -76,7 +76,7 @@ void VKVertexDecompilerThread::insertHeader(std::stringstream &OS) "#extension GL_ARB_separate_shader_objects : enable\n\n"; OS << - "layout(std140, set = 0, binding = " << vk_prog->binding_table.context_buffer_location << " ) uniform VertexContextBuffer\n" + "layout(std140, set=0, binding=" << vk_prog->binding_table.context_buffer_location << ") uniform VertexContextBuffer\n" "{\n" " mat4 scale_offset_mat;\n" " ivec4 user_clip_enabled[2];\n" @@ -99,7 +99,7 @@ void VKVertexDecompilerThread::insertHeader(std::stringstream &OS) if (m_device_props.emulate_conditional_rendering) { OS << - "layout(std430, set = 0, binding = " << vk_prog->binding_table.cr_pred_buffer_location << ") readonly buffer EXT_Conditional_Rendering\n" + "layout(std430, set=0, binding=" << vk_prog->binding_table.cr_pred_buffer_location << ") readonly buffer EXT_Conditional_Rendering\n" "{\n" " uint conditional_rendering_predicate;\n" "};\n\n"; @@ -219,10 +219,7 @@ void VKVertexDecompilerThread::insertConstants(std::stringstream & OS, const std } } - if (PT.type == "sampler2D" || - PT.type == "samplerCube" || - PT.type == "sampler1D" || - PT.type == "sampler3D") + if (PT.type.starts_with("sampler")) { const int id = vk::get_texture_index(PI.name); in.location = vk_prog->binding_table.vtex_location[id]; @@ -249,7 +246,7 @@ void VKVertexDecompilerThread::insertConstants(std::stringstream & OS, const std } } - OS << "layout(set = 0, binding=" << in.location << ") uniform " << samplerType << " " << PI.name << ";\n"; + OS << "layout(set=0, binding=" << in.location << ") uniform " << samplerType << " " << PI.name << ";\n"; } } } diff --git a/rpcs3/Emu/RSX/VK/vkutils/descriptors.cpp b/rpcs3/Emu/RSX/VK/vkutils/descriptors.cpp index 9bc57b0987..c8673d4517 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/descriptors.cpp +++ b/rpcs3/Emu/RSX/VK/vkutils/descriptors.cpp @@ -435,7 +435,8 @@ namespace vk void descriptor_set::bind(const vk::command_buffer& cmd, VkPipelineBindPoint bind_point, VkPipelineLayout layout) { - if ((m_push_type_mask & ~m_update_after_bind_mask) || (m_pending_writes.size() >= max_cache_size)) + if ((m_push_type_mask & ~m_update_after_bind_mask) || + (m_pending_writes.size() >= max_cache_size)) { flush(); } From 20b54f308687b66f5a93ac55e9844ad13131c715 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Thu, 12 Jun 2025 14:58:03 +0300 Subject: [PATCH 06/37] vk: Correctly initialize descriptor copy data --- rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp b/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp index 27caf615d2..fb8450a166 100644 --- a/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp +++ b/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp @@ -496,6 +496,8 @@ namespace vk }; m_copy_cmds.clear(); + rsx::flags32_t type_mask = 0u; + for (unsigned i = 0; i < m_descriptor_slots.size(); ++i) { if (m_descriptors_dirty[i]) @@ -514,9 +516,11 @@ namespace vk .dstBinding = i, .descriptorCount = 1 }); + + type_mask |= (1u << m_descriptor_types[i]); } - m_descriptor_set.push(m_copy_cmds); // Write previous state + m_descriptor_set.push(m_copy_cmds, type_mask); // Write previous state m_previous_set = m_descriptor_set.value(); m_descriptor_set = allocate_descriptor_set(); From 64866098e732ed2cfa548796b7934d670ed6e335 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Thu, 12 Jun 2025 23:00:41 +0300 Subject: [PATCH 07/37] vk: Respect shader compile flags when linking --- rpcs3/Emu/RSX/VK/VKPipelineCompiler.cpp | 29 ++++++++++++++----------- rpcs3/Emu/RSX/VK/VKPipelineCompiler.h | 18 ++++++++++++--- 2 files changed, 31 insertions(+), 16 deletions(-) diff --git a/rpcs3/Emu/RSX/VK/VKPipelineCompiler.cpp b/rpcs3/Emu/RSX/VK/VKPipelineCompiler.cpp index 884841ec4b..26e0b64098 100644 --- a/rpcs3/Emu/RSX/VK/VKPipelineCompiler.cpp +++ b/rpcs3/Emu/RSX/VK/VKPipelineCompiler.cpp @@ -36,12 +36,12 @@ namespace vk { if (job.is_graphics_job) { - auto compiled = int_compile_graphics_pipe(job.graphics_data, job.graphics_modules, job.inputs, {}); + auto compiled = int_compile_graphics_pipe(job.graphics_data, job.graphics_modules, job.inputs, {}, job.flags); job.callback_func(compiled); } else { - auto compiled = int_compile_compute_pipe(job.compute_data, job.inputs); + auto compiled = int_compile_compute_pipe(job.compute_data, job.inputs, job.flags); job.callback_func(compiled); } } @@ -52,20 +52,22 @@ namespace vk std::unique_ptr pipe_compiler::int_compile_compute_pipe( const VkComputePipelineCreateInfo& create_info, - const std::vector& cs_inputs) + const std::vector& cs_inputs, + op_flags flags) { auto program = std::make_unique(*m_device, create_info, cs_inputs); - program->link(false); + program->link(flags & SEPARATE_SHADER_OBJECTS); return program; } std::unique_ptr pipe_compiler::int_compile_graphics_pipe( const VkGraphicsPipelineCreateInfo& create_info, const std::vector& vs_inputs, - const std::vector& fs_inputs) + const std::vector& fs_inputs, + op_flags flags) { auto program = std::make_unique(*m_device, create_info, vs_inputs, fs_inputs); - program->link(true); + program->link(flags & SEPARATE_SHADER_OBJECTS); return program; } @@ -73,7 +75,8 @@ namespace vk const vk::pipeline_props &create_info, VkShaderModule modules[2], const std::vector& vs_inputs, - const std::vector& fs_inputs) + const std::vector& fs_inputs, + op_flags flags) { VkPipelineShaderStageCreateInfo shader_stages[2] = {}; shader_stages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; @@ -167,7 +170,7 @@ namespace vk info.basePipelineHandle = VK_NULL_HANDLE; info.renderPass = vk::get_renderpass(*m_device, create_info.renderpass_key); - return int_compile_graphics_pipe(info, vs_inputs, fs_inputs); + return int_compile_graphics_pipe(info, vs_inputs, fs_inputs, flags); } std::unique_ptr pipe_compiler::compile( @@ -177,10 +180,10 @@ namespace vk { if (flags & COMPILE_INLINE) { - return int_compile_compute_pipe(create_info, cs_inputs); + return int_compile_compute_pipe(create_info, cs_inputs, flags); } - m_work_queue.push(create_info, cs_inputs, callback); + m_work_queue.push(create_info, cs_inputs, flags, callback); return {}; } @@ -192,7 +195,7 @@ namespace vk { // It is very inefficient to defer this as all pointers need to be saved ensure(flags & COMPILE_INLINE); - return int_compile_graphics_pipe(create_info, vs_inputs, fs_inputs); + return int_compile_graphics_pipe(create_info, vs_inputs, fs_inputs, flags); } std::unique_ptr pipe_compiler::compile( @@ -206,10 +209,10 @@ namespace vk VkShaderModule modules[] = { vs, fs }; if (flags & COMPILE_INLINE) { - return int_compile_graphics_pipe(create_info, modules, vs_inputs, fs_inputs); + return int_compile_graphics_pipe(create_info, modules, vs_inputs, fs_inputs, flags); } - m_work_queue.push(create_info, modules, vs_inputs, fs_inputs, callback); + m_work_queue.push(create_info, modules, vs_inputs, fs_inputs, flags, callback); return {}; } diff --git a/rpcs3/Emu/RSX/VK/VKPipelineCompiler.h b/rpcs3/Emu/RSX/VK/VKPipelineCompiler.h index 25c0b8e1c0..762e8aadfc 100644 --- a/rpcs3/Emu/RSX/VK/VKPipelineCompiler.h +++ b/rpcs3/Emu/RSX/VK/VKPipelineCompiler.h @@ -117,11 +117,14 @@ namespace vk VkShaderModule graphics_modules[2]; std::vector inputs; + op_flags flags; + pipe_compiler_job( const vk::pipeline_props& props, VkShaderModule modules[2], const std::vector& vs_in, const std::vector& fs_in, + op_flags flags_, callback_t func) { callback_func = func; @@ -129,6 +132,7 @@ namespace vk graphics_modules[0] = modules[0]; graphics_modules[1] = modules[1]; is_graphics_job = true; + flags = flags_; inputs.reserve(vs_in.size() + fs_in.size()); inputs.insert(inputs.end(), vs_in.begin(), vs_in.end()); @@ -138,11 +142,16 @@ namespace vk pipe_compiler_job( const VkComputePipelineCreateInfo& props, const std::vector& cs_in, + op_flags flags_, callback_t func) { callback_func = func; compute_data = props; is_graphics_job = false; + flags = flags_; + + graphics_modules[0] = VK_NULL_HANDLE; + graphics_modules[1] = VK_NULL_HANDLE; inputs = cs_in; } @@ -153,18 +162,21 @@ namespace vk std::unique_ptr int_compile_compute_pipe( const VkComputePipelineCreateInfo& create_info, - const std::vector& cs_inputs); + const std::vector& cs_inputs, + op_flags flags); std::unique_ptr int_compile_graphics_pipe( const VkGraphicsPipelineCreateInfo& create_info, const std::vector& vs_inputs, - const std::vector& fs_inputs); + const std::vector& fs_inputs, + op_flags flags); std::unique_ptr int_compile_graphics_pipe( const vk::pipeline_props &create_info, VkShaderModule modules[2], const std::vector& vs_inputs, - const std::vector& fs_inputs); + const std::vector& fs_inputs, + op_flags flags); }; void initialize_pipe_compiler(int num_worker_threads = -1); From ae74aa336f7f220a921d8796ac3d0daeda913e85 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Thu, 12 Jun 2025 23:21:14 +0300 Subject: [PATCH 08/37] vk: Use write commands instead of copy commands to avoid dependencies --- rpcs3/Emu/RSX/VK/VKProgramBuffer.h | 4 +++- rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp | 12 ++++++------ rpcs3/Emu/RSX/VK/VKProgramPipeline.h | 3 +-- rpcs3/Emu/RSX/VK/vkutils/descriptors.cpp | 17 +++++++++++++++++ rpcs3/Emu/RSX/VK/vkutils/descriptors.h | 1 + 5 files changed, 28 insertions(+), 9 deletions(-) diff --git a/rpcs3/Emu/RSX/VK/VKProgramBuffer.h b/rpcs3/Emu/RSX/VK/VKProgramBuffer.h index 647b21adc4..3e4ee000df 100644 --- a/rpcs3/Emu/RSX/VK/VKProgramBuffer.h +++ b/rpcs3/Emu/RSX/VK/VKProgramBuffer.h @@ -48,7 +48,9 @@ namespace vk bool compile_async, std::function callback) { - const auto compiler_flags = compile_async ? vk::pipe_compiler::COMPILE_DEFERRED : vk::pipe_compiler::COMPILE_INLINE; + vk::pipe_compiler::op_flags compiler_flags = compile_async ? vk::pipe_compiler::COMPILE_DEFERRED : vk::pipe_compiler::COMPILE_INLINE; + compiler_flags |= vk::pipe_compiler::SEPARATE_SHADER_OBJECTS; + auto compiler = vk::get_pipe_compiler(); auto result = compiler->compile( pipelineProperties, diff --git a/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp b/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp index fb8450a166..8ad89bc4a9 100644 --- a/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp +++ b/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp @@ -509,20 +509,20 @@ namespace vk } m_copy_cmds.push_back({ - .sType = VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET, - .srcSet = m_previous_set, - .srcBinding = i, + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, .dstSet = m_descriptor_set.value(), .dstBinding = i, - .descriptorCount = 1 + .descriptorCount = 1, + .descriptorType = m_descriptor_types[i], + .pImageInfo = std::get_if(&m_descriptor_slots[i]), + .pBufferInfo = std::get_if(&m_descriptor_slots[i]), + .pTexelBufferView = std::get_if(&m_descriptor_slots[i]) }); type_mask |= (1u << m_descriptor_types[i]); } m_descriptor_set.push(m_copy_cmds, type_mask); // Write previous state - - m_previous_set = m_descriptor_set.value(); m_descriptor_set = allocate_descriptor_set(); } diff --git a/rpcs3/Emu/RSX/VK/VKProgramPipeline.h b/rpcs3/Emu/RSX/VK/VKProgramPipeline.h index 785a7f9529..d0f06e2a80 100644 --- a/rpcs3/Emu/RSX/VK/VKProgramPipeline.h +++ b/rpcs3/Emu/RSX/VK/VKProgramPipeline.h @@ -121,11 +121,10 @@ namespace vk vk::descriptor_set m_descriptor_set{}; rsx::simple_array m_descriptor_pool_sizes; rsx::simple_array m_descriptor_types; - VkDescriptorSet m_previous_set = VK_NULL_HANDLE; std::vector m_descriptor_slots; std::vector m_descriptors_dirty; - rsx::simple_array m_copy_cmds; + rsx::simple_array m_copy_cmds; bool m_any_descriptors_dirty = false; void init(VkDevice dev); diff --git a/rpcs3/Emu/RSX/VK/vkutils/descriptors.cpp b/rpcs3/Emu/RSX/VK/vkutils/descriptors.cpp index c8673d4517..5a2ad92dab 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/descriptors.cpp +++ b/rpcs3/Emu/RSX/VK/vkutils/descriptors.cpp @@ -422,6 +422,23 @@ namespace vk } } + void descriptor_set::push(rsx::simple_array& write_cmds, u32 type_mask) + { + m_push_type_mask |= type_mask; + + if (m_pending_writes.empty()) [[unlikely]] + { + m_pending_writes = std::move(write_cmds); + } + else + { + const auto old_size = m_pending_writes.size(); + const auto new_size = write_cmds.size() + old_size; + m_pending_writes.resize(new_size); + std::copy(write_cmds.begin(), write_cmds.end(), m_pending_writes.begin() + old_size); + } + } + void descriptor_set::push(const descriptor_set_dynamic_offset_t& offset) { ensure(offset.location >= 0 && offset.location <= 16); diff --git a/rpcs3/Emu/RSX/VK/vkutils/descriptors.h b/rpcs3/Emu/RSX/VK/vkutils/descriptors.h index 9fd0b436a9..c3e67302ae 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/descriptors.h +++ b/rpcs3/Emu/RSX/VK/vkutils/descriptors.h @@ -103,6 +103,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& copy_cmd, u32 type_mask = umax); + void push(rsx::simple_array& write_cmds, 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); From 93e6aa63100311de368cf27b490261250f0238b0 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Fri, 13 Jun 2025 00:51:58 +0300 Subject: [PATCH 09/37] vk: Fix FSR upscaling --- rpcs3/Emu/RSX/VK/upscalers/fsr1/fsr_pass.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/rpcs3/Emu/RSX/VK/upscalers/fsr1/fsr_pass.cpp b/rpcs3/Emu/RSX/VK/upscalers/fsr1/fsr_pass.cpp index 01a05bf598..589defd3e8 100644 --- a/rpcs3/Emu/RSX/VK/upscalers/fsr1/fsr_pass.cpp +++ b/rpcs3/Emu/RSX/VK/upscalers/fsr1/fsr_pass.cpp @@ -61,6 +61,9 @@ namespace vk // Fill with 0 to avoid sending incomplete/unused variables to the GPU memset(m_constants_buf, 0, sizeof(m_constants_buf)); + // No ssbo usage + ssbo_count = 0; + // Enable push constants use_push_constants = true; push_constants_size = push_constants_size_; @@ -116,6 +119,11 @@ namespace vk m_input_size = input_size; m_output_size = output_size; + if (!m_program) + { + load_program(cmd); + } + configure(cmd); constexpr auto wg_size = 16; From 2ae9753d7944c5f1dc721c278c13d3f92ece1a75 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Fri, 13 Jun 2025 13:15:22 +0300 Subject: [PATCH 10/37] vk: Lazy register/derigeter of hot data --- rpcs3/Emu/RSX/VK/VKCompute.cpp | 5 +++ rpcs3/Emu/RSX/VK/VKCompute.h | 5 +++ rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp | 3 +- rpcs3/Emu/RSX/VK/vkutils/descriptors.cpp | 50 +++++++++++++----------- rpcs3/Emu/RSX/VK/vkutils/descriptors.h | 1 + 5 files changed, 40 insertions(+), 24 deletions(-) diff --git a/rpcs3/Emu/RSX/VK/VKCompute.cpp b/rpcs3/Emu/RSX/VK/VKCompute.cpp index c164edddd7..6f676e60c9 100644 --- a/rpcs3/Emu/RSX/VK/VKCompute.cpp +++ b/rpcs3/Emu/RSX/VK/VKCompute.cpp @@ -250,6 +250,11 @@ namespace vk void cs_shuffle_base::set_parameters(const vk::command_buffer& cmd, const u32* params, u8 count) { + if (!m_program) + { + load_program(cmd); + } + ensure(use_push_constants); vkCmdPushConstants(cmd, m_program->layout(), VK_SHADER_STAGE_COMPUTE_BIT, 0, count * 4, params); } diff --git a/rpcs3/Emu/RSX/VK/VKCompute.h b/rpcs3/Emu/RSX/VK/VKCompute.h index fa053afe50..9ffeb1ca7f 100644 --- a/rpcs3/Emu/RSX/VK/VKCompute.h +++ b/rpcs3/Emu/RSX/VK/VKCompute.h @@ -451,6 +451,11 @@ namespace vk void set_parameters(const vk::command_buffer& cmd) { + if (!m_program) + { + load_program(cmd); + } + vkCmdPushConstants(cmd, m_program->layout(), VK_SHADER_STAGE_COMPUTE_BIT, 0, push_constants_size, params.data); } diff --git a/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp b/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp index 8ad89bc4a9..c03a9e7b00 100644 --- a/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp +++ b/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp @@ -402,7 +402,8 @@ namespace vk break; } - bind_sets[count++] = set.m_descriptor_set.value(); // Current set pointer for binding + bind_sets[count++] = set.m_descriptor_set.value(); // Current set pointer for binding + set.m_descriptor_set.on_bind(); // Notify async queue set.next_descriptor_set(); // Flush queue and update pointers } diff --git a/rpcs3/Emu/RSX/VK/vkutils/descriptors.cpp b/rpcs3/Emu/RSX/VK/vkutils/descriptors.cpp index 5a2ad92dab..ebe94fd8d3 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/descriptors.cpp +++ b/rpcs3/Emu/RSX/VK/vkutils/descriptors.cpp @@ -14,44 +14,37 @@ namespace vk public: inline void flush_all() { + reader_lock lock(m_notifications_lock); + for (auto& set : m_notification_list) { set->flush(); } + + m_notification_list.clear(); } void register_(descriptor_set* set) { - // Rare event, upon creation of a new set tracker. - // Check for spurious 'new' events when the aux context is taking over - for (const auto& set_ : m_notification_list) - { - if (set_ == set) return; - } + std::lock_guard lock(m_notifications_lock); m_notification_list.push_back(set); - rsx_log.warning("[descriptor_manager::register] Now monitoring %u descriptor sets", m_notification_list.size()); + // rsx_log.notice("[descriptor_manager::register] Now monitoring %u descriptor sets", m_notification_list.size()); } void deregister(descriptor_set* set) { - for (auto it = m_notification_list.begin(); it != m_notification_list.end(); ++it) - { - if (*it == set) - { - *it = m_notification_list.back(); - m_notification_list.pop_back(); - break; - } - } + std::lock_guard lock(m_notifications_lock); - rsx_log.warning("[descriptor_manager::deregister] Now monitoring %u descriptor sets", m_notification_list.size()); + m_notification_list.erase_if(FN(x == set)); + // rsx_log.notice("[descriptor_manager::deregister] Now monitoring %u descriptor sets", m_notification_list.size()); } dispatch_manager() = default; private: rsx::simple_array m_notification_list; + shared_mutex m_notifications_lock; dispatch_manager(const dispatch_manager&) = delete; dispatch_manager& operator = (const dispatch_manager&) = delete; @@ -295,11 +288,6 @@ namespace vk m_in_use = true; m_update_after_bind_mask = g_render_device->get_descriptor_update_after_bind_support(); - - if (m_update_after_bind_mask) - { - g_fxo->get().register_(this); - } } else if (m_push_type_mask & ~m_update_after_bind_mask) { @@ -450,13 +438,29 @@ namespace vk m_dynamic_offsets[offset.location] = offset.value; } - void descriptor_set::bind(const vk::command_buffer& cmd, VkPipelineBindPoint bind_point, VkPipelineLayout layout) + void descriptor_set::on_bind() { + if (!m_push_type_mask) + { + return; + } + + // We have queued writes if ((m_push_type_mask & ~m_update_after_bind_mask) || (m_pending_writes.size() >= max_cache_size)) { flush(); } + else if (m_update_after_bind_mask) + { + // Register for async flush + g_fxo->get().register_(this); + } + } + + void descriptor_set::bind(const vk::command_buffer& cmd, VkPipelineBindPoint bind_point, VkPipelineLayout layout) + { + on_bind(); vkCmdBindDescriptorSets(cmd, bind_point, layout, 0, 1, &m_handle, ::size32(m_dynamic_offsets), m_dynamic_offsets.data()); } diff --git a/rpcs3/Emu/RSX/VK/vkutils/descriptors.h b/rpcs3/Emu/RSX/VK/vkutils/descriptors.h index c3e67302ae..556fe5d0b9 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/descriptors.h +++ b/rpcs3/Emu/RSX/VK/vkutils/descriptors.h @@ -106,6 +106,7 @@ namespace vk void push(rsx::simple_array& write_cmds, u32 type_mask = umax); void push(const descriptor_set_dynamic_offset_t& offset); + void on_bind(); void bind(const vk::command_buffer& cmd, VkPipelineBindPoint bind_point, VkPipelineLayout layout); void flush(); From 2c8c788d8156bc179ab31010d2970c21e4eeca73 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Fri, 13 Jun 2025 13:44:46 +0300 Subject: [PATCH 11/37] vk: Use standard C++ --- rpcs3/Emu/RSX/VK/vkutils/descriptors.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rpcs3/Emu/RSX/VK/vkutils/descriptors.cpp b/rpcs3/Emu/RSX/VK/vkutils/descriptors.cpp index ebe94fd8d3..d8e8fcd7ff 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/descriptors.cpp +++ b/rpcs3/Emu/RSX/VK/vkutils/descriptors.cpp @@ -14,7 +14,7 @@ namespace vk public: inline void flush_all() { - reader_lock lock(m_notifications_lock); + std::shared_lock lock(m_notifications_lock); for (auto& set : m_notification_list) { @@ -44,7 +44,7 @@ namespace vk private: rsx::simple_array m_notification_list; - shared_mutex m_notifications_lock; + std::shared_mutex m_notifications_lock; dispatch_manager(const dispatch_manager&) = delete; dispatch_manager& operator = (const dispatch_manager&) = delete; From f241825c730b0284159a06db58dd56dd6e4530d0 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Sun, 15 Jun 2025 14:21:25 +0300 Subject: [PATCH 12/37] vk: Update binding model for compute jobs --- rpcs3/Emu/RSX/Common/simple_array.hpp | 5 +++ rpcs3/Emu/RSX/VK/VKCompute.cpp | 23 +++++++------- rpcs3/Emu/RSX/VK/VKCompute.h | 33 ++++++++++---------- rpcs3/Emu/RSX/VK/VKResolveHelper.h | 2 +- rpcs3/Emu/RSX/VK/upscalers/fsr1/fsr_pass.cpp | 2 +- rpcs3/Emu/RSX/VK/upscalers/fsr_pass.h | 2 +- rpcs3/Emu/RSX/VK/vkutils/descriptors.cpp | 22 +++++++------ 7 files changed, 47 insertions(+), 42 deletions(-) diff --git a/rpcs3/Emu/RSX/Common/simple_array.hpp b/rpcs3/Emu/RSX/Common/simple_array.hpp index dfec324eeb..06e0b1870d 100644 --- a/rpcs3/Emu/RSX/Common/simple_array.hpp +++ b/rpcs3/Emu/RSX/Common/simple_array.hpp @@ -305,6 +305,11 @@ namespace rsx return _size * sizeof(Ty); } + u32 size_bytes32() const + { + return _size * sizeof(Ty); + } + u32 capacity() const { return _capacity; diff --git a/rpcs3/Emu/RSX/VK/VKCompute.cpp b/rpcs3/Emu/RSX/VK/VKCompute.cpp index 6f676e60c9..9d91773988 100644 --- a/rpcs3/Emu/RSX/VK/VKCompute.cpp +++ b/rpcs3/Emu/RSX/VK/VKCompute.cpp @@ -132,7 +132,7 @@ namespace vk m_program = compiler->compile(create_info, vk::pipe_compiler::COMPILE_INLINE, {}, get_inputs()); } - bind_resources(); + bind_resources(cmd); m_program->bind(cmd, VK_PIPELINE_BIND_POINT_COMPUTE); } @@ -243,20 +243,19 @@ namespace vk m_src += suffix; } - void cs_shuffle_base::bind_resources() + 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); } - void cs_shuffle_base::set_parameters(const vk::command_buffer& cmd, const u32* params, u8 count) + void cs_shuffle_base::set_parameters(const vk::command_buffer& cmd) { - if (!m_program) + if (!m_params.empty()) { - load_program(cmd); + ensure(use_push_constants); + vkCmdPushConstants(cmd, m_program->layout(), VK_SHADER_STAGE_COMPUTE_BIT, 0, m_params.size_bytes32(), m_params.data()); } - - ensure(use_push_constants); - vkCmdPushConstants(cmd, m_program->layout(), VK_SHADER_STAGE_COMPUTE_BIT, 0, count * 4, params); } void cs_shuffle_base::run(const vk::command_buffer& cmd, const vk::buffer* data, u32 data_length, u32 data_offset) @@ -294,15 +293,15 @@ namespace vk " uint stencil_offset;\n"; } - void cs_interleave_task::bind_resources() + 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); } 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) { - u32 parameters[4] = { data_length, zeta_offset - data_offset, stencil_offset - data_offset, 0 }; - set_parameters(cmd, parameters, 4); + m_params = { data_length, zeta_offset - data_offset, stencil_offset - data_offset, 0 }; ensure(stencil_offset > data_offset); m_ssbo_length = stencil_offset + (data_length / 4) - data_offset; @@ -354,7 +353,7 @@ namespace vk m_src = fmt::replace_all(m_src, syntax_replace); } - void cs_aggregator::bind_resources() + 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); diff --git a/rpcs3/Emu/RSX/VK/VKCompute.h b/rpcs3/Emu/RSX/VK/VKCompute.h index 9ffeb1ca7f..0dfa80f4f5 100644 --- a/rpcs3/Emu/RSX/VK/VKCompute.h +++ b/rpcs3/Emu/RSX/VK/VKCompute.h @@ -35,7 +35,7 @@ namespace vk void destroy(); virtual std::vector get_inputs(); - virtual void bind_resources() {} + virtual void bind_resources(const vk::command_buffer& cmd) {} void load_program(const vk::command_buffer& cmd); @@ -50,6 +50,8 @@ namespace vk u32 m_data_length = 0; u32 kernel_size = 1; + rsx::simple_array m_params; + std::string variables, work_kernel, loop_advance, suffix; std::string method_declarations; @@ -57,9 +59,9 @@ namespace vk void build(const char* function_name, u32 _kernel_size = 0); - void bind_resources() override; + void bind_resources(const vk::command_buffer& cmd) override; - void set_parameters(const vk::command_buffer& cmd, const u32* params, u8 count); + void set_parameters(const vk::command_buffer& cmd); void run(const vk::command_buffer& cmd, const vk::buffer* data, u32 data_length, u32 data_offset = 0); }; @@ -125,7 +127,7 @@ namespace vk cs_interleave_task(); - void bind_resources() override; + void bind_resources(const vk::command_buffer& cmd) override; void run(const vk::command_buffer& cmd, const vk::buffer* data, u32 data_offset, u32 data_length, u32 zeta_offset, u32 stencil_offset); }; @@ -342,8 +344,9 @@ namespace vk cs_shuffle_base::build(""); } - void bind_resources() override + 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); } @@ -361,8 +364,7 @@ namespace vk data_offset = src_offset; } - u32 parameters[4] = { src_length, src_offset - data_offset, dst_offset - data_offset, 0 }; - set_parameters(cmd, parameters, 4); + m_params = { src_length, src_offset - data_offset, dst_offset - data_offset, 0 }; cs_shuffle_base::run(cmd, data, src_length, data_offset); } }; @@ -443,19 +445,16 @@ namespace vk m_src = fmt::replace_all(m_src, syntax_replace); } - void bind_resources() override + void bind_resources(const vk::command_buffer& cmd) override { + 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); } void set_parameters(const vk::command_buffer& cmd) { - if (!m_program) - { - load_program(cmd); - } - vkCmdPushConstants(cmd, m_program->layout(), VK_SHADER_STAGE_COMPUTE_BIT, 0, push_constants_size, params.data); } @@ -475,7 +474,6 @@ namespace vk params.logw = rsx::ceil_log2(width); params.logh = rsx::ceil_log2(height); params.logd = rsx::ceil_log2(depth); - set_parameters(cmd); const u32 num_bytes_per_invocation = (sizeof(_BlockType) * optimal_group_size); const u32 linear_invocations = utils::aligned_div(data_length, num_bytes_per_invocation); @@ -492,7 +490,7 @@ namespace vk cs_aggregator(); - void bind_resources() override; + void bind_resources(const vk::command_buffer& cmd) override; void run(const vk::command_buffer& cmd, const vk::buffer* dst, const vk::buffer* src, u32 num_words); }; @@ -576,8 +574,10 @@ namespace vk m_src = fmt::replace_all(m_src, syntax_replace); } - void bind_resources() override + void bind_resources(const vk::command_buffer& cmd) override { + 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); @@ -648,7 +648,6 @@ namespace vk params.image_height = (Op == RSX_detiler_op::decode) ? tile_aligned_height : config.image_height; params.image_pitch = config.image_pitch; params.image_bpp = config.image_bpp; - set_parameters(cmd); const u32 subtexels_per_invocation = (config.image_bpp < 4) ? (4 / config.image_bpp) : 1; const u32 virtual_width = config.image_width / subtexels_per_invocation; diff --git a/rpcs3/Emu/RSX/VK/VKResolveHelper.h b/rpcs3/Emu/RSX/VK/VKResolveHelper.h index 9bc9e4f532..a9064eff95 100644 --- a/rpcs3/Emu/RSX/VK/VKResolveHelper.h +++ b/rpcs3/Emu/RSX/VK/VKResolveHelper.h @@ -49,7 +49,7 @@ namespace vk return result; } - void bind_resources() override + void bind_resources(const vk::command_buffer& cmd) override { auto msaa_view = multisampled->get_view(rsx::default_remap_vector.with_encoding(VK_REMAP_VIEW_MULTISAMPLED)); auto resolved_view = resolve->get_view(rsx::default_remap_vector.with_encoding(VK_REMAP_IDENTITY)); diff --git a/rpcs3/Emu/RSX/VK/upscalers/fsr1/fsr_pass.cpp b/rpcs3/Emu/RSX/VK/upscalers/fsr1/fsr_pass.cpp index 589defd3e8..23a4733c60 100644 --- a/rpcs3/Emu/RSX/VK/upscalers/fsr1/fsr_pass.cpp +++ b/rpcs3/Emu/RSX/VK/upscalers/fsr1/fsr_pass.cpp @@ -97,7 +97,7 @@ namespace vk return result; } - void fsr_pass::bind_resources() + void fsr_pass::bind_resources(const vk::command_buffer& cmd) { // Bind relevant stuff if (!m_sampler) diff --git a/rpcs3/Emu/RSX/VK/upscalers/fsr_pass.h b/rpcs3/Emu/RSX/VK/upscalers/fsr_pass.h index 6d9b15d72a..7bff58b049 100644 --- a/rpcs3/Emu/RSX/VK/upscalers/fsr_pass.h +++ b/rpcs3/Emu/RSX/VK/upscalers/fsr_pass.h @@ -20,7 +20,7 @@ namespace vk u32 m_constants_buf[20]; std::vector get_inputs() override; - void bind_resources() override; + void bind_resources(const vk::command_buffer&) override; virtual void configure(const vk::command_buffer& cmd) = 0; diff --git a/rpcs3/Emu/RSX/VK/vkutils/descriptors.cpp b/rpcs3/Emu/RSX/VK/vkutils/descriptors.cpp index d8e8fcd7ff..a49dc66301 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/descriptors.cpp +++ b/rpcs3/Emu/RSX/VK/vkutils/descriptors.cpp @@ -14,7 +14,7 @@ namespace vk public: inline void flush_all() { - std::shared_lock lock(m_notifications_lock); + std::lock_guard lock(m_notifications_lock); for (auto& set : m_notification_list) { @@ -44,7 +44,7 @@ namespace vk private: rsx::simple_array m_notification_list; - std::shared_mutex m_notifications_lock; + std::mutex m_notifications_lock; dispatch_manager(const dispatch_manager&) = delete; dispatch_manager& operator = (const dispatch_manager&) = delete; @@ -81,17 +81,17 @@ namespace vk } else { - binding_flags[i] = VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT; + binding_flags[i] = VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT; } } - binding_infos.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT; + binding_infos.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO; binding_infos.pNext = nullptr; binding_infos.bindingCount = ::size32(binding_flags); binding_infos.pBindingFlags = binding_flags.data(); infos.pNext = &binding_infos; - infos.flags |= VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT; + infos.flags |= VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT; VkDescriptorSetLayout result; CHECK_RESULT(vkCreateDescriptorSetLayout(*g_render_device, &infos, nullptr, &result)); @@ -442,6 +442,7 @@ namespace vk { if (!m_push_type_mask) { + ensure(m_pending_writes.empty()); return; } @@ -450,16 +451,17 @@ namespace vk (m_pending_writes.size() >= max_cache_size)) { flush(); + return; } - else if (m_update_after_bind_mask) - { - // Register for async flush - g_fxo->get().register_(this); - } + + // Register for async flush + ensure(m_update_after_bind_mask); + g_fxo->get().register_(this); } void descriptor_set::bind(const vk::command_buffer& cmd, VkPipelineBindPoint bind_point, VkPipelineLayout layout) { + // Notify on_bind(); vkCmdBindDescriptorSets(cmd, bind_point, layout, 0, 1, &m_handle, ::size32(m_dynamic_offsets), m_dynamic_offsets.data()); From ffa835efac9edfc6e8ad91c5f74aeb1fde54dc1f Mon Sep 17 00:00:00 2001 From: kd-11 Date: Sun, 15 Jun 2025 14:22:04 +0300 Subject: [PATCH 13/37] vk: Use shared layout generator for all pipelines - Common code applying flags uniformly fixes bugs with misconfigured options --- rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp b/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp index c03a9e7b00..d7bdfcbb36 100644 --- a/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp +++ b/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp @@ -568,14 +568,7 @@ namespace vk } } - VkDescriptorSetLayoutCreateInfo set_layout_create_info - { - .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, - .flags = 0, - .bindingCount = ::size32(bindings), - .pBindings = bindings.data() - }; - CHECK_RESULT(vkCreateDescriptorSetLayout(m_device, &set_layout_create_info, nullptr, &m_descriptor_set_layout)); + m_descriptor_set_layout = vk::descriptors::create_layout(bindings); } void descriptor_table_t::create_descriptor_pool() From 3a65359d59285f95ddc18a532a4f47e87ed71bb9 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Sun, 15 Jun 2025 15:01:45 +0300 Subject: [PATCH 14/37] vk: Fix clang build and resource leak on exit --- rpcs3/Emu/RSX/VK/VKCommonDecompiler.cpp | 3 ++- rpcs3/Emu/RSX/VK/VKGSRender.cpp | 4 ++++ rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp | 5 ++++- rpcs3/Emu/RSX/VK/vkutils/descriptors.cpp | 13 +++++++++++++ rpcs3/Emu/RSX/VK/vkutils/descriptors.h | 3 ++- 5 files changed, 25 insertions(+), 3 deletions(-) diff --git a/rpcs3/Emu/RSX/VK/VKCommonDecompiler.cpp b/rpcs3/Emu/RSX/VK/VKCommonDecompiler.cpp index 1191561625..790421e474 100644 --- a/rpcs3/Emu/RSX/VK/VKCommonDecompiler.cpp +++ b/rpcs3/Emu/RSX/VK/VKCommonDecompiler.cpp @@ -46,9 +46,10 @@ namespace vk #define IS_DIGIT(x) (x >= '0' && x <= '9') constexpr int max_index_length = 2; + const int name_length = static_cast(name.length()); std::string index; - for (int char_idx = name.length() - max_index_length; char_idx < name.length(); ++char_idx) + for (int char_idx = name_length - max_index_length; char_idx < name_length; ++char_idx) { if (IS_DIGIT(name[char_idx])) { diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index c1d560a637..4506c870ec 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -1,3 +1,4 @@ +#include "Emu/RSX/VK/vkutils/descriptors.h" #include "stdafx.h" #include "../Overlays/overlay_compile_notification.h" #include "../Overlays/Shaders/shader_loading_dialog_native.h" @@ -854,6 +855,9 @@ VKGSRender::~VKGSRender() m_command_buffer_pool.destroy(); m_secondary_command_buffer_pool.destroy(); + // Descriptors + vk::descriptors::flush(); + // Global resources vk::destroy_global_resources(); diff --git a/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp b/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp index d7bdfcbb36..b5bc7642ba 100644 --- a/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp +++ b/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp @@ -420,7 +420,10 @@ namespace vk } vkDestroyDescriptorSetLayout(m_device, m_descriptor_set_layout, nullptr); - vk::get_resource_manager()->dispose(m_descriptor_pool); + m_descriptor_pool->destroy(); + + m_descriptor_pool.reset(); + m_device = VK_NULL_HANDLE; } void descriptor_table_t::init(VkDevice dev) diff --git a/rpcs3/Emu/RSX/VK/vkutils/descriptors.cpp b/rpcs3/Emu/RSX/VK/vkutils/descriptors.cpp index a49dc66301..9e5880a7ee 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/descriptors.cpp +++ b/rpcs3/Emu/RSX/VK/vkutils/descriptors.cpp @@ -40,6 +40,12 @@ namespace vk // rsx_log.notice("[descriptor_manager::deregister] Now monitoring %u descriptor sets", m_notification_list.size()); } + void destroy() + { + std::lock_guard lock(m_notifications_lock); + m_notification_list.clear(); + } + dispatch_manager() = default; private: @@ -60,6 +66,11 @@ namespace vk g_fxo->get().flush_all(); } + void destroy() + { + g_fxo->get().destroy(); + } + VkDescriptorSetLayout create_layout(const rsx::simple_array& bindings) { VkDescriptorSetLayoutCreateInfo infos = {}; @@ -414,11 +425,13 @@ namespace vk { m_push_type_mask |= type_mask; +#if !defined(__clang__) || (__clang_major__ >= 16) if (m_pending_writes.empty()) [[unlikely]] { m_pending_writes = std::move(write_cmds); } else +#endif { const auto old_size = m_pending_writes.size(); const auto new_size = write_cmds.size() + old_size; diff --git a/rpcs3/Emu/RSX/VK/vkutils/descriptors.h b/rpcs3/Emu/RSX/VK/vkutils/descriptors.h index 556fe5d0b9..c2cf5deb20 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/descriptors.h +++ b/rpcs3/Emu/RSX/VK/vkutils/descriptors.h @@ -122,7 +122,7 @@ namespace vk rsx::simple_array m_image_info_pool; rsx::simple_array m_dynamic_offsets; -#ifdef __clang__ +#if defined(__clang__) && (__clang_major__ < 16) // Clang (pre 16.x) does not support LWG 2089, std::construct_at for POD types struct WriteDescriptorSetT : public VkWriteDescriptorSet { @@ -162,6 +162,7 @@ namespace vk { void init(); void flush(); + void destroy(); VkDescriptorSetLayout create_layout(const rsx::simple_array& bindings); } From bb1c0a5eee4a31c1ded5b37c1e3a41fd7068b06c Mon Sep 17 00:00:00 2001 From: kd-11 Date: Sun, 15 Jun 2025 22:04:57 +0300 Subject: [PATCH 15/37] rsx/util: Support basic array merge --- rpcs3/Emu/RSX/Common/simple_array.hpp | 7 +++++++ rpcs3/tests/test_simple_array.cpp | 25 +++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/rpcs3/Emu/RSX/Common/simple_array.hpp b/rpcs3/Emu/RSX/Common/simple_array.hpp index 06e0b1870d..033994547d 100644 --- a/rpcs3/Emu/RSX/Common/simple_array.hpp +++ b/rpcs3/Emu/RSX/Common/simple_array.hpp @@ -285,6 +285,13 @@ namespace rsx return pos; } + void operator += (const rsx::simple_array& that) + { + const auto old_size = _size; + resize(_size + that._size); + std::memcpy(data() + old_size, that.data(), that.size_bytes()); + } + void clear() { _size = 0; diff --git a/rpcs3/tests/test_simple_array.cpp b/rpcs3/tests/test_simple_array.cpp index f64e01200e..916284a6cd 100644 --- a/rpcs3/tests/test_simple_array.cpp +++ b/rpcs3/tests/test_simple_array.cpp @@ -189,4 +189,29 @@ namespace rsx EXPECT_EQ(arr[i], i + 1); } } + + TEST(SimpleArray, Merge) + { + rsx::simple_array arr{ 1 }; + rsx::simple_array arr2{ 2, 3, 4, 5, 6, 7, 8, 9 }; + rsx::simple_array arr3{ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 }; + + // Check small vector optimization + EXPECT_TRUE(arr.is_local_storage()); + + // Small vector optimization holds after append + arr += arr2; + EXPECT_TRUE(arr.is_local_storage()); + + // Exceed the boundary and we move into dynamic alloc + arr += arr3; + EXPECT_FALSE(arr.is_local_storage()); + + // Verify contents + EXPECT_EQ(arr.size(), 30); + for (int i = 0; i < 30; ++i) + { + EXPECT_EQ(arr[i], i + 1); + } + } } From 5417d4854df208cb7791b62cacdf8ab0daab8340 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Sun, 15 Jun 2025 22:05:36 +0300 Subject: [PATCH 16/37] vk: Fix edge cases in descriptor update logic --- rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp | 6 +++--- rpcs3/Emu/RSX/VK/VKProgramPipeline.h | 6 ++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp b/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp index b5bc7642ba..892c217f6c 100644 --- a/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp +++ b/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp @@ -399,12 +399,11 @@ namespace vk { if (!set.m_device) { - break; + continue; } bind_sets[count++] = set.m_descriptor_set.value(); // Current set pointer for binding - set.m_descriptor_set.on_bind(); // Notify async queue - set.next_descriptor_set(); // Flush queue and update pointers + set.on_bind(); // Notify bind event. Internally updates handles and triggers flushing. } vkCmdBindPipeline(cmd, bind_point, m_pipeline); @@ -528,6 +527,7 @@ namespace vk m_descriptor_set.push(m_copy_cmds, type_mask); // Write previous state m_descriptor_set = allocate_descriptor_set(); + m_any_descriptors_dirty = false; } void descriptor_table_t::create_descriptor_set_layout() diff --git a/rpcs3/Emu/RSX/VK/VKProgramPipeline.h b/rpcs3/Emu/RSX/VK/VKProgramPipeline.h index d0f06e2a80..36653facf7 100644 --- a/rpcs3/Emu/RSX/VK/VKProgramPipeline.h +++ b/rpcs3/Emu/RSX/VK/VKProgramPipeline.h @@ -138,6 +138,12 @@ namespace vk VkDescriptorSet allocate_descriptor_set(); void next_descriptor_set(); + inline void on_bind() + { + next_descriptor_set(); // Enqueue changes and update pointers + m_descriptor_set.on_bind(); // Notify async queue to flush any pending changes + } + template inline void notify_descriptor_slot_updated(u32 slot, const T& data) { From 15791cf94eea005166fe8a7cdf74a0344d3a0a7b Mon Sep 17 00:00:00 2001 From: kd-11 Date: Sun, 15 Jun 2025 22:56:32 +0300 Subject: [PATCH 17/37] vk: Fix descriptor set update and caching model to support skipped updates --- rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp | 31 +++++++++++++++--------- rpcs3/Emu/RSX/VK/VKProgramPipeline.h | 8 +----- rpcs3/Emu/RSX/VK/vkutils/descriptors.cpp | 19 ++++----------- 3 files changed, 25 insertions(+), 33 deletions(-) diff --git a/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp b/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp index 892c217f6c..18d658fc42 100644 --- a/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp +++ b/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp @@ -364,7 +364,7 @@ namespace vk break; } - set.next_descriptor_set(); // Initializes the set layout and allocates first set + set.create_descriptor_set_layout(); set_layouts.push_back(set.m_descriptor_set_layout); for (const auto& input : set.m_inputs[input_type_push_constant]) @@ -402,8 +402,7 @@ namespace vk continue; } - bind_sets[count++] = set.m_descriptor_set.value(); // Current set pointer for binding - set.on_bind(); // Notify bind event. Internally updates handles and triggers flushing. + bind_sets[count++] = set.commit(); // Commit variable changes and return handle to the new set } vkCmdBindPipeline(cmd, bind_point, m_pipeline); @@ -418,10 +417,17 @@ namespace vk return; } - vkDestroyDescriptorSetLayout(m_device, m_descriptor_set_layout, nullptr); - m_descriptor_pool->destroy(); + if (m_descriptor_set_layout) + { + vkDestroyDescriptorSetLayout(m_device, m_descriptor_set_layout, nullptr); + } + + if (m_descriptor_pool) + { + m_descriptor_pool->destroy(); + m_descriptor_pool.reset(); + } - m_descriptor_pool.reset(); m_device = VK_NULL_HANDLE; } @@ -451,26 +457,24 @@ namespace vk { if (!m_descriptor_pool) { - create_descriptor_set_layout(); create_descriptor_pool(); } return m_descriptor_pool->allocate(m_descriptor_set_layout); } - void descriptor_table_t::next_descriptor_set() + VkDescriptorSet descriptor_table_t::commit() { if (!m_descriptor_set) { - m_descriptor_set = allocate_descriptor_set(); + m_any_descriptors_dirty = true; std::fill(m_descriptors_dirty.begin(), m_descriptors_dirty.end(), false); - return; } // Check if we need to actually open a new set if (!m_any_descriptors_dirty) { - return; + return m_descriptor_set.value(); } auto push_descriptor_slot = [this](unsigned idx) @@ -500,6 +504,7 @@ namespace vk m_copy_cmds.clear(); rsx::flags32_t type_mask = 0u; + m_descriptor_set = allocate_descriptor_set(); for (unsigned i = 0; i < m_descriptor_slots.size(); ++i) { @@ -526,8 +531,10 @@ namespace vk } m_descriptor_set.push(m_copy_cmds, type_mask); // Write previous state - m_descriptor_set = allocate_descriptor_set(); + m_descriptor_set.on_bind(); m_any_descriptors_dirty = false; + + return m_descriptor_set.value(); } void descriptor_table_t::create_descriptor_set_layout() diff --git a/rpcs3/Emu/RSX/VK/VKProgramPipeline.h b/rpcs3/Emu/RSX/VK/VKProgramPipeline.h index 36653facf7..bc36b936e7 100644 --- a/rpcs3/Emu/RSX/VK/VKProgramPipeline.h +++ b/rpcs3/Emu/RSX/VK/VKProgramPipeline.h @@ -136,13 +136,7 @@ namespace vk void create_descriptor_pool(); VkDescriptorSet allocate_descriptor_set(); - void next_descriptor_set(); - - inline void on_bind() - { - next_descriptor_set(); // Enqueue changes and update pointers - m_descriptor_set.on_bind(); // Notify async queue to flush any pending changes - } + VkDescriptorSet commit(); template inline void notify_descriptor_slot_updated(u32 slot, const T& data) diff --git a/rpcs3/Emu/RSX/VK/vkutils/descriptors.cpp b/rpcs3/Emu/RSX/VK/vkutils/descriptors.cpp index 9e5880a7ee..b5e62f33f6 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/descriptors.cpp +++ b/rpcs3/Emu/RSX/VK/vkutils/descriptors.cpp @@ -411,14 +411,10 @@ namespace vk if (m_pending_copies.empty()) [[likely]] { m_pending_copies = std::move(copy_cmd); + return; } - else - { - const auto old_size = m_pending_copies.size(); - const auto new_size = copy_cmd.size() + old_size; - m_pending_copies.resize(new_size); - std::copy(copy_cmd.begin(), copy_cmd.end(), m_pending_copies.begin() + old_size); - } + + m_pending_copies += copy_cmd; } void descriptor_set::push(rsx::simple_array& write_cmds, u32 type_mask) @@ -429,15 +425,10 @@ namespace vk if (m_pending_writes.empty()) [[unlikely]] { m_pending_writes = std::move(write_cmds); + return; } - else #endif - { - const auto old_size = m_pending_writes.size(); - const auto new_size = write_cmds.size() + old_size; - m_pending_writes.resize(new_size); - std::copy(write_cmds.begin(), write_cmds.end(), m_pending_writes.begin() + old_size); - } + m_pending_writes += write_cmds; } void descriptor_set::push(const descriptor_set_dynamic_offset_t& offset) From b3492b73ad678aa138df3f3f1e7eec27b3e46d7a Mon Sep 17 00:00:00 2001 From: kd-11 Date: Sun, 15 Jun 2025 23:45:11 +0300 Subject: [PATCH 18/37] vk: Improve pipeline layout validation and fix slot allocation bugs --- rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp | 3 +++ rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp | 20 ++++++++++++++------ rpcs3/Emu/RSX/VK/VKVertexProgram.cpp | 2 ++ 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp b/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp index dc5ff8640f..7aee3c7d95 100644 --- a/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp +++ b/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp @@ -57,6 +57,9 @@ void VKFragmentDecompilerThread::prepareBindingTable() vk_prog->binding_table.tex_param_location = location++; vk_prog->binding_table.polygon_stipple_params_location = location++; + std::memset(vk_prog->binding_table.ftex_location, 0xff, sizeof(vk_prog->binding_table.ftex_location)); + std::memset(vk_prog->binding_table.ftex_stencil_location, 0xff, sizeof(vk_prog->binding_table.ftex_stencil_location)); + if (has_textures) [[ likely ]] { unsigned num_textures = 0; diff --git a/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp b/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp index 18d658fc42..9f53e62f2e 100644 --- a/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp +++ b/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp @@ -547,6 +547,8 @@ namespace vk m_descriptor_pool_sizes.clear(); m_descriptor_pool_sizes.reserve(input_type_max_enum); + std::unordered_map descriptor_type_map; + for (const auto& type_arr : m_inputs) { if (type_arr.empty() || type_arr.front().type == input_type_push_constant) @@ -568,16 +570,22 @@ namespace vk }; bindings.push_back(binding); - if (m_descriptor_types.size() < (input.location + 1)) - { - m_descriptor_types.resize((input.location + 1)); - } - - m_descriptor_types[input.location] = type; + descriptor_type_map[input.location] = type; m_descriptor_pool_sizes.back().descriptorCount++; } } + m_descriptor_types.resize(::size32(m_descriptors_dirty)); + + for (u32 i = 0; i < ::size32(m_descriptors_dirty); ++i) + { + if (descriptor_type_map.find(i) == descriptor_type_map.end()) + { + fmt::throw_exception("Invalid input structure. Some input bindings were not declared!"); + } + m_descriptor_types[i] = descriptor_type_map[i]; + } + m_descriptor_set_layout = vk::descriptors::create_layout(bindings); } diff --git a/rpcs3/Emu/RSX/VK/VKVertexProgram.cpp b/rpcs3/Emu/RSX/VK/VKVertexProgram.cpp index a45eb0e2bc..70d0972984 100644 --- a/rpcs3/Emu/RSX/VK/VKVertexProgram.cpp +++ b/rpcs3/Emu/RSX/VK/VKVertexProgram.cpp @@ -38,6 +38,8 @@ void VKVertexDecompilerThread::prepareBindingTable() vk_prog->binding_table.cr_pred_buffer_location = location++; } + std::memset(vk_prog->binding_table.vtex_location, 0xff, sizeof(vk_prog->binding_table.vtex_location)); + for (const ParamType& PT : m_parr.params[PF_PARAM_UNIFORM]) { const bool is_texture_type = PT.type.starts_with("sampler"); From 91491c7cf388b3da067e1969f4aab839b9f757b7 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Sun, 22 Jun 2025 03:13:24 +0300 Subject: [PATCH 19/37] vk: Drop copy optimization - The pointer-based nature of write entries, changes invalidate previous data - Instead of managing scratch, just push to the descriptors built-in management which is quite optimal --- rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp | 18 +++--------------- rpcs3/Emu/RSX/VK/VKProgramPipeline.h | 1 - 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp b/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp index 9f53e62f2e..85454481a2 100644 --- a/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp +++ b/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp @@ -502,8 +502,6 @@ namespace vk fmt::throw_exception("Unexpected descriptor structure at index %u", idx); }; - m_copy_cmds.clear(); - rsx::flags32_t type_mask = 0u; m_descriptor_set = allocate_descriptor_set(); for (unsigned i = 0; i < m_descriptor_slots.size(); ++i) @@ -516,21 +514,11 @@ namespace vk continue; } - m_copy_cmds.push_back({ - .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - .dstSet = m_descriptor_set.value(), - .dstBinding = i, - .descriptorCount = 1, - .descriptorType = m_descriptor_types[i], - .pImageInfo = std::get_if(&m_descriptor_slots[i]), - .pBufferInfo = std::get_if(&m_descriptor_slots[i]), - .pTexelBufferView = std::get_if(&m_descriptor_slots[i]) - }); - - type_mask |= (1u << m_descriptor_types[i]); + // We should copy here if possible. + // Without descriptor_buffer, the most efficient option is to just use the normal bind logic due to the pointer-based nature of the descriptor inputs and no stride. + push_descriptor_slot(i); } - m_descriptor_set.push(m_copy_cmds, type_mask); // Write previous state m_descriptor_set.on_bind(); m_any_descriptors_dirty = false; diff --git a/rpcs3/Emu/RSX/VK/VKProgramPipeline.h b/rpcs3/Emu/RSX/VK/VKProgramPipeline.h index bc36b936e7..81c3ff8525 100644 --- a/rpcs3/Emu/RSX/VK/VKProgramPipeline.h +++ b/rpcs3/Emu/RSX/VK/VKProgramPipeline.h @@ -124,7 +124,6 @@ namespace vk std::vector m_descriptor_slots; std::vector m_descriptors_dirty; - rsx::simple_array m_copy_cmds; bool m_any_descriptors_dirty = false; void init(VkDevice dev); From cdc78f81f761b43e4baafd3f368893d13f598959 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Sun, 22 Jun 2025 14:43:38 +0300 Subject: [PATCH 20/37] vk: Code improvements --- rpcs3/Emu/RSX/VK/VKCommonDecompiler.cpp | 6 +----- rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/rpcs3/Emu/RSX/VK/VKCommonDecompiler.cpp b/rpcs3/Emu/RSX/VK/VKCommonDecompiler.cpp index 790421e474..815492caa3 100644 --- a/rpcs3/Emu/RSX/VK/VKCommonDecompiler.cpp +++ b/rpcs3/Emu/RSX/VK/VKCommonDecompiler.cpp @@ -43,22 +43,18 @@ namespace vk fmt::throw_exception("Invalid texture name: '%s'", name); } -#define IS_DIGIT(x) (x >= '0' && x <= '9') - constexpr int max_index_length = 2; const int name_length = static_cast(name.length()); std::string index; for (int char_idx = name_length - max_index_length; char_idx < name_length; ++char_idx) { - if (IS_DIGIT(name[char_idx])) + if (std::isdigit(name[char_idx])) { index += name[char_idx]; } } -#undef IS_DIGIT - if (index.empty()) { fmt::throw_exception("Invalid texture name: '%s'", name); diff --git a/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp b/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp index 85454481a2..967828655e 100644 --- a/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp +++ b/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp @@ -361,7 +361,7 @@ namespace vk { if (!set.m_device) { - break; + continue; } set.create_descriptor_set_layout(); From 91e22aa4e48a19cd2086182bacb9c5e4f8fdcf8b Mon Sep 17 00:00:00 2001 From: kd-11 Date: Sun, 22 Jun 2025 15:45:56 +0300 Subject: [PATCH 21/37] vk: Fix FS stencil mirror binding location overwrites causing holes in descriptor layout --- rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp b/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp index 7aee3c7d95..94012840ec 100644 --- a/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp +++ b/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp @@ -92,7 +92,7 @@ void VKFragmentDecompilerThread::prepareBindingTable() { for (auto& stencil_location : vk_prog->binding_table.ftex_stencil_location) { - if (stencil_location == umax) + if (stencil_location != 0) { continue; } From dd28d100d61b79bd317484f4fd7edc1998df907f Mon Sep 17 00:00:00 2001 From: kd-11 Date: Sun, 22 Jun 2025 16:19:48 +0300 Subject: [PATCH 22/37] vk: Fix crash when running attachment clear pass --- rpcs3/Emu/RSX/VK/VKOverlays.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/rpcs3/Emu/RSX/VK/VKOverlays.cpp b/rpcs3/Emu/RSX/VK/VKOverlays.cpp index 6a74f8e646..743339e26c 100644 --- a/rpcs3/Emu/RSX/VK/VKOverlays.cpp +++ b/rpcs3/Emu/RSX/VK/VKOverlays.cpp @@ -43,6 +43,10 @@ namespace vk if (!m_vao.heap) { m_vao.create(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, 1 * 0x100000, "overlays VAO", 128); + } + + if (!m_ubo.heap && m_num_uniform_buffers > 0) + { m_ubo.create(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, 8 * 0x100000, "overlays UBO", 128); } } @@ -704,6 +708,9 @@ namespace vk // Disable samplers m_num_usable_samplers = 0; + // Disable UBOs + m_num_uniform_buffers = 0; + renderpass_config.set_depth_mask(false); renderpass_config.set_color_mask(0, true, true, true, true); renderpass_config.set_attachment_count(1); @@ -711,6 +718,7 @@ namespace vk std::vector attachment_clear_pass::get_vertex_inputs() { + check_heap(); return { vk::glsl::program_input::make( From 16a0ae6a7bc46773e8414f661b8e7e3f633691be Mon Sep 17 00:00:00 2001 From: kd-11 Date: Sun, 22 Jun 2025 18:28:35 +0300 Subject: [PATCH 23/37] vk: Update shader interpreter to use dynamic binding layout --- rpcs3/Emu/RSX/Program/ShaderInterpreter.h | 3 +- rpcs3/Emu/RSX/VK/VKCommonPipelineLayout.cpp | 151 ---------- rpcs3/Emu/RSX/VK/VKCommonPipelineLayout.h | 7 - rpcs3/Emu/RSX/VK/VKDraw.cpp | 21 +- rpcs3/Emu/RSX/VK/VKFragmentProgram.h | 2 +- rpcs3/Emu/RSX/VK/VKGSRender.cpp | 55 +++- rpcs3/Emu/RSX/VK/VKGSRender.h | 8 + rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp | 301 ++++++++------------ rpcs3/Emu/RSX/VK/VKShaderInterpreter.h | 23 +- rpcs3/Emu/RSX/VK/vkutils/device.cpp | 12 - rpcs3/Emu/RSX/VK/vkutils/device.h | 3 - 11 files changed, 200 insertions(+), 386 deletions(-) diff --git a/rpcs3/Emu/RSX/Program/ShaderInterpreter.h b/rpcs3/Emu/RSX/Program/ShaderInterpreter.h index 5503a2870c..f89c058dec 100644 --- a/rpcs3/Emu/RSX/Program/ShaderInterpreter.h +++ b/rpcs3/Emu/RSX/Program/ShaderInterpreter.h @@ -20,8 +20,9 @@ namespace program_common COMPILER_OPT_ENABLE_KIL = (1 << 11), COMPILER_OPT_ENABLE_STIPPLING = (1 << 12), COMPILER_OPT_ENABLE_INSTANCING = (1 << 13), + COMPILER_OPT_ENABLE_VTX_TEXTURES = (1 << 14), - COMPILER_OPT_MAX = COMPILER_OPT_ENABLE_INSTANCING + COMPILER_OPT_MAX = COMPILER_OPT_ENABLE_VTX_TEXTURES }; static std::string get_vertex_interpreter() diff --git a/rpcs3/Emu/RSX/VK/VKCommonPipelineLayout.cpp b/rpcs3/Emu/RSX/VK/VKCommonPipelineLayout.cpp index 602d855d76..76cda4d253 100644 --- a/rpcs3/Emu/RSX/VK/VKCommonPipelineLayout.cpp +++ b/rpcs3/Emu/RSX/VK/VKCommonPipelineLayout.cpp @@ -8,157 +8,6 @@ namespace vk { - rsx::simple_array get_common_binding_table() - { - const auto& binding_table = vk::get_current_renderer()->get_pipeline_binding_table(); - rsx::simple_array bindings(binding_table.instancing_constants_buffer_slot + 1); - - u32 idx = 0; - - // Vertex stream, one stream for cacheable data, one stream for transient data - for (int i = 0; i < 3; i++) - { - bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; - bindings[idx].descriptorCount = 1; - bindings[idx].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - bindings[idx].binding = binding_table.vertex_buffers_first_bind_slot + i; - bindings[idx].pImmutableSamplers = nullptr; - idx++; - } - - bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - bindings[idx].descriptorCount = 1; - bindings[idx].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - bindings[idx].binding = binding_table.fragment_constant_buffers_bind_slot; - bindings[idx].pImmutableSamplers = nullptr; - - idx++; - - bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - bindings[idx].descriptorCount = 1; - bindings[idx].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - bindings[idx].binding = binding_table.fragment_state_bind_slot; - bindings[idx].pImmutableSamplers = nullptr; - - idx++; - - bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - bindings[idx].descriptorCount = 1; - bindings[idx].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - bindings[idx].binding = binding_table.fragment_texture_params_bind_slot; - bindings[idx].pImmutableSamplers = nullptr; - - idx++; - - 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; - bindings[idx].pImmutableSamplers = nullptr; - - idx++; - - bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - bindings[idx].descriptorCount = 1; - bindings[idx].stageFlags = VK_SHADER_STAGE_ALL_GRAPHICS; - bindings[idx].binding = binding_table.vertex_params_bind_slot; - bindings[idx].pImmutableSamplers = nullptr; - - idx++; - - 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.conditional_render_predicate_slot; - bindings[idx].pImmutableSamplers = nullptr; - - idx++; - - bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - bindings[idx].descriptorCount = 1; - bindings[idx].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - bindings[idx].binding = binding_table.rasterizer_env_bind_slot; - bindings[idx].pImmutableSamplers = nullptr; - - idx++; - - 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.instancing_lookup_table_bind_slot; - bindings[idx].pImmutableSamplers = nullptr; - - idx++; - - 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.instancing_constants_buffer_slot; - bindings[idx].pImmutableSamplers = nullptr; - - idx++; - - return bindings; - } - - std::tuple> - get_common_pipeline_layout(VkDevice dev) - { - const auto& binding_table = vk::get_current_renderer()->get_pipeline_binding_table(); - auto bindings = get_common_binding_table(); - u32 idx = ::size32(bindings); - - bindings.resize(binding_table.total_descriptor_bindings); - - for (auto binding = binding_table.textures_first_bind_slot; - binding < binding_table.vertex_textures_first_bind_slot; - binding++) - { - bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - bindings[idx].descriptorCount = 1; - bindings[idx].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - bindings[idx].binding = binding; - bindings[idx].pImmutableSamplers = nullptr; - idx++; - } - - for (int i = 0; i < rsx::limits::vertex_textures_count; i++) - { - bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - bindings[idx].descriptorCount = 1; - bindings[idx].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - bindings[idx].binding = binding_table.vertex_textures_first_bind_slot + i; - bindings[idx].pImmutableSamplers = nullptr; - idx++; - } - - ensure(idx == binding_table.total_descriptor_bindings); - - std::array push_constants; - push_constants[0].offset = 0; - 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 = 24; - } - - const auto set_layout = vk::descriptors::create_layout(bindings); - - VkPipelineLayoutCreateInfo layout_info = {}; - layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - layout_info.setLayoutCount = 1; - layout_info.pSetLayouts = &set_layout; - layout_info.pushConstantRangeCount = 1; - layout_info.pPushConstantRanges = push_constants.data(); - - VkPipelineLayout result; - CHECK_RESULT(vkCreatePipelineLayout(dev, &layout_info, nullptr, &result)); - return std::make_tuple(result, set_layout, bindings); - } - rsx::simple_array get_descriptor_pool_sizes(const rsx::simple_array& bindings) { // Compile descriptor pool sizes diff --git a/rpcs3/Emu/RSX/VK/VKCommonPipelineLayout.h b/rpcs3/Emu/RSX/VK/VKCommonPipelineLayout.h index 371d0ebf76..e5ada45bf8 100644 --- a/rpcs3/Emu/RSX/VK/VKCommonPipelineLayout.h +++ b/rpcs3/Emu/RSX/VK/VKCommonPipelineLayout.h @@ -5,13 +5,6 @@ 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> 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 get_common_binding_table(); - // Returns an array of pool sizes that can be used to generate a proper descriptor pool rsx::simple_array get_descriptor_pool_sizes(const rsx::simple_array& bindings); } diff --git a/rpcs3/Emu/RSX/VK/VKDraw.cpp b/rpcs3/Emu/RSX/VK/VKDraw.cpp index 1e96087694..008d51f4bb 100644 --- a/rpcs3/Emu/RSX/VK/VKDraw.cpp +++ b/rpcs3/Emu/RSX/VK/VKDraw.cpp @@ -555,7 +555,7 @@ bool VKGSRender::bind_texture_env() { m_program->bind_uniform({ fs_sampler_handles[i]->value, view->value, view->image()->current_layout }, vk::glsl::binding_set_index_fragment, - m_fragment_prog->binding_table.ftex_location[i]); + m_fs_binding_table->ftex_location[i]); if (current_fragment_program.texture_state.redirected_textures & (1 << i)) { @@ -576,7 +576,7 @@ bool VKGSRender::bind_texture_env() m_program->bind_uniform({ m_stencil_mirror_sampler->value, stencil_view->value, stencil_view->image()->current_layout }, vk::glsl::binding_set_index_fragment, - m_fragment_prog->binding_table.ftex_stencil_location[i]); + m_fs_binding_table->ftex_stencil_location[i]); } } else @@ -584,13 +584,13 @@ bool VKGSRender::bind_texture_env() const VkImageViewType view_type = vk::get_view_type(current_fragment_program.get_texture_dimension(i)); m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer, view_type)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, vk::glsl::binding_set_index_fragment, - m_fragment_prog->binding_table.ftex_location[i]); + m_fs_binding_table->ftex_location[i]); if (current_fragment_program.texture_state.redirected_textures & (1 << i)) { m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer, view_type)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, vk::glsl::binding_set_index_fragment, - m_fragment_prog->binding_table.ftex_stencil_location[i]); + m_fs_binding_table->ftex_stencil_location[i]); } } } @@ -605,7 +605,7 @@ bool VKGSRender::bind_texture_env() const auto view_type = vk::get_view_type(current_vertex_program.get_texture_dimension(i)); m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer, view_type)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, vk::glsl::binding_set_index_vertex, - m_vertex_prog->binding_table.vtex_location[i]); + m_vs_binding_table->vtex_location[i]); continue; } @@ -628,7 +628,7 @@ bool VKGSRender::bind_texture_env() m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer, view_type)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, vk::glsl::binding_set_index_vertex, - m_vertex_prog->binding_table.vtex_location[i]); + m_vs_binding_table->vtex_location[i]); continue; } @@ -637,7 +637,7 @@ bool VKGSRender::bind_texture_env() m_program->bind_uniform({ vs_sampler_handles[i]->value, image_ptr->value, image_ptr->image()->current_layout }, vk::glsl::binding_set_index_vertex, - m_vertex_prog->binding_table.vtex_location[i]); + m_vs_binding_table->vtex_location[i]); } return out_of_memory; @@ -874,10 +874,9 @@ void VKGSRender::emit_geometry(u32 sub_index) ensure(m_vertex_layout_storage); if (update_descriptors) { - const auto& binding_table = m_vertex_prog->binding_table; - m_program->bind_uniform(persistent_buffer, vk::glsl::binding_set_index_vertex, binding_table.vertex_buffers_location); - m_program->bind_uniform(volatile_buffer, vk::glsl::binding_set_index_vertex, binding_table.vertex_buffers_location + 1); - m_program->bind_uniform(m_vertex_layout_storage->value, vk::glsl::binding_set_index_vertex, binding_table.vertex_buffers_location + 2); + m_program->bind_uniform(persistent_buffer, vk::glsl::binding_set_index_vertex, m_vs_binding_table->vertex_buffers_location); + m_program->bind_uniform(volatile_buffer, vk::glsl::binding_set_index_vertex, m_vs_binding_table->vertex_buffers_location + 1); + m_program->bind_uniform(m_vertex_layout_storage->value, vk::glsl::binding_set_index_vertex, m_vs_binding_table->vertex_buffers_location + 2); } bool reload_state = (!m_current_draw.subdraw_id++); diff --git a/rpcs3/Emu/RSX/VK/VKFragmentProgram.h b/rpcs3/Emu/RSX/VK/VKFragmentProgram.h index 049455a866..c51b81b8fc 100644 --- a/rpcs3/Emu/RSX/VK/VKFragmentProgram.h +++ b/rpcs3/Emu/RSX/VK/VKFragmentProgram.h @@ -10,7 +10,7 @@ namespace vk class shader_interpreter; } -struct VKFragmentDecompilerThread : public FragmentProgramDecompiler +class VKFragmentDecompilerThread : public FragmentProgramDecompiler { friend class vk::shader_interpreter; diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index 4506c870ec..b2003f645c 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -1780,8 +1780,11 @@ bool VKGSRender::load_program() m_program = m_shader_interpreter.get( m_pipeline_properties, current_fp_metadata, + current_vp_metadata, current_vertex_program.ctrl, current_fragment_program.ctrl); + + std::tie(m_vs_binding_table, m_fs_binding_table) = get_binding_table(); return true; } } @@ -1879,6 +1882,7 @@ bool VKGSRender::load_program() m_program = m_shader_interpreter.get( m_pipeline_properties, current_fp_metadata, + current_vp_metadata, current_vertex_program.ctrl, current_fragment_program.ctrl); @@ -1900,6 +1904,16 @@ bool VKGSRender::load_program() } } + if (m_program) + { + std::tie(m_vs_binding_table, m_fs_binding_table) = get_binding_table(); + } + else + { + m_vs_binding_table = nullptr; + m_fs_binding_table = nullptr; + } + return m_program != nullptr; } @@ -1911,13 +1925,14 @@ void VKGSRender::load_program_env() } const u32 fragment_constants_size = current_fp_metadata.program_constants_buffer_length; + const bool is_interpreter = m_shader_interpreter.is_interpreter(m_program); const bool update_transform_constants = !!(m_graphics_state & rsx::pipeline_state::transform_constants_dirty); const bool update_fragment_constants = !!(m_graphics_state & rsx::pipeline_state::fragment_constants_dirty); const bool update_vertex_env = !!(m_graphics_state & rsx::pipeline_state::vertex_state_dirty); const bool update_fragment_env = !!(m_graphics_state & rsx::pipeline_state::fragment_state_dirty); const bool update_fragment_texture_env = !!(m_graphics_state & rsx::pipeline_state::fragment_texture_state_dirty); - const bool update_instruction_buffers = (!!m_interpreter_state && m_shader_interpreter.is_interpreter(m_program)); + const bool update_instruction_buffers = (!!m_interpreter_state && is_interpreter); const bool update_raster_env = (rsx::method_registers.polygon_stipple_enabled() && !!(m_graphics_state & rsx::pipeline_state::polygon_stipple_pattern_dirty)); const bool update_instancing_data = rsx::method_registers.current_draw_clause.is_trivial_instanced_draw; @@ -2078,17 +2093,14 @@ void VKGSRender::load_program_env() } } - const auto& vs_binding_table = m_vertex_prog->binding_table; - const auto& fs_binding_table = m_fragment_prog->binding_table; + m_program->bind_uniform(m_vertex_env_buffer_info, vk::glsl::binding_set_index_vertex, m_vs_binding_table->context_buffer_location); + m_program->bind_uniform(m_fragment_env_buffer_info, vk::glsl::binding_set_index_fragment, m_fs_binding_table->context_buffer_location); + m_program->bind_uniform(m_fragment_texture_params_buffer_info, vk::glsl::binding_set_index_fragment, m_fs_binding_table->tex_param_location); + m_program->bind_uniform(m_raster_env_buffer_info, vk::glsl::binding_set_index_fragment, m_fs_binding_table->polygon_stipple_params_location); - m_program->bind_uniform(m_vertex_env_buffer_info, vk::glsl::binding_set_index_vertex, vs_binding_table.context_buffer_location); - m_program->bind_uniform(m_fragment_env_buffer_info, vk::glsl::binding_set_index_fragment, fs_binding_table.context_buffer_location); - m_program->bind_uniform(m_fragment_texture_params_buffer_info, vk::glsl::binding_set_index_fragment, fs_binding_table.tex_param_location); - m_program->bind_uniform(m_raster_env_buffer_info, vk::glsl::binding_set_index_fragment, fs_binding_table.polygon_stipple_params_location); - - if (vs_binding_table.cbuf_location != umax) + if (m_vs_binding_table->cbuf_location != umax) { - m_program->bind_uniform(m_vertex_constants_buffer_info, vk::glsl::binding_set_index_vertex, vs_binding_table.cbuf_location); + m_program->bind_uniform(m_vertex_constants_buffer_info, vk::glsl::binding_set_index_vertex, m_vs_binding_table->cbuf_location); } if (m_shader_interpreter.is_interpreter(m_program)) @@ -2096,21 +2108,21 @@ void VKGSRender::load_program_env() m_program->bind_uniform(m_vertex_instructions_buffer_info, vk::glsl::binding_set_index_vertex, m_shader_interpreter.get_vertex_instruction_location()); m_program->bind_uniform(m_fragment_instructions_buffer_info, vk::glsl::binding_set_index_fragment, m_shader_interpreter.get_fragment_instruction_location()); } - else if (fs_binding_table.cbuf_location != umax) + else if (m_fs_binding_table->cbuf_location != umax) { - m_program->bind_uniform(m_fragment_constants_buffer_info, vk::glsl::binding_set_index_fragment, fs_binding_table.cbuf_location); + m_program->bind_uniform(m_fragment_constants_buffer_info, vk::glsl::binding_set_index_fragment, m_fs_binding_table->cbuf_location); } if (vk::emulate_conditional_rendering()) { auto predicate = m_cond_render_buffer ? m_cond_render_buffer->value : vk::get_scratch_buffer(*m_current_command_buffer, 4)->value; - m_program->bind_uniform({ predicate, 0, 4 }, vk::glsl::binding_set_index_vertex, vs_binding_table.cr_pred_buffer_location); + m_program->bind_uniform({ predicate, 0, 4 }, vk::glsl::binding_set_index_vertex, m_vs_binding_table->cr_pred_buffer_location); } if (current_vertex_program.ctrl & RSX_SHADER_CONTROL_INSTANCED_CONSTANTS) { - m_program->bind_uniform(m_instancing_indirection_buffer_info, vk::glsl::binding_set_index_vertex, vs_binding_table.instanced_lut_buffer_location); - m_program->bind_uniform(m_instancing_constants_array_buffer_info, vk::glsl::binding_set_index_vertex, vs_binding_table.instanced_cbuf_location); + m_program->bind_uniform(m_instancing_indirection_buffer_info, vk::glsl::binding_set_index_vertex, m_vs_binding_table->instanced_lut_buffer_location); + m_program->bind_uniform(m_instancing_constants_array_buffer_info, vk::glsl::binding_set_index_vertex, m_vs_binding_table->instanced_cbuf_location); } // Clear flags @@ -2137,6 +2149,19 @@ void VKGSRender::load_program_env() m_graphics_state.clear(handled_flags); } +std::pair VKGSRender::get_binding_table() const +{ + ensure(m_program); + + if (!m_shader_interpreter.is_interpreter(m_program)) + { + return { &m_vertex_prog->binding_table, &m_fragment_prog->binding_table }; + } + + const auto& [vs, fs] = m_shader_interpreter.get_shaders(); + return { &vs->binding_table, &fs->binding_table }; +} + bool VKGSRender::is_current_program_interpreted() const { return m_program && m_shader_interpreter.is_interpreter(m_program); diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.h b/rpcs3/Emu/RSX/VK/VKGSRender.h index 61dc496402..107da8ebf2 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.h +++ b/rpcs3/Emu/RSX/VK/VKGSRender.h @@ -26,6 +26,9 @@ using namespace vk::vmm_allocation_pool_; // clang workaround. using namespace vk::upscaling_flags_; // ditto +using vs_binding_table_t = decltype(VKVertexProgram::binding_table); +using fs_binding_table_t = decltype(VKFragmentProgram::binding_table); + namespace vk { using host_data_t = rsx::host_gpu_context_t; @@ -53,6 +56,9 @@ private: vk::glsl::program *m_prev_program = nullptr; vk::pipeline_props m_pipeline_properties; + const vs_binding_table_t* m_vs_binding_table = nullptr; + const fs_binding_table_t* m_fs_binding_table = nullptr; + vk::texture_cache m_texture_cache; vk::surface_cache m_rtts; @@ -78,6 +84,8 @@ private: VkDependencyInfoKHR m_async_compute_dependency_info {}; VkMemoryBarrier2KHR m_async_compute_memory_barrier {}; + std::pair get_binding_table() const; + public: //vk::fbo draw_fbo; std::unique_ptr m_vertex_cache; diff --git a/rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp b/rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp index e7c4862dbc..4ab6a0fa3d 100644 --- a/rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp +++ b/rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp @@ -12,23 +12,70 @@ namespace vk { - glsl::shader* shader_interpreter::build_vs(u64 compiler_options) + u32 shader_interpreter::init(VKVertexProgram* vk_prog, u64 compiler_options) const + { + std::memset(&vk_prog->binding_table, 0xff, sizeof(vk_prog->binding_table)); + + u32 location = 0; + vk_prog->binding_table.vertex_buffers_location = location; + location += 3; + + vk_prog->binding_table.context_buffer_location = location++; + + if (vk::emulate_conditional_rendering()) + { + vk_prog->binding_table.cr_pred_buffer_location = location++; + } + + if (compiler_options & program_common::interpreter::COMPILER_OPT_ENABLE_INSTANCING) + { + vk_prog->binding_table.instanced_lut_buffer_location = location++; + vk_prog->binding_table.instanced_cbuf_location = location++; + } + else + { + vk_prog->binding_table.cbuf_location = location++; + } + + if (vk::emulate_conditional_rendering()) + { + vk_prog->binding_table.cr_pred_buffer_location = location++; + } + + // Return next index + return location; + } + + u32 shader_interpreter::init(VKFragmentProgram* vk_prog, u64 compiler_opt) const + { + std::memset(&vk_prog->binding_table, 0xff, sizeof(vk_prog->binding_table)); + + vk_prog->binding_table.context_buffer_location = 0; + vk_prog->binding_table.tex_param_location = 1; + vk_prog->binding_table.polygon_stipple_params_location = 2; + + // Return next index + return 3; + } + + VKVertexProgram* shader_interpreter::build_vs(u64 compiler_options) { ::glsl::shader_properties properties{}; properties.domain = ::glsl::program_domain::glsl_vertex_program; properties.require_lit_emulation = true; - // TODO: Extend decompiler thread - // TODO: Rename decompiler thread, it no longer spawns a thread RSXVertexProgram null_prog; std::string shader_str; ParamArray arr; - VKVertexProgram vk_prog; + + // Initialize binding layout + auto vk_prog = std::make_unique(); + m_vertex_instruction_start = init(vk_prog.get(), compiler_options); null_prog.ctrl = (compiler_options & program_common::interpreter::COMPILER_OPT_ENABLE_INSTANCING) ? RSX_SHADER_CONTROL_INSTANCED_CONSTANTS : 0; - VKVertexDecompilerThread comp(null_prog, shader_str, arr, vk_prog); + VKVertexDecompilerThread comp(null_prog, shader_str, arr, *vk_prog); // Initialize compiler properties comp.properties.has_indexed_constants = true; @@ -52,6 +99,12 @@ namespace vk " uvec4 vp_instructions[];\n" "};\n\n"; + if (compiler_options & program_common::interpreter::COMPILER_OPT_ENABLE_VTX_TEXTURES) + { + // FIXME: Unimplemented + rsx_log.todo("Vertex textures are currently not implemented for the shader interpreter."); + } + if (compiler_options & program_common::interpreter::COMPILER_OPT_ENABLE_INSTANCING) { builder << "#define _ENABLE_INSTANCED_CONSTANTS\n"; @@ -68,48 +121,29 @@ namespace vk builder << program_common::interpreter::get_vertex_interpreter(); const std::string s = builder.str(); - auto vs = std::make_unique(); + auto vs = &vk_prog->shader; vs->create(::glsl::program_domain::glsl_vertex_program, s); vs->compile(); - // Prepare input table - const auto& binding_table = vk::get_current_renderer()->get_pipeline_binding_table(); + // Declare local inputs + auto vs_inputs = comp.get_inputs(); + vk::glsl::program_input in; - - in.location = binding_table.vertex_params_bind_slot; + in.set = 0; in.domain = ::glsl::glsl_vertex_program; - in.name = "VertexContextBuffer"; - in.type = vk::glsl::input_type_uniform_buffer; - m_vs_inputs.push_back(in); + in.location = m_vertex_instruction_start; + in.type = glsl::input_type_storage_buffer; + in.name = "VertexInstructionBlock"; + vs_inputs.push_back(in); - in.location = binding_table.vertex_buffers_first_bind_slot; - in.name = "persistent_input_stream"; - in.type = vk::glsl::input_type_texel_buffer; - m_vs_inputs.push_back(in); + vk_prog->SetInputs(vs_inputs); - in.location = binding_table.vertex_buffers_first_bind_slot + 1; - in.name = "volatile_input_stream"; - in.type = vk::glsl::input_type_texel_buffer; - m_vs_inputs.push_back(in); - - in.location = binding_table.vertex_buffers_first_bind_slot + 2; - in.name = "vertex_layout_stream"; - in.type = vk::glsl::input_type_texel_buffer; - m_vs_inputs.push_back(in); - - in.location = binding_table.vertex_constant_buffers_bind_slot; - in.name = "VertexConstantsBuffer"; - in.type = vk::glsl::input_type_uniform_buffer; - m_vs_inputs.push_back(in); - - // TODO: Bind textures if needed - - auto ret = vs.get(); - m_shader_cache[compiler_options].m_vs = std::move(vs); + auto ret = vk_prog.get(); + m_shader_cache[compiler_options].m_vs = std::move(vk_prog); return ret; } - glsl::shader* shader_interpreter::build_fs(u64 compiler_options) + VKFragmentProgram* shader_interpreter::build_fs(u64 compiler_options) { [[maybe_unused]] ::glsl::shader_properties properties{}; properties.domain = ::glsl::program_domain::glsl_fragment_program; @@ -120,10 +154,13 @@ namespace vk ParamArray arr; std::string shader_str; RSXFragmentProgram frag; - VKFragmentProgram vk_prog; - VKFragmentDecompilerThread comp(shader_str, arr, frag, len, vk_prog); - const auto& binding_table = vk::get_current_renderer()->get_pipeline_binding_table(); + auto vk_prog = std::make_unique(); + m_fragment_instruction_start = init(vk_prog.get(), compiler_options); + m_fragment_textures_start = m_fragment_instruction_start + 1; + + VKFragmentDecompilerThread comp(shader_str, arr, frag, len, *vk_prog); + std::stringstream builder; builder << "#version 450\n" @@ -199,7 +236,7 @@ namespace vk for (int i = 0, bind_location = m_fragment_textures_start; i < 4; ++i) { - builder << "layout(set=0, binding=" << bind_location++ << ") " << "uniform " << type_names[i] << " " << type_names[i] << "_array[16];\n"; + builder << "layout(set=1, binding=" << bind_location++ << ") " << "uniform " << type_names[i] << " " << type_names[i] << "_array[16];\n"; } builder << "\n" @@ -211,7 +248,7 @@ namespace vk } builder << - "layout(std430, binding=" << m_fragment_instruction_start << ") readonly restrict buffer FragmentInstructionBlock\n" + "layout(std430, set=1, binding=" << m_fragment_instruction_start << ") readonly restrict buffer FragmentInstructionBlock\n" "{\n" " uint shader_control;\n" " uint texture_control;\n" @@ -223,140 +260,35 @@ namespace vk builder << program_common::interpreter::get_fragment_interpreter(); const std::string s = builder.str(); - auto fs = std::make_unique(); + auto fs = &vk_prog->shader; fs->create(::glsl::program_domain::glsl_fragment_program, s); fs->compile(); - // Prepare input table + // Declare local inputs + auto inputs = comp.get_inputs(); + vk::glsl::program_input in; - in.location = binding_table.fragment_constant_buffers_bind_slot; + in.set = 1; in.domain = ::glsl::glsl_fragment_program; - in.name = "FragmentConstantsBuffer"; - in.type = vk::glsl::input_type_uniform_buffer; - m_fs_inputs.push_back(in); - - in.location = binding_table.fragment_state_bind_slot; - in.name = "FragmentStateBuffer"; - m_fs_inputs.push_back(in); - - in.location = binding_table.fragment_texture_params_bind_slot; - in.name = "TextureParametersBuffer"; - m_fs_inputs.push_back(in); + in.location = m_fragment_instruction_start; + in.type = glsl::input_type_storage_buffer; + in.name = "FragmentInstructionBlock"; + inputs.push_back(in); for (int i = 0, location = m_fragment_textures_start; i < 4; ++i, ++location) { in.location = location; in.name = std::string(type_names[i]) + "_array[16]"; - m_fs_inputs.push_back(in); + in.type = glsl::input_type_texture; + inputs.push_back(in); } - auto ret = fs.get(); - m_shader_cache[compiler_options].m_fs = std::move(fs); + vk_prog->SetInputs(inputs); + + auto ret = vk_prog.get(); + m_shader_cache[compiler_options].m_fs = std::move(vk_prog); return ret; } -/* - std::pair shader_interpreter::create_layout(VkDevice dev) - { - const auto& binding_table = vk::get_current_renderer()->get_pipeline_binding_table(); - auto bindings = get_common_binding_table(); - u32 idx = ::size32(bindings); - - bindings.resize(binding_table.total_descriptor_bindings); - - // Texture 1D array - bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - bindings[idx].descriptorCount = 16; - bindings[idx].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - bindings[idx].binding = binding_table.textures_first_bind_slot; - bindings[idx].pImmutableSamplers = nullptr; - - m_fragment_textures_start = bindings[idx].binding; - idx++; - - // Texture 2D array - bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - bindings[idx].descriptorCount = 16; - bindings[idx].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - bindings[idx].binding = binding_table.textures_first_bind_slot + 1; - bindings[idx].pImmutableSamplers = nullptr; - - idx++; - - // Texture 3D array - bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - bindings[idx].descriptorCount = 16; - bindings[idx].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - bindings[idx].binding = binding_table.textures_first_bind_slot + 2; - bindings[idx].pImmutableSamplers = nullptr; - - idx++; - - // Texture CUBE array - bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - bindings[idx].descriptorCount = 16; - bindings[idx].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - bindings[idx].binding = binding_table.textures_first_bind_slot + 3; - bindings[idx].pImmutableSamplers = nullptr; - - idx++; - - // Vertex texture array (2D only) - bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - bindings[idx].descriptorCount = 4; - bindings[idx].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - bindings[idx].binding = binding_table.textures_first_bind_slot + 4; - bindings[idx].pImmutableSamplers = nullptr; - - idx++; - - // Vertex program ucode block - 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.textures_first_bind_slot + 5; - bindings[idx].pImmutableSamplers = nullptr; - - m_vertex_instruction_start = bindings[idx].binding; - idx++; - - // Fragment program ucode block - bindings[idx].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - bindings[idx].descriptorCount = 1; - bindings[idx].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - bindings[idx].binding = binding_table.textures_first_bind_slot + 6; - bindings[idx].pImmutableSamplers = nullptr; - - m_fragment_instruction_start = bindings[idx].binding; - idx++; - bindings.resize(idx); - - m_descriptor_pool_sizes = get_descriptor_pool_sizes(bindings); - - std::array push_constants; - push_constants[0].offset = 0; - push_constants[0].size = 16; - push_constants[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - - if (vk::emulate_conditional_rendering()) - { - // Conditional render toggle - push_constants[0].size = 20; - } - - const auto set_layout = vk::descriptors::create_layout(bindings); - - VkPipelineLayoutCreateInfo layout_info = {}; - layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - layout_info.setLayoutCount = 1; - layout_info.pSetLayouts = &set_layout; - layout_info.pushConstantRangeCount = 1; - layout_info.pPushConstantRanges = push_constants.data(); - - VkPipelineLayout result; - CHECK_RESULT(vkCreatePipelineLayout(dev, &layout_info, nullptr, &result)); - return { set_layout, result }; - } -*/ void shader_interpreter::init(const vk::render_device& dev) { @@ -366,19 +298,14 @@ namespace vk void shader_interpreter::destroy() { m_program_cache.clear(); - - for (auto &fs : m_shader_cache) - { - fs.second.m_vs->destroy(); - fs.second.m_fs->destroy(); - } - m_shader_cache.clear(); } glsl::program* shader_interpreter::link(const vk::pipeline_props& properties, u64 compiler_opt) { - glsl::shader *fs, *vs; + VKVertexProgram* vs; + VKFragmentProgram* fs; + if (auto found = m_shader_cache.find(compiler_opt); found != m_shader_cache.end()) { fs = found->second.m_fs.get(); @@ -393,12 +320,12 @@ namespace vk VkPipelineShaderStageCreateInfo shader_stages[2] = {}; shader_stages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; shader_stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT; - shader_stages[0].module = vs->get_handle(); + shader_stages[0].module = vs->shader.get_handle(); shader_stages[0].pName = "main"; shader_stages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; shader_stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; - shader_stages[1].module = fs->get_handle(); + shader_stages[1].module = fs->shader.get_handle(); shader_stages[1].pName = "main"; std::vector dynamic_state_descriptors = @@ -464,7 +391,13 @@ namespace vk info.renderPass = vk::get_renderpass(m_device, properties.renderpass_key); auto compiler = vk::get_pipe_compiler(); - auto program = compiler->compile(info, vk::pipe_compiler::COMPILE_INLINE, {}, m_vs_inputs, m_fs_inputs); + auto program = compiler->compile( + info, + vk::pipe_compiler::COMPILE_INLINE | vk::pipe_compiler::SEPARATE_SHADER_OBJECTS, + {}, + vs->uniforms, + fs->uniforms); + return program.release(); } @@ -486,7 +419,8 @@ namespace vk glsl::program* shader_interpreter::get( const vk::pipeline_props& properties, - const program_hash_util::fragment_program_utils::fragment_program_metadata& metadata, + const program_hash_util::fragment_program_utils::fragment_program_metadata& fp_metadata, + const program_hash_util::vertex_program_utils::vertex_program_metadata& vp_metadata, u32 vp_ctrl, u32 fp_ctrl) { @@ -526,11 +460,12 @@ namespace vk if (fp_ctrl & CELL_GCM_SHADER_CONTROL_DEPTH_EXPORT) key.compiler_opt |= program_common::interpreter::COMPILER_OPT_ENABLE_DEPTH_EXPORT; if (fp_ctrl & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS) key.compiler_opt |= program_common::interpreter::COMPILER_OPT_ENABLE_F32_EXPORT; if (fp_ctrl & RSX_SHADER_CONTROL_USES_KIL) key.compiler_opt |= program_common::interpreter::COMPILER_OPT_ENABLE_KIL; - if (metadata.referenced_textures_mask) key.compiler_opt |= program_common::interpreter::COMPILER_OPT_ENABLE_TEXTURES; - if (metadata.has_branch_instructions) key.compiler_opt |= program_common::interpreter::COMPILER_OPT_ENABLE_FLOW_CTRL; - if (metadata.has_pack_instructions) key.compiler_opt |= program_common::interpreter::COMPILER_OPT_ENABLE_PACKING; + if (fp_metadata.referenced_textures_mask) key.compiler_opt |= program_common::interpreter::COMPILER_OPT_ENABLE_TEXTURES; + if (fp_metadata.has_branch_instructions) key.compiler_opt |= program_common::interpreter::COMPILER_OPT_ENABLE_FLOW_CTRL; + if (fp_metadata.has_pack_instructions) key.compiler_opt |= program_common::interpreter::COMPILER_OPT_ENABLE_PACKING; if (rsx::method_registers.polygon_stipple_enabled()) key.compiler_opt |= program_common::interpreter::COMPILER_OPT_ENABLE_STIPPLING; if (vp_ctrl & RSX_SHADER_CONTROL_INSTANCED_CONSTANTS) key.compiler_opt |= program_common::interpreter::COMPILER_OPT_ENABLE_INSTANCING; + if (vp_metadata.referenced_textures_mask) key.compiler_opt |= program_common::interpreter::COMPILER_OPT_ENABLE_VTX_TEXTURES; if (m_current_key == key) [[likely]] { @@ -567,4 +502,16 @@ namespace vk { return m_fragment_instruction_start; } + + std::pair shader_interpreter::get_shaders() const + { + if (auto found = m_shader_cache.find(m_current_key.compiler_opt); found != m_shader_cache.end()) + { + auto fs = found->second.m_fs.get(); + auto vs = found->second.m_vs.get(); + return { vs, fs }; + } + + return { nullptr, nullptr }; + } }; diff --git a/rpcs3/Emu/RSX/VK/VKShaderInterpreter.h b/rpcs3/Emu/RSX/VK/VKShaderInterpreter.h index aeaad698fb..9d934b3ffa 100644 --- a/rpcs3/Emu/RSX/VK/VKShaderInterpreter.h +++ b/rpcs3/Emu/RSX/VK/VKShaderInterpreter.h @@ -5,6 +5,9 @@ #include "vkutils/descriptors.h" #include +class VKVertexProgram; +class VKFragmentProgram; + namespace vk { using ::program_hash_util::fragment_program_utils; @@ -12,9 +15,6 @@ namespace vk class shader_interpreter { - std::vector m_vs_inputs; - std::vector m_fs_inputs; - VkDevice m_device = VK_NULL_HANDLE; glsl::program* m_current_interpreter = nullptr; @@ -39,8 +39,8 @@ namespace vk struct shader_cache_entry_t { - std::unique_ptr m_fs; - std::unique_ptr m_vs; + std::unique_ptr m_fs; + std::unique_ptr m_vs; }; std::unordered_map, key_hasher> m_program_cache; @@ -52,20 +52,27 @@ namespace vk pipeline_key m_current_key{}; - glsl::shader* build_vs(u64 compiler_opt); - glsl::shader* build_fs(u64 compiler_opt); + VKVertexProgram* build_vs(u64 compiler_opt); + VKFragmentProgram* build_fs(u64 compiler_opt); glsl::program* link(const vk::pipeline_props& properties, u64 compiler_opt); + u32 init(VKVertexProgram* vk_prog, u64 compiler_opt) const; + u32 init(VKFragmentProgram* vk_prog, u64 compiler_opt) const; + public: void init(const vk::render_device& dev); void destroy(); glsl::program* get( const vk::pipeline_props& properties, - const program_hash_util::fragment_program_utils::fragment_program_metadata& metadata, + const program_hash_util::fragment_program_utils::fragment_program_metadata& fp_metadata, + const program_hash_util::vertex_program_utils::vertex_program_metadata& vp_metadata, u32 vp_ctrl, u32 fp_ctrl); + // Retrieve the shader components that make up the current interpreter + std::pair get_shaders() const; + bool is_interpreter(const glsl::program* prog) const; u32 get_vertex_instruction_location() const; diff --git a/rpcs3/Emu/RSX/VK/vkutils/device.cpp b/rpcs3/Emu/RSX/VK/vkutils/device.cpp index 85d9148834..907d692e85 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/device.cpp +++ b/rpcs3/Emu/RSX/VK/vkutils/device.cpp @@ -813,7 +813,6 @@ namespace vk memory_map = vk::get_memory_mapping(pdev); m_formats_support = vk::get_optimal_tiling_supported_formats(pdev); - m_pipeline_binding_table = vk::get_pipeline_binding_table(pdev); if (g_cfg.video.disable_vulkan_mem_allocator) { @@ -1148,15 +1147,4 @@ namespace vk return result; } - - pipeline_binding_table get_pipeline_binding_table(const vk::physical_device& dev) - { - pipeline_binding_table result{}; - - // Need to check how many samplers are supported by the driver - const auto usable_samplers = std::min(dev.get_limits().maxPerStageDescriptorSampledImages, 32u); - result.vertex_textures_first_bind_slot = result.textures_first_bind_slot + usable_samplers; - result.total_descriptor_bindings = result.vertex_textures_first_bind_slot + 4; - return result; - } } diff --git a/rpcs3/Emu/RSX/VK/vkutils/device.h b/rpcs3/Emu/RSX/VK/vkutils/device.h index 63e30d3d42..0511802aac 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/device.h +++ b/rpcs3/Emu/RSX/VK/vkutils/device.h @@ -137,7 +137,6 @@ namespace vk physical_device* pgpu = nullptr; memory_type_mapping memory_map{}; gpu_formats_support m_formats_support{}; - pipeline_binding_table m_pipeline_binding_table{}; std::unique_ptr m_allocator; VkDevice dev = VK_NULL_HANDLE; @@ -168,7 +167,6 @@ namespace vk const physical_device& gpu() const { return *pgpu; } const memory_type_mapping& get_memory_mapping() const { return memory_map; } const gpu_formats_support& get_formats_support() const { return m_formats_support; } - const pipeline_binding_table& get_pipeline_binding_table() const { return m_pipeline_binding_table; } const gpu_shader_types_support& get_shader_types_support() const { return pgpu->shader_types_support; } const custom_border_color_features& get_custom_border_color_support() const { return pgpu->custom_border_color_support; } const multidraw_features get_multidraw_support() const { return pgpu->multidraw_support; } @@ -206,7 +204,6 @@ namespace vk memory_type_mapping get_memory_mapping(const physical_device& dev); gpu_formats_support get_optimal_tiling_supported_formats(const physical_device& dev); - pipeline_binding_table get_pipeline_binding_table(const physical_device& dev); extern const render_device* g_render_device; } From 396c4bbdd7202f4debd0ae422416b631bd6e218c Mon Sep 17 00:00:00 2001 From: kd-11 Date: Sun, 22 Jun 2025 19:01:38 +0300 Subject: [PATCH 24/37] vk: Drop obsolete logic around descriptor switching --- rpcs3/Emu/RSX/VK/VKDraw.cpp | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/rpcs3/Emu/RSX/VK/VKDraw.cpp b/rpcs3/Emu/RSX/VK/VKDraw.cpp index 008d51f4bb..ae5348c52f 100644 --- a/rpcs3/Emu/RSX/VK/VKDraw.cpp +++ b/rpcs3/Emu/RSX/VK/VKDraw.cpp @@ -837,36 +837,6 @@ void VKGSRender::emit_geometry(u32 sub_index) vk::clear_status_interrupt(vk::heap_changed); } } - else if (persistent_buffer != old_persistent_buffer || volatile_buffer != old_volatile_buffer) - { - /* - // Need to update descriptors; make a copy for the next draw - VkDescriptorSet previous_set = m_current_frame->descriptor_set.value(); - m_current_frame->descriptor_set.flush(); - m_current_frame->descriptor_set = allocate_descriptor_set(); - rsx::simple_array copy_cmds(binding_table.total_descriptor_bindings); - - for (u32 n = 0; n < binding_table.total_descriptor_bindings; ++n) - { - copy_cmds[n] = - { - VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET, // sType - nullptr, // pNext - previous_set, // srcSet - n, // srcBinding - 0u, // srcArrayElement - m_current_frame->descriptor_set.value(), // dstSet - n, // dstBinding - 0u, // dstArrayElement - 1u // descriptorCount - }; - } - - m_current_frame->descriptor_set.push(copy_cmds); - update_descriptors = true; - */ - fmt::throw_exception("Not implemented"); - } // Update vertex fetch parameters update_vertex_env(sub_index, upload_info); From 5d6b8b20c4ce0afc0410235ac309ee7271a158c4 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Sun, 22 Jun 2025 20:01:39 +0300 Subject: [PATCH 25/37] vk: Fix binding of arrays --- rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp | 51 +++++++++++++++++++++--- rpcs3/Emu/RSX/VK/VKProgramPipeline.h | 10 ++++- rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp | 2 +- 3 files changed, 55 insertions(+), 8 deletions(-) diff --git a/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp b/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp index 967828655e..bd12828e08 100644 --- a/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp +++ b/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp @@ -339,14 +339,23 @@ namespace vk void program::bind_uniform_array(const VkDescriptorImageInfo* image_descriptors, VkDescriptorType type, int count, u32 set_id, u32 binding_point) { + // Non-caching write auto& set = m_sets[set_id]; + auto& arr = set.m_scratch_images_array; + + descriptor_array_ref_t data + { + .first = arr.size(), + .count = static_cast(count) + }; + + arr.reserve(arr.size() + static_cast(count)); for (int i = 0; i < count; ++i) { - if (set.m_descriptor_slots[binding_point + i] != image_descriptors[i]) - { - set.notify_descriptor_slot_updated(binding_point + i, image_descriptors[i]); - } + arr.push_back(image_descriptors[i]); } + + set.notify_descriptor_slot_updated(binding_point, data); } void program::create_pipeline_layout() @@ -499,6 +508,14 @@ namespace vk return; } + if (auto ptr = std::get_if(&slot)) + { + ensure(type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER); // Only type supported at the moment + ensure((ptr->first + ptr->count) <= m_scratch_images_array.size()); + m_descriptor_set.push(m_scratch_images_array.data() + ptr->first, ptr->count, type, idx); + return; + } + fmt::throw_exception("Unexpected descriptor structure at index %u", idx); }; @@ -521,6 +538,7 @@ namespace vk m_descriptor_set.on_bind(); m_any_descriptors_dirty = false; + m_scratch_images_array.clear(); return m_descriptor_set.value(); } @@ -537,6 +555,27 @@ namespace vk std::unordered_map descriptor_type_map; + auto descriptor_count = [](const std::string& name) -> u32 + { + const auto start = name.find_last_of("["); + if (start == std::string::npos) + { + return 1; + } + + const auto end = name.find_last_of("]"); + ensure(end != std::string::npos && start < end, "Invalid variable name"); + + const std::string array_size = name.substr(start + 1, end - start - 1); + if (const auto count = std::atoi(array_size.c_str()); + count > 0) + { + return count; + } + + return 1; + }; + for (const auto& type_arr : m_inputs) { if (type_arr.empty() || type_arr.front().type == input_type_push_constant) @@ -553,13 +592,13 @@ namespace vk { .binding = input.location, .descriptorType = type, - .descriptorCount = 1, + .descriptorCount = descriptor_count(input.name), .stageFlags = to_shader_stage_flags(input.domain) }; bindings.push_back(binding); descriptor_type_map[input.location] = type; - m_descriptor_pool_sizes.back().descriptorCount++; + m_descriptor_pool_sizes.back().descriptorCount += binding.descriptorCount; } } diff --git a/rpcs3/Emu/RSX/VK/VKProgramPipeline.h b/rpcs3/Emu/RSX/VK/VKProgramPipeline.h index 81c3ff8525..4b38d23fb8 100644 --- a/rpcs3/Emu/RSX/VK/VKProgramPipeline.h +++ b/rpcs3/Emu/RSX/VK/VKProgramPipeline.h @@ -109,7 +109,13 @@ namespace vk VkShaderModule get_handle() const; }; - using descriptor_slot_t = std::variant; + struct descriptor_array_ref_t + { + u32 first = 0; + u32 count = 0; + }; + + using descriptor_slot_t = std::variant; struct descriptor_table_t { @@ -126,6 +132,8 @@ namespace vk std::vector m_descriptors_dirty; bool m_any_descriptors_dirty = false; + rsx::simple_array< VkDescriptorImageInfo> m_scratch_images_array; + void init(VkDevice dev); void destroy(); diff --git a/rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp b/rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp index 4ab6a0fa3d..760e069fb6 100644 --- a/rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp +++ b/rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp @@ -404,7 +404,7 @@ namespace vk void shader_interpreter::update_fragment_textures(const std::array& sampled_images) { // FIXME: Cannot use m_fragment_textures.start now since each interpreter has its own binding layout - auto [set, binding] = m_current_interpreter->get_uniform_location(::glsl::glsl_fragment_program, glsl::input_type_texture, "texture1D_array"); + auto [set, binding] = m_current_interpreter->get_uniform_location(::glsl::glsl_fragment_program, glsl::input_type_texture, "sampler1D_array[16]"); if (binding == umax) { return; From 37c4406b23a1cb9a45a787a7a930686feb26b36e Mon Sep 17 00:00:00 2001 From: kd-11 Date: Mon, 23 Jun 2025 00:57:30 +0300 Subject: [PATCH 26/37] Remove unused file --- rpcs3/Emu/RSX/VK/VKProgramHelper.hpp | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 rpcs3/Emu/RSX/VK/VKProgramHelper.hpp diff --git a/rpcs3/Emu/RSX/VK/VKProgramHelper.hpp b/rpcs3/Emu/RSX/VK/VKProgramHelper.hpp deleted file mode 100644 index 328df80f1d..0000000000 --- a/rpcs3/Emu/RSX/VK/VKProgramHelper.hpp +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include "VKProgramPipeline.h" - -namespace vk -{ - namespace glsl - { - - } -} - From 8130babad3ebe23d1f7899348b4c2af8372b67e7 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Mon, 23 Jun 2025 01:36:18 +0300 Subject: [PATCH 27/37] vk: Fix crash when running MSAA resolve shaders --- rpcs3/Emu/RSX/VK/VKResolveHelper.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/rpcs3/Emu/RSX/VK/VKResolveHelper.h b/rpcs3/Emu/RSX/VK/VKResolveHelper.h index a9064eff95..05ea997096 100644 --- a/rpcs3/Emu/RSX/VK/VKResolveHelper.h +++ b/rpcs3/Emu/RSX/VK/VKResolveHelper.h @@ -16,7 +16,9 @@ namespace vk u32 cs_wave_y = 1; cs_resolve_base() - {} + { + ssbo_count = 0; + } virtual ~cs_resolve_base() {} From 3f635033cce8ee4990d7c3321fe8a6509c9e1922 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Mon, 23 Jun 2025 01:43:31 +0300 Subject: [PATCH 28/37] vk: Cleanup compiler warnings --- rpcs3/Emu/RSX/VK/VKCompute.cpp | 2 +- rpcs3/Emu/RSX/VK/VKCompute.h | 2 +- rpcs3/Emu/RSX/VK/VKDraw.cpp | 3 --- rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp | 3 --- rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp | 2 +- rpcs3/Emu/RSX/VK/VKProgramPipeline.h | 4 ++-- rpcs3/Emu/RSX/VK/VKResolveHelper.h | 2 +- rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp | 4 ++-- rpcs3/Emu/RSX/VK/upscalers/fsr1/fsr_pass.cpp | 2 +- 9 files changed, 9 insertions(+), 15 deletions(-) diff --git a/rpcs3/Emu/RSX/VK/VKCompute.cpp b/rpcs3/Emu/RSX/VK/VKCompute.cpp index 9d91773988..3df2c9695a 100644 --- a/rpcs3/Emu/RSX/VK/VKCompute.cpp +++ b/rpcs3/Emu/RSX/VK/VKCompute.cpp @@ -353,7 +353,7 @@ namespace vk m_src = fmt::replace_all(m_src, syntax_replace); } - void cs_aggregator::bind_resources(const vk::command_buffer& cmd) + 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); diff --git a/rpcs3/Emu/RSX/VK/VKCompute.h b/rpcs3/Emu/RSX/VK/VKCompute.h index 0dfa80f4f5..5d20a60391 100644 --- a/rpcs3/Emu/RSX/VK/VKCompute.h +++ b/rpcs3/Emu/RSX/VK/VKCompute.h @@ -35,7 +35,7 @@ namespace vk void destroy(); virtual std::vector get_inputs(); - virtual void bind_resources(const vk::command_buffer& cmd) {} + virtual void bind_resources(const vk::command_buffer& /*cmd*/) {} void load_program(const vk::command_buffer& cmd); diff --git a/rpcs3/Emu/RSX/VK/VKDraw.cpp b/rpcs3/Emu/RSX/VK/VKDraw.cpp index ae5348c52f..2a6d195bef 100644 --- a/rpcs3/Emu/RSX/VK/VKDraw.cpp +++ b/rpcs3/Emu/RSX/VK/VKDraw.cpp @@ -761,9 +761,6 @@ void VKGSRender::emit_geometry(u32 sub_index) return; } - const auto old_persistent_buffer = m_persistent_attribute_storage ? m_persistent_attribute_storage->value : null_buffer_view->value; - const auto old_volatile_buffer = m_volatile_attribute_storage ? m_volatile_attribute_storage->value : null_buffer_view->value; - // Programs data is dependent on vertex state auto upload_info = upload_vertex_data(); if (!upload_info.vertex_draw_count) diff --git a/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp b/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp index 94012840ec..040d528218 100644 --- a/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp +++ b/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp @@ -62,7 +62,6 @@ void VKFragmentDecompilerThread::prepareBindingTable() if (has_textures) [[ likely ]] { - unsigned num_textures = 0; for (const ParamType& PT : m_parr.params[PF_PARAM_UNIFORM]) { if (!PT.type.starts_with("sampler")) @@ -72,8 +71,6 @@ void VKFragmentDecompilerThread::prepareBindingTable() for (const ParamItem& PI : PT.items) { - num_textures++; - const auto texture_id = vk::get_texture_index(PI.name); const auto mask = 1u << texture_id; diff --git a/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp b/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp index bd12828e08..aae8407103 100644 --- a/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp +++ b/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp @@ -337,7 +337,7 @@ namespace vk m_sets[set_id].notify_descriptor_slot_updated(binding_point, buffer_view); } - void program::bind_uniform_array(const VkDescriptorImageInfo* image_descriptors, VkDescriptorType type, int count, u32 set_id, u32 binding_point) + void program::bind_uniform_array(const VkDescriptorImageInfo* image_descriptors, int count, u32 set_id, u32 binding_point) { // Non-caching write auto& set = m_sets[set_id]; diff --git a/rpcs3/Emu/RSX/VK/VKProgramPipeline.h b/rpcs3/Emu/RSX/VK/VKProgramPipeline.h index 4b38d23fb8..c7faaa8c37 100644 --- a/rpcs3/Emu/RSX/VK/VKProgramPipeline.h +++ b/rpcs3/Emu/RSX/VK/VKProgramPipeline.h @@ -170,7 +170,7 @@ namespace vk class program { - VkDevice m_device = VK_NULL_HANDLE; + VkDevice m_device = VK_NULL_HANDLE; VkPipeline m_pipeline = VK_NULL_HANDLE; VkPipelineLayout m_pipeline_layout = VK_NULL_HANDLE; @@ -202,7 +202,7 @@ namespace vk 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_array(const VkDescriptorImageInfo* image_descriptors, VkDescriptorType type, int count, u32 set_id, u32 binding_point); + void bind_uniform_array(const VkDescriptorImageInfo* image_descriptors, int count, u32 set_id, u32 binding_point); inline VkPipelineLayout layout() const { return m_pipeline_layout; } inline VkPipeline value() const { return m_pipeline; } diff --git a/rpcs3/Emu/RSX/VK/VKResolveHelper.h b/rpcs3/Emu/RSX/VK/VKResolveHelper.h index 05ea997096..23d243b032 100644 --- a/rpcs3/Emu/RSX/VK/VKResolveHelper.h +++ b/rpcs3/Emu/RSX/VK/VKResolveHelper.h @@ -51,7 +51,7 @@ namespace vk return result; } - void bind_resources(const vk::command_buffer& cmd) override + void bind_resources(const vk::command_buffer& /*cmd*/) override { auto msaa_view = multisampled->get_view(rsx::default_remap_vector.with_encoding(VK_REMAP_VIEW_MULTISAMPLED)); auto resolved_view = resolve->get_view(rsx::default_remap_vector.with_encoding(VK_REMAP_IDENTITY)); diff --git a/rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp b/rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp index 760e069fb6..d389423dd2 100644 --- a/rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp +++ b/rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp @@ -46,7 +46,7 @@ namespace vk return location; } - u32 shader_interpreter::init(VKFragmentProgram* vk_prog, u64 compiler_opt) const + u32 shader_interpreter::init(VKFragmentProgram* vk_prog, u64 /*compiler_opt*/) const { std::memset(&vk_prog->binding_table, 0xff, sizeof(vk_prog->binding_table)); @@ -413,7 +413,7 @@ namespace vk const VkDescriptorImageInfo* texture_ptr = sampled_images.data(); for (u32 i = 0; i < 4; ++i, ++binding, texture_ptr += 16) { - m_current_interpreter->bind_uniform_array(texture_ptr, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 16, set, binding); + m_current_interpreter->bind_uniform_array(texture_ptr, 16, set, binding); } } diff --git a/rpcs3/Emu/RSX/VK/upscalers/fsr1/fsr_pass.cpp b/rpcs3/Emu/RSX/VK/upscalers/fsr1/fsr_pass.cpp index 23a4733c60..dc6562289e 100644 --- a/rpcs3/Emu/RSX/VK/upscalers/fsr1/fsr_pass.cpp +++ b/rpcs3/Emu/RSX/VK/upscalers/fsr1/fsr_pass.cpp @@ -97,7 +97,7 @@ namespace vk return result; } - void fsr_pass::bind_resources(const vk::command_buffer& cmd) + void fsr_pass::bind_resources(const vk::command_buffer& /*cmd*/) { // Bind relevant stuff if (!m_sampler) From 1f0328c5d5fc4ba60e552734a3e545ed5c0643d7 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Tue, 24 Jun 2025 03:59:29 +0300 Subject: [PATCH 29/37] vk: Fix up binding layouts for some broken shaders --- rpcs3/Emu/RSX/Program/GLSLSnippets/OverlayRenderFS.glsl | 4 ++-- rpcs3/Emu/RSX/VK/VKOverlays.cpp | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/rpcs3/Emu/RSX/Program/GLSLSnippets/OverlayRenderFS.glsl b/rpcs3/Emu/RSX/Program/GLSLSnippets/OverlayRenderFS.glsl index de1992174f..84fdfdb8b7 100644 --- a/rpcs3/Emu/RSX/Program/GLSLSnippets/OverlayRenderFS.glsl +++ b/rpcs3/Emu/RSX/Program/GLSLSnippets/OverlayRenderFS.glsl @@ -14,8 +14,8 @@ R"( #define SAMPLER_MODE_TEXTURE2D 3 #ifdef VULKAN - layout(set=0, binding=1) uniform sampler2D fs0; - layout(set=0, binding=2) uniform sampler2DArray fs1; + layout(set=0, binding=0) uniform sampler2D fs0; + layout(set=0, binding=1) uniform sampler2DArray fs1; #else layout(binding=31) uniform sampler2D fs0; layout(binding=30) uniform sampler2DArray fs1; diff --git a/rpcs3/Emu/RSX/VK/VKOverlays.cpp b/rpcs3/Emu/RSX/VK/VKOverlays.cpp index 743339e26c..70d9a7ab49 100644 --- a/rpcs3/Emu/RSX/VK/VKOverlays.cpp +++ b/rpcs3/Emu/RSX/VK/VKOverlays.cpp @@ -310,6 +310,7 @@ namespace vk // 2 input textures m_num_usable_samplers = 2; + m_num_uniform_buffers = 0; renderpass_config.set_attachment_count(1); renderpass_config.set_color_mask(0, true, true, true, true); @@ -807,6 +808,9 @@ namespace vk "{\n" " out_color = vec4(0.);\n" "}\n"; + + m_num_uniform_buffers = 0; + m_num_usable_samplers = 0; } void stencil_clear_pass::set_up_viewport(vk::command_buffer& cmd, u32 x, u32 y, u32 w, u32 h) @@ -865,6 +869,7 @@ namespace vk renderpass_config.set_attachment_count(1); m_num_usable_samplers = 2; + m_num_uniform_buffers = 0; } std::vector video_out_calibration_pass::get_fragment_inputs() From 3df93dcc19cef542d3080d07b61873365f7993ac Mon Sep 17 00:00:00 2001 From: kd-11 Date: Tue, 24 Jun 2025 04:22:36 +0300 Subject: [PATCH 30/37] vk: Fix shader interpreter inputs when textures are not used --- rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp b/rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp index d389423dd2..c80fb7873d 100644 --- a/rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp +++ b/rpcs3/Emu/RSX/VK/VKShaderInterpreter.cpp @@ -275,12 +275,15 @@ namespace vk in.name = "FragmentInstructionBlock"; inputs.push_back(in); - for (int i = 0, location = m_fragment_textures_start; i < 4; ++i, ++location) + if (compiler_options & program_common::interpreter::COMPILER_OPT_ENABLE_TEXTURES) { - in.location = location; - in.name = std::string(type_names[i]) + "_array[16]"; - in.type = glsl::input_type_texture; - inputs.push_back(in); + for (int i = 0, location = m_fragment_textures_start; i < 4; ++i, ++location) + { + in.location = location; + in.name = std::string(type_names[i]) + "_array[16]"; + in.type = glsl::input_type_texture; + inputs.push_back(in); + } } vk_prog->SetInputs(inputs); From aa50b0fbb99c04918645a78acd1fcab8a1cf31b2 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Wed, 25 Jun 2025 01:44:04 +0300 Subject: [PATCH 31/37] vk: Fix video-out calibration pass inputs --- rpcs3/Emu/RSX/VK/VKOverlays.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rpcs3/Emu/RSX/VK/VKOverlays.cpp b/rpcs3/Emu/RSX/VK/VKOverlays.cpp index 70d9a7ab49..34ca64ca66 100644 --- a/rpcs3/Emu/RSX/VK/VKOverlays.cpp +++ b/rpcs3/Emu/RSX/VK/VKOverlays.cpp @@ -859,7 +859,7 @@ namespace vk std::pair repl_list[] = { - { "%sampler_binding", fmt::format("(%d + x)", sampler_location(0)) }, + { "%sampler_binding", "x" }, { "%set_decorator", "set=0" }, }; fs_src = fmt::replace_all(fs_src, repl_list); From 1660dc24b385292bc35c0ddb0454acb5e5299e91 Mon Sep 17 00:00:00 2001 From: Elad <18193363+knight4u32@users.noreply.github.com> Date: Sun, 22 Jun 2025 20:57:47 +0300 Subject: [PATCH 32/37] cellSaveData: Order equal elements using the opposing trait --- rpcs3/Emu/Cell/Modules/cellSaveData.cpp | 64 ++++++++++++++++++------- rpcs3/util/logs.cpp | 5 ++ 2 files changed, 52 insertions(+), 17 deletions(-) diff --git a/rpcs3/Emu/Cell/Modules/cellSaveData.cpp b/rpcs3/Emu/Cell/Modules/cellSaveData.cpp index 00d2d385f9..7ae96fa64d 100644 --- a/rpcs3/Emu/Cell/Modules/cellSaveData.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSaveData.cpp @@ -700,11 +700,32 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v u32 errDialog, PSetList setList, PSetBuf setBuf, PFuncList funcList, PFuncFixed funcFixed, PFuncStat funcStat, PFuncFile funcFile, u32 container, u32 unk_op_flags /*TODO*/, vm::ptr userdata, u32 userId, PFuncDone funcDone) { - if (const auto& [ok, list] = setList.try_read(); ok) - cellSaveData.notice("savedata_op(): setList = { .sortType=%d, .sortOrder=%d, .dirNamePrefix='%s' }", list.sortType, list.sortOrder, list.dirNamePrefix); + if (setList) + { + if (const auto& [ok, list] = setList.try_read(); ok) + { + cellSaveData.notice("savedata_op(): setList = { .sortType=%d, .sortOrder=%d, .dirNamePrefix='%s' }", list.sortType, list.sortOrder, list.dirNamePrefix); + } + else + { + cellSaveData.error("savedata_op(): Failed to read setList!"); + } + } - if (const auto& [ok, buf] = setBuf.try_read(); ok) - cellSaveData.notice("savedata_op(): setBuf = { .dirListMax=%d, .fileListMax=%d, .bufSize=%d }", buf.dirListMax, buf.fileListMax, buf.bufSize); + if (setBuf) + { + if (const auto& [ok, buf] = setBuf.try_read(); ok) + { + cellSaveData.notice("savedata_op(): setBuf = { .dirListMax=%d, .fileListMax=%d, .bufSize=%d }", buf.dirListMax, buf.fileListMax, buf.bufSize); + } + else + { + cellSaveData.error("savedata_op(): Failed to read setBuf!"); + } + } + + // There is a lot going on in this function, ensure function log and past log commands have completed for ease of debugging + logs::listener::sync_all(); if (const auto ecode = savedata_check_args(operation, version, dirName, errDialog, setList, setBuf, funcList, funcFixed, funcStat, funcFile, container, unk_op_flags, userdata, userId, funcDone)) @@ -858,25 +879,34 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v const u32 order = setList->sortOrder; const u32 type = setList->sortType; - std::sort(save_entries.begin(), save_entries.end(), [=](const SaveDataEntry& entry1, const SaveDataEntry& entry2) + std::sort(save_entries.begin(), save_entries.end(), [order, type](const SaveDataEntry& entry1, const SaveDataEntry& entry2) -> bool { - if (order == CELL_SAVEDATA_SORTORDER_DESCENT && type == CELL_SAVEDATA_SORTTYPE_MODIFIEDTIME) + const bool mtime_lower = entry1.mtime < entry2.mtime; + const bool mtime_equal = entry1.mtime == entry2.mtime; + const bool subtitle_lower = entry1.subtitle < entry2.subtitle; + const bool subtitle_equal = entry1.subtitle == entry2.subtitle; + const bool revert_order = order == CELL_SAVEDATA_SORTORDER_DESCENT; + + if (type == CELL_SAVEDATA_SORTTYPE_MODIFIEDTIME) { - return entry1.mtime > entry2.mtime; + if (mtime_equal) + { + return subtitle_lower != revert_order; + } + + return mtime_lower != revert_order; } - if (order == CELL_SAVEDATA_SORTORDER_DESCENT && type == CELL_SAVEDATA_SORTTYPE_SUBTITLE) + else if (type == CELL_SAVEDATA_SORTTYPE_SUBTITLE) { - return entry1.subtitle > entry2.subtitle; - } - if (order == CELL_SAVEDATA_SORTORDER_ASCENT && type == CELL_SAVEDATA_SORTTYPE_MODIFIEDTIME) - { - return entry1.mtime < entry2.mtime; - } - if (order == CELL_SAVEDATA_SORTORDER_ASCENT && type == CELL_SAVEDATA_SORTTYPE_SUBTITLE) - { - return entry1.subtitle < entry2.subtitle; + if (subtitle_equal) + { + return mtime_lower != revert_order; + } + + return subtitle_lower != revert_order; } + ensure(false); return true; }); } diff --git a/rpcs3/util/logs.cpp b/rpcs3/util/logs.cpp index bcc1235ac7..d48a22c0aa 100644 --- a/rpcs3/util/logs.cpp +++ b/rpcs3/util/logs.cpp @@ -701,6 +701,11 @@ void logs::file_writer::sync() std::this_thread::yield(); } + if (thread_ctrl::get_current()) + { + return; + } + // Ensure written to disk if (m_fout) { From 786ac95dc018bd56874450b48b6cbd2083ef3242 Mon Sep 17 00:00:00 2001 From: Elad <18193363+knight4u32@users.noreply.github.com> Date: Sun, 29 Jun 2025 20:11:49 +0300 Subject: [PATCH 33/37] RawSPU: Add missing MMIO register reads --- rpcs3/Emu/Cell/RawSPUThread.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/rpcs3/Emu/Cell/RawSPUThread.cpp b/rpcs3/Emu/Cell/RawSPUThread.cpp index 86b483d947..81bb6fd89e 100644 --- a/rpcs3/Emu/Cell/RawSPUThread.cpp +++ b/rpcs3/Emu/Cell/RawSPUThread.cpp @@ -130,6 +130,18 @@ bool spu_thread::read_reg(const u32 addr, u32& value) return true; } + case Prxy_QueryMask_offs: + { + value = mfc_prxy_mask; + return true; + } + + case Prxy_QueryType_offs: + { + value = 0; + return true; + } + case SPU_Out_MBox_offs: { value = ch_out_mbox.pop(); @@ -367,6 +379,8 @@ bool spu_thread::test_is_problem_state_register_offset(u32 offset, bool for_read case MFC_QStatus_offs: case SPU_Out_MBox_offs: case SPU_MBox_Status_offs: + case Prxy_QueryType_offs: + case Prxy_QueryMask_offs: case SPU_Status_offs: case Prxy_TagStatus_offs: case SPU_NPC_offs: From bfd2adab5e10e417b1e9dc67a656f92d4d4170dd Mon Sep 17 00:00:00 2001 From: Megamouse Date: Thu, 26 Jun 2025 20:01:34 +0200 Subject: [PATCH 34/37] Fix noexcept warnings in XAudio --- rpcs3/Emu/Audio/XAudio2/XAudio2Backend.cpp | 4 ++-- rpcs3/Emu/Audio/XAudio2/XAudio2Backend.h | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/rpcs3/Emu/Audio/XAudio2/XAudio2Backend.cpp b/rpcs3/Emu/Audio/XAudio2/XAudio2Backend.cpp index 0a84d747bf..b9a4daeecc 100644 --- a/rpcs3/Emu/Audio/XAudio2/XAudio2Backend.cpp +++ b/rpcs3/Emu/Audio/XAudio2/XAudio2Backend.cpp @@ -337,7 +337,7 @@ f64 XAudio2Backend::GetCallbackFrameLen() return std::max(min_latency, _10ms); // 10ms is the minimum for XAudio } -void XAudio2Backend::OnVoiceProcessingPassStart(UINT32 BytesRequired) +void XAudio2Backend::OnVoiceProcessingPassStart(UINT32 BytesRequired) noexcept { std::unique_lock lock(m_cb_mutex, std::defer_lock); if (BytesRequired && !m_reset_req.observe() && lock.try_lock_for(std::chrono::microseconds{50}) && m_write_callback && m_playing) @@ -366,7 +366,7 @@ void XAudio2Backend::OnVoiceProcessingPassStart(UINT32 BytesRequired) } } -void XAudio2Backend::OnCriticalError(HRESULT Error) +void XAudio2Backend::OnCriticalError(HRESULT Error) noexcept { XAudio.error("OnCriticalError() called: %s (0x%08x)", std::system_category().message(Error), static_cast(Error)); diff --git a/rpcs3/Emu/Audio/XAudio2/XAudio2Backend.h b/rpcs3/Emu/Audio/XAudio2/XAudio2Backend.h index 0312e7f633..1bab624d67 100644 --- a/rpcs3/Emu/Audio/XAudio2/XAudio2Backend.h +++ b/rpcs3/Emu/Audio/XAudio2/XAudio2Backend.h @@ -54,18 +54,18 @@ private: atomic_t m_reset_req = false; // XAudio voice callbacks - void OnVoiceProcessingPassStart(UINT32 BytesRequired) override; - void OnVoiceProcessingPassEnd() override {} - void OnStreamEnd() override {} - void OnBufferStart(void* /* pBufferContext */) override {} - void OnBufferEnd(void* /* pBufferContext*/) override {} - void OnLoopEnd(void* /* pBufferContext */) override {} - void OnVoiceError(void* /* pBufferContext */, HRESULT /* Error */) override {} + void OnVoiceProcessingPassStart(UINT32 BytesRequired) noexcept override; + void OnVoiceProcessingPassEnd() noexcept override {} + void OnStreamEnd() noexcept override {} + void OnBufferStart(void* /* pBufferContext */) noexcept override {} + void OnBufferEnd(void* /* pBufferContext*/) noexcept override {} + void OnLoopEnd(void* /* pBufferContext */) noexcept override {} + void OnVoiceError(void* /* pBufferContext */, HRESULT /* Error */) noexcept override {} // XAudio engine callbacks - void OnProcessingPassStart() override {}; - void OnProcessingPassEnd() override {}; - void OnCriticalError(HRESULT Error) override; + void OnProcessingPassStart() noexcept override {}; + void OnProcessingPassEnd() noexcept override {}; + void OnCriticalError(HRESULT Error) noexcept override; // IMMNotificationClient callbacks IFACEMETHODIMP_(ULONG) AddRef() override { return 1; }; From c7c206ecdca0afbd6c454711597ff77d83d02c17 Mon Sep 17 00:00:00 2001 From: Megamouse Date: Thu, 26 Jun 2025 20:02:08 +0200 Subject: [PATCH 35/37] Fix u32 compile error on clang-cl --- rpcs3/Emu/RSX/VK/VKCommandStream.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rpcs3/Emu/RSX/VK/VKCommandStream.h b/rpcs3/Emu/RSX/VK/VKCommandStream.h index 4ee4d00e19..8287094dbd 100644 --- a/rpcs3/Emu/RSX/VK/VKCommandStream.h +++ b/rpcs3/Emu/RSX/VK/VKCommandStream.h @@ -6,7 +6,7 @@ namespace vk { struct fence; - enum // callback commands + enum rctrl_command : u32 // callback commands { rctrl_queue_submit = 0x80000000, rctrl_run_gc = 0x80000001, From 38ff48595d3bbfd010e21e75990f221976042716 Mon Sep 17 00:00:00 2001 From: Megamouse Date: Thu, 26 Jun 2025 20:03:58 +0200 Subject: [PATCH 36/37] Fix missing include on clang-cl --- rpcs3/Emu/NP/rpcn_client.h | 1 + 1 file changed, 1 insertion(+) diff --git a/rpcs3/Emu/NP/rpcn_client.h b/rpcs3/Emu/NP/rpcn_client.h index e3d2fb0299..28200d7a2f 100644 --- a/rpcs3/Emu/NP/rpcn_client.h +++ b/rpcs3/Emu/NP/rpcn_client.h @@ -9,6 +9,7 @@ #ifdef _WIN32 #include +#include #else #ifdef __clang__ #pragma GCC diagnostic push From 20c9dcd2d6dbac8d2c1a4b1aab88d995ed6dc72e Mon Sep 17 00:00:00 2001 From: Megamouse Date: Thu, 26 Jun 2025 20:06:06 +0200 Subject: [PATCH 37/37] Remove qstr, sstr and qsv aliases. This does not compile on clang-cl --- rpcs3/rpcs3qt/debugger_frame.cpp | 8 +- rpcs3/rpcs3qt/debugger_list.cpp | 12 +-- rpcs3/rpcs3qt/emu_settings.h | 2 - rpcs3/rpcs3qt/game_compatibility.cpp | 18 ++-- rpcs3/rpcs3qt/game_list_frame.cpp | 48 ++++----- rpcs3/rpcs3qt/instruction_editor_dialog.cpp | 10 +- rpcs3/rpcs3qt/kernel_explorer.cpp | 110 ++++++++++---------- rpcs3/rpcs3qt/main_window.cpp | 88 ++++++++-------- rpcs3/rpcs3qt/memory_viewer_panel.cpp | 28 +++-- rpcs3/rpcs3qt/pad_settings_dialog.cpp | 8 +- rpcs3/rpcs3qt/qt_utils.cpp | 10 +- rpcs3/rpcs3qt/register_editor_dialog.cpp | 24 ++--- rpcs3/rpcs3qt/rsx_debugger.cpp | 14 ++- rpcs3/rpcs3qt/settings_dialog.cpp | 56 +++++----- rpcs3/rpcs3qt/user_manager_dialog.cpp | 24 ++--- 15 files changed, 214 insertions(+), 246 deletions(-) diff --git a/rpcs3/rpcs3qt/debugger_frame.cpp b/rpcs3/rpcs3qt/debugger_frame.cpp index 502a01dc09..b85aa2859e 100644 --- a/rpcs3/rpcs3qt/debugger_frame.cpp +++ b/rpcs3/rpcs3qt/debugger_frame.cpp @@ -40,8 +40,6 @@ #include "rpcs3qt/debugger_add_bp_window.h" #include "util/asm.hpp" -constexpr auto qstr = QString::fromStdString; - constexpr auto s_pause_flags = cpu_flag::dbg_pause + cpu_flag::dbg_global_pause; extern atomic_t g_debugger_pause_all_threads_on_bp; @@ -1030,7 +1028,7 @@ void debugger_frame::UpdateUnitList() std::function func_cpu = make_check_cpu(std::addressof(cpu), true); // Space at the end is to pad a gap on the right - cpu_list.emplace_back(qstr((id >> 24 == 0x55 ? "RSX[0x55555555]" : cpu.get_name()) + ' '), std::move(func_cpu)); + cpu_list.emplace_back(QString::fromStdString((id >> 24 == 0x55 ? "RSX[0x55555555]" : cpu.get_name()) + ' '), std::move(func_cpu)); if (old_cpu_ptr == std::addressof(cpu)) { @@ -1373,7 +1371,7 @@ void debugger_frame::WritePanels() int loc = m_misc_state->verticalScrollBar()->value(); int hloc = m_misc_state->horizontalScrollBar()->value(); m_misc_state->clear(); - m_misc_state->setPlainText(qstr(cpu->dump_misc())); + m_misc_state->setPlainText(QString::fromStdString(cpu->dump_misc())); m_misc_state->verticalScrollBar()->setValue(loc); m_misc_state->horizontalScrollBar()->setValue(hloc); @@ -1382,7 +1380,7 @@ void debugger_frame::WritePanels() m_regs->clear(); m_last_reg_state.clear(); cpu->dump_regs(m_last_reg_state, m_dump_reg_func_data); - m_regs->setPlainText(qstr(m_last_reg_state)); + m_regs->setPlainText(QString::fromStdString(m_last_reg_state)); m_regs->verticalScrollBar()->setValue(loc); m_regs->horizontalScrollBar()->setValue(hloc); diff --git a/rpcs3/rpcs3qt/debugger_list.cpp b/rpcs3/rpcs3qt/debugger_list.cpp index e398921aaf..757eb9cd98 100644 --- a/rpcs3/rpcs3qt/debugger_list.cpp +++ b/rpcs3/rpcs3qt/debugger_list.cpp @@ -19,8 +19,6 @@ #include -constexpr auto qstr = QString::fromStdString; - debugger_list::debugger_list(QWidget* parent, std::shared_ptr gui_settings, breakpoint_handler* handler) : QListWidget(parent) , m_gui_settings(std::move(gui_settings)) @@ -208,7 +206,7 @@ void debugger_list::ShowAddress(u32 addr, bool select_addr, bool direct) for (uint i = 0; i < m_item_count; ++i) { QListWidgetItem* list_item = item(i); - list_item->setText(qstr(fmt::format(" [%08x] ?? ?? ?? ??:", 0))); + list_item->setText(QString::fromStdString(fmt::format(" [%08x] ?? ?? ?? ??:", 0))); list_item->setForeground(default_foreground); list_item->setBackground(default_background); } @@ -253,7 +251,7 @@ void debugger_list::ShowAddress(u32 addr, bool select_addr, bool direct) if (cpu && cpu->get_class() == thread_class::ppu && !vm::check_addr(pc, 0)) { - list_item->setText((IsBreakpoint(pc) ? ">> " : " ") + qstr(fmt::format("[%08x] ?? ?? ?? ??:", pc))); + list_item->setText((IsBreakpoint(pc) ? ">> " : " ") + QString::fromStdString(fmt::format("[%08x] ?? ?? ?? ??:", pc))); count = 4; continue; } @@ -261,7 +259,7 @@ void debugger_list::ShowAddress(u32 addr, bool select_addr, bool direct) if (cpu && cpu->get_class() == thread_class::ppu && !vm::check_addr(pc, vm::page_executable)) { const u32 data = *vm::get_super_ptr>(pc); - list_item->setText((IsBreakpoint(pc) ? ">> " : " ") + qstr(fmt::format("[%08x] %02x %02x %02x %02x:", pc, + list_item->setText((IsBreakpoint(pc) ? ">> " : " ") + QString::fromStdString(fmt::format("[%08x] %02x %02x %02x %02x:", pc, static_cast(data >> 24), static_cast(data >> 16), static_cast(data >> 8), @@ -274,12 +272,12 @@ void debugger_list::ShowAddress(u32 addr, bool select_addr, bool direct) if (!count) { - list_item->setText((IsBreakpoint(pc) ? ">> " : " ") + qstr(fmt::format("[%08x] ??? ?? ??", pc))); + list_item->setText((IsBreakpoint(pc) ? ">> " : " ") + QString::fromStdString(fmt::format("[%08x] ??? ?? ??", pc))); count = 4; continue; } - list_item->setText((IsBreakpoint(pc) ? ">> " : " ") + qstr(m_disasm->last_opcode)); + list_item->setText((IsBreakpoint(pc) ? ">> " : " ") + QString::fromStdString(m_disasm->last_opcode)); } } diff --git a/rpcs3/rpcs3qt/emu_settings.h b/rpcs3/rpcs3qt/emu_settings.h index 4cd3da262d..5da946dabe 100644 --- a/rpcs3/rpcs3qt/emu_settings.h +++ b/rpcs3/rpcs3qt/emu_settings.h @@ -23,8 +23,6 @@ namespace cfg class _base; } -constexpr auto qstr = QString::fromStdString; - class emu_settings : public QObject { /** A settings class for Emulator specific settings. This class is a refactored version of the wx version. It is much nicer diff --git a/rpcs3/rpcs3qt/game_compatibility.cpp b/rpcs3/rpcs3qt/game_compatibility.cpp index e672cdb508..2d901b6642 100644 --- a/rpcs3/rpcs3qt/game_compatibility.cpp +++ b/rpcs3/rpcs3qt/game_compatibility.cpp @@ -13,8 +13,6 @@ LOG_CHANNEL(compat_log, "Compat"); -constexpr auto qstr = QString::fromStdString; - game_compatibility::game_compatibility(std::shared_ptr gui_settings, QWidget* parent) : QObject(parent) , m_gui_settings(std::move(gui_settings)) @@ -91,7 +89,7 @@ bool game_compatibility::ReadJSON(const QJsonObject& json_data, bool after_downl break; } compat_log.error("%s: return code %d", error_message, return_code); - Q_EMIT DownloadError(qstr(error_message) + " " + QString::number(return_code)); + Q_EMIT DownloadError(QString::fromStdString(error_message) + " " + QString::number(return_code)); } else { @@ -269,10 +267,10 @@ compat::package_info game_compatibility::GetPkgInfo(const QString& pkg_path, gam const std::string changelog_key = "paramhip"; info.path = pkg_path; - info.title = qstr(std::string(psf::get_string(psf, title_key))); // Let's read this from the psf first - info.title_id = qstr(std::string(psf::get_string(psf, "TITLE_ID"))); - info.category = qstr(std::string(psf::get_string(psf, "CATEGORY"))); - info.version = qstr(std::string(psf::get_string(psf, "APP_VER"))); + info.title = QString::fromStdString(std::string(psf::get_string(psf, title_key))); // Let's read this from the psf first + info.title_id = QString::fromStdString(std::string(psf::get_string(psf, "TITLE_ID"))); + info.category = QString::fromStdString(std::string(psf::get_string(psf, "CATEGORY"))); + info.version = QString::fromStdString(std::string(psf::get_string(psf, "APP_VER"))); if (!info.category.isEmpty()) { @@ -306,7 +304,7 @@ compat::package_info game_compatibility::GetPkgInfo(const QString& pkg_path, gam if (info.version.isEmpty()) { // Fallback to VERSION - info.version = qstr(std::string(psf::get_string(psf, "VERSION"))); + info.version = QString::fromStdString(std::string(psf::get_string(psf, "VERSION"))); } if (compat) @@ -321,12 +319,12 @@ compat::package_info game_compatibility::GetPkgInfo(const QString& pkg_path, gam { if (const std::string localized_title = package.get_title(title_key); !localized_title.empty()) { - info.title = qstr(localized_title); + info.title = QString::fromStdString(localized_title); } if (const std::string localized_changelog = package.get_changelog(changelog_key); !localized_changelog.empty()) { - info.changelog = qstr(localized_changelog); + info.changelog = QString::fromStdString(localized_changelog); } // This should be an update since it was found in a patch set diff --git a/rpcs3/rpcs3qt/game_list_frame.cpp b/rpcs3/rpcs3qt/game_list_frame.cpp index 58430bc3b1..3da34c832a 100644 --- a/rpcs3/rpcs3qt/game_list_frame.cpp +++ b/rpcs3/rpcs3qt/game_list_frame.cpp @@ -265,15 +265,15 @@ bool game_list_frame::IsEntryVisible(const game_info& game, bool search_fallback { if (m_is_list_layout) { - return m_category_filters.contains(qstr(game->info.category)); + return m_category_filters.contains(QString::fromStdString(game->info.category)); } - return m_grid_category_filters.contains(qstr(game->info.category)); + return m_grid_category_filters.contains(QString::fromStdString(game->info.category)); }; - const QString serial = qstr(game->info.serial); + const QString serial = QString::fromStdString(game->info.serial); const bool is_visible = m_show_hidden || !m_hidden_list.contains(serial); - return is_visible && matches_category() && SearchMatchesApp(qstr(game->info.name), serial, search_fallback); + return is_visible && matches_category() && SearchMatchesApp(QString::fromStdString(game->info.name), serial, search_fallback); } bool game_list_frame::RemoveContentPath(const std::string& path, const std::string& desc) @@ -1068,7 +1068,7 @@ void game_list_frame::CreateShortcuts(const std::vector& games, const if (!fs::create_path(target_icon_dir)) { - game_list_log.error("Failed to create shortcut path %s (%s)", qstr(gameinfo->info.name).simplified(), target_icon_dir, fs::g_tls_error); + game_list_log.error("Failed to create shortcut path %s (%s)", QString::fromStdString(gameinfo->info.name).simplified(), target_icon_dir, fs::g_tls_error); success = false; continue; } @@ -1094,11 +1094,11 @@ void game_list_frame::CreateShortcuts(const std::vector& games, const if (!gameid_token_value.empty() && gui::utils::create_shortcut(gameinfo->info.name, gameinfo->info.serial, target_cli_args, gameinfo->info.name, gameinfo->info.icon_path, target_icon_dir, location)) { - game_list_log.success("Created %s shortcut for %s", destination, qstr(gameinfo->info.name).simplified()); + game_list_log.success("Created %s shortcut for %s", destination, QString::fromStdString(gameinfo->info.name).simplified()); } else { - game_list_log.error("Failed to create %s shortcut for %s", destination, qstr(gameinfo->info.name).simplified()); + game_list_log.error("Failed to create %s shortcut for %s", destination, QString::fromStdString(gameinfo->info.name).simplified()); success = false; } } @@ -1144,8 +1144,8 @@ void game_list_frame::ShowContextMenu(const QPoint &pos) } GameInfo current_game = gameinfo->info; - const QString serial = qstr(current_game.serial); - const QString name = qstr(current_game.name).simplified(); + const QString serial = QString::fromStdString(current_game.serial); + const QString name = QString::fromStdString(current_game.name).simplified(); const std::string cache_base_dir = GetCacheDirBySerial(current_game.serial); const std::string config_data_base_dir = GetDataDirBySerial(current_game.serial); @@ -1520,7 +1520,7 @@ void game_list_frame::ShowContextMenu(const QPoint &pos) for (const auto& [type, icon_name, suffix, actions] : icon_map) { - const QString icon_path = qstr(custom_icon_dir_path) + icon_name; + const QString icon_path = QString::fromStdString(custom_icon_dir_path) + icon_name; if (QFile::exists(icon_path)) { @@ -1547,7 +1547,7 @@ void game_list_frame::ShowContextMenu(const QPoint &pos) // Open Folder menu QMenu* open_folder_menu = menu.addMenu(tr("&Open Folder")); - const bool is_disc_game = qstr(current_game.category) == cat::cat_disc_game; + const bool is_disc_game = QString::fromStdString(current_game.category) == cat::cat_disc_game; const std::string captures_dir = fs::get_config_dir() + "/captures/"; const std::string recordings_dir = fs::get_config_dir() + "/recordings/" + current_game.serial; const std::string screenshots_dir = fs::get_config_dir() + "/screenshots/" + current_game.serial; @@ -1723,7 +1723,7 @@ void game_list_frame::ShowContextMenu(const QPoint &pos) return; } - const bool is_disc_game = qstr(current_game.category) == cat::cat_disc_game; + const bool is_disc_game = QString::fromStdString(current_game.category) == cat::cat_disc_game; const bool is_in_games_dir = is_disc_game && Emu.IsPathInsideDir(current_game.path, rpcs3::utils::get_games_dir()); std::vector data_dir_list; @@ -1737,11 +1737,11 @@ void game_list_frame::ShowContextMenu(const QPoint &pos) } const bool has_data_dir = !data_dir_list.empty(); // "true" if data path is present (it could be absent for a disc game) - QString text = tr("%0 - %1\n").arg(qstr(current_game.serial)).arg(name); + QString text = tr("%0 - %1\n").arg(QString::fromStdString(current_game.serial)).arg(name); if (is_disc_game) { - text += tr("\nDisc Game Info:\nPath: %0\n").arg(qstr(current_game.path)); + text += tr("\nDisc Game Info:\nPath: %0\n").arg(QString::fromStdString(current_game.path)); if (current_game.size_on_disk != umax) // If size was properly detected { @@ -1757,7 +1757,7 @@ void game_list_frame::ShowContextMenu(const QPoint &pos) for (const std::string& data_dir : data_dir_list) { - text += tr("Path: %0\n").arg(qstr(data_dir)); + text += tr("Path: %0\n").arg(QString::fromStdString(data_dir)); if (const u64 data_size = fs::get_dir_size(data_dir, 1); data_size != umax) // If size was properly detected { @@ -1835,8 +1835,8 @@ void game_list_frame::ShowContextMenu(const QPoint &pos) if (has_data_dir && RemoveContentPathList(data_dir_list, gameinfo->localized_category.toStdString()) != data_dir_list.size()) { QMessageBox::critical(this, tr("Failure!"), remove_caches - ? tr("Failed to remove %0 from drive!\nPath: %1\nCaches and custom configs have been left intact.").arg(name).arg(qstr(data_dir_list[0])) - : tr("Failed to remove %0 from drive!\nPath: %1").arg(name).arg(qstr(data_dir_list[0]))); + ? tr("Failed to remove %0 from drive!\nPath: %1\nCaches and custom configs have been left intact.").arg(name).arg(QString::fromStdString(data_dir_list[0])) + : tr("Failed to remove %0 from drive!\nPath: %1").arg(name).arg(QString::fromStdString(data_dir_list[0]))); return; } @@ -1981,7 +1981,7 @@ void game_list_frame::ShowContextMenu(const QPoint &pos) }); // Disable options depending on software category - const QString category = qstr(current_game.category); + const QString category = QString::fromStdString(current_game.category); if (category == cat::cat_ps3_os) { @@ -2072,7 +2072,7 @@ bool game_list_frame::RemoveCustomPadConfiguration(const std::string& title_id, g_cfg_input_configs.save(); game_list_log.notice("Removed active input configuration entry for key '%s'", title_id); - if (QDir(qstr(config_dir)).removeRecursively()) + if (QDir(QString::fromStdString(config_dir)).removeRecursively()) { if (game) { @@ -2108,7 +2108,7 @@ bool game_list_frame::RemoveShadersCache(const std::string& base_dir, bool is_in u32 caches_total = 0; const QStringList filter{ QStringLiteral("shaders_cache") }; - const QString q_base_dir = qstr(base_dir); + const QString q_base_dir = QString::fromStdString(base_dir); QDirIterator dir_iter(q_base_dir, filter, QDir::Dirs | QDir::NoDotAndDotDot, QDirIterator::Subdirectories); @@ -2159,7 +2159,7 @@ bool game_list_frame::RemovePPUCache(const std::string& base_dir, bool is_intera u32 files_total = 0; const QStringList filter{ QStringLiteral("v*.obj"), QStringLiteral("v*.obj.gz") }; - const QString q_base_dir = qstr(base_dir); + const QString q_base_dir = QString::fromStdString(base_dir); QDirIterator dir_iter(q_base_dir, filter, QDir::Files | QDir::NoDotAndDotDot, QDirIterator::Subdirectories); @@ -2210,7 +2210,7 @@ bool game_list_frame::RemoveSPUCache(const std::string& base_dir, bool is_intera u32 files_total = 0; const QStringList filter{ QStringLiteral("spu*.dat"), QStringLiteral("spu*.dat.gz"), QStringLiteral("spu*.obj"), QStringLiteral("spu*.obj.gz") }; - const QString q_base_dir = qstr(base_dir); + const QString q_base_dir = QString::fromStdString(base_dir); QDirIterator dir_iter(q_base_dir, filter, QDir::Files | QDir::NoDotAndDotDot, QDirIterator::Subdirectories); @@ -2260,9 +2260,9 @@ void game_list_frame::RemoveHDD1Cache(const std::string& base_dir, const std::st u32 dirs_removed = 0; u32 dirs_total = 0; - const QString q_base_dir = qstr(base_dir); + const QString q_base_dir = QString::fromStdString(base_dir); - const QStringList filter{ qstr(title_id + "_*") }; + const QStringList filter{ QString::fromStdString(title_id + "_*") }; QDirIterator dir_iter(q_base_dir, filter, QDir::Dirs | QDir::NoDotAndDotDot); diff --git a/rpcs3/rpcs3qt/instruction_editor_dialog.cpp b/rpcs3/rpcs3qt/instruction_editor_dialog.cpp index 460b7503f6..667fbe40db 100644 --- a/rpcs3/rpcs3qt/instruction_editor_dialog.cpp +++ b/rpcs3/rpcs3qt/instruction_editor_dialog.cpp @@ -12,8 +12,6 @@ #include #include -constexpr auto qstr = QString::fromStdString; - extern bool ppu_patch(u32 addr, u32 value); extern std::string format_spu_func_info(u32 addr, cpu_thread* spu); @@ -50,14 +48,14 @@ instruction_editor_dialog::instruction_editor_dialog(QWidget *parent, u32 _pc, C m_disasm->change_mode(cpu_disasm_mode::normal); m_disasm->disasm(m_pc); - m_preview = new QLabel(qstr(m_disasm->last_opcode), this); + m_preview = new QLabel(QString::fromStdString(m_disasm->last_opcode), this); // Layouts vbox_left_panel->addWidget(new QLabel(tr("Address: "))); vbox_left_panel->addWidget(new QLabel(tr("Instruction: "))); vbox_left_panel->addWidget(new QLabel(tr("Preview: "))); - vbox_right_panel->addWidget(new QLabel(qstr(fmt::format("%08x", m_pc)))); + vbox_right_panel->addWidget(new QLabel(QString::fromStdString(fmt::format("%08x", m_pc)))); vbox_right_panel->addWidget(m_instr); vbox_right_panel->addWidget(m_preview); @@ -68,7 +66,7 @@ instruction_editor_dialog::instruction_editor_dialog(QWidget *parent, u32 _pc, C m_func_info = new QLabel("", this); vbox_right_panel->addWidget(m_func_info); - m_func_info->setText(qstr(format_spu_func_info(m_pc, cpu))); + m_func_info->setText(QString::fromStdString(format_spu_func_info(m_pc, cpu))); } if (cpu && cpu->get_class() == thread_class::spu) @@ -158,7 +156,7 @@ void instruction_editor_dialog::updatePreview() const if (ok && m_disasm->disasm(m_pc)) { - m_preview->setText(qstr(m_disasm->last_opcode)); + m_preview->setText(QString::fromStdString(m_disasm->last_opcode)); } else { diff --git a/rpcs3/rpcs3qt/kernel_explorer.cpp b/rpcs3/rpcs3qt/kernel_explorer.cpp index 3b50f9ea97..360c352100 100644 --- a/rpcs3/rpcs3qt/kernel_explorer.cpp +++ b/rpcs3/rpcs3qt/kernel_explorer.cpp @@ -38,8 +38,6 @@ #include "kernel_explorer.h" #include "qt_utils.h" -constexpr auto qstr = QString::fromStdString; - LOG_CHANNEL(sys_log, "SYS"); enum kernel_item_role @@ -173,7 +171,7 @@ static QTreeWidgetItem* add_solid_node(QTreeWidgetItem* parent, const QString& b kernel_explorer::kernel_explorer(QWidget* parent) : QDialog(parent) { - setWindowTitle(tr("Kernel Explorer | %1").arg(qstr(Emu.GetTitleAndTitleID()))); + setWindowTitle(tr("Kernel Explorer | %1").arg(QString::fromStdString(Emu.GetTitleAndTitleID()))); setObjectName("kernel_explorer"); setAttribute(Qt::WA_DeleteOnClose); setMinimumSize(QSize(800, 600)); @@ -313,10 +311,10 @@ void kernel_explorer::update() const u32 total_memory_usage = dct->used; - root->setText(0, qstr(fmt::format("Process 0x%08x: Total Memory Usage: 0x%x/0x%x (%0.2f/%0.2f MB)", process_getpid(), total_memory_usage, dct->size, 1. * total_memory_usage / (1024 * 1024) + root->setText(0, QString::fromStdString(fmt::format("Process 0x%08x: Total Memory Usage: 0x%x/0x%x (%0.2f/%0.2f MB)", process_getpid(), total_memory_usage, dct->size, 1. * total_memory_usage / (1024 * 1024) , 1. * dct->size / (1024 * 1024)))); - add_solid_node(find_node(root, additional_nodes::process_info), qstr(fmt::format("Process Info, Sdk Version: 0x%08x, PPC SEG: %#x, SFO Category: %s (Fake: %s)", g_ps3_process_info.sdk_ver, g_ps3_process_info.ppc_seg, Emu.GetCat(), Emu.GetFakeCat()))); + add_solid_node(find_node(root, additional_nodes::process_info), QString::fromStdString(fmt::format("Process Info, Sdk Version: 0x%08x, PPC SEG: %#x, SFO Category: %s (Fake: %s)", g_ps3_process_info.sdk_ver, g_ps3_process_info.ppc_seg, Emu.GetCat(), Emu.GetFakeCat()))); auto display_program_segments = [this](QTreeWidgetItem* tree, const ppu_module& m) { @@ -325,7 +323,7 @@ void kernel_explorer::update() const u32 addr = m.segs[i].addr; const u32 size = m.segs[i].size; - add_leaf(tree, qstr(fmt::format("Segment %u: (0x%08x...0x%08x), Flags: 0x%x" + add_leaf(tree, QString::fromStdString(fmt::format("Segment %u: (0x%08x...0x%08x), Flags: 0x%x" , i, addr, addr + std::max(size, 1) - 1, m.segs[i].flags))); } }; @@ -342,7 +340,7 @@ void kernel_explorer::update() { for (; cpu; cpu = cpu->get_next_cpu()) { - add_leaf(tree, qstr(fmt::format("Waiter: ID: 0x%x", cpu->get_class() == thread_class::spu ? static_cast(cpu)->lv2_id : cpu->id))); + add_leaf(tree, QString::fromStdString(fmt::format("Waiter: ID: 0x%x", cpu->get_class() == thread_class::spu ? static_cast(cpu)->lv2_id : cpu->id))); } }; @@ -355,32 +353,32 @@ void kernel_explorer::update() if (mem.pshared) { - add_leaf(node, qstr(fmt::format("Shared Mem 0x%08x: Size: 0x%x (%0.2f MB), Chunk: %s, Mappings: %u, Mem Container: %s, Key: %#llx", id, mem.size, size_mb, mem.align == 0x10000u ? "64K" : "1MB", +mem.counter, mem.ct->id, mem.key))); + add_leaf(node, QString::fromStdString(fmt::format("Shared Mem 0x%08x: Size: 0x%x (%0.2f MB), Chunk: %s, Mappings: %u, Mem Container: %s, Key: %#llx", id, mem.size, size_mb, mem.align == 0x10000u ? "64K" : "1MB", +mem.counter, mem.ct->id, mem.key))); break; } - add_leaf(node, qstr(fmt::format("Shared Mem 0x%08x: Size: 0x%x (%0.2f MB), Chunk: %s, Mem Container: %s, Mappings: %u", id, mem.size, size_mb, mem.align == 0x10000u ? "64K" : "1MB", mem.ct->id, +mem.counter))); + add_leaf(node, QString::fromStdString(fmt::format("Shared Mem 0x%08x: Size: 0x%x (%0.2f MB), Chunk: %s, Mem Container: %s, Mappings: %u", id, mem.size, size_mb, mem.align == 0x10000u ? "64K" : "1MB", mem.ct->id, +mem.counter))); break; } case SYS_MUTEX_OBJECT: { auto& mutex = static_cast(obj); const auto control = mutex.control.load(); - show_waiters(add_solid_node(node, qstr(fmt::format(u8"Mutex 0x%08x: “%s”", id, lv2_obj::name64(mutex.name))), qstr(fmt::format(u8"Mutex 0x%08x: “%s”, %s,%s Owner: %#x, Locks: %u, Key: %#llx, Conds: %u", id, lv2_obj::name64(mutex.name), mutex.protocol, + show_waiters(add_solid_node(node, QString::fromStdString(fmt::format(u8"Mutex 0x%08x: “%s”", id, lv2_obj::name64(mutex.name))), QString::fromStdString(fmt::format(u8"Mutex 0x%08x: “%s”, %s,%s Owner: %#x, Locks: %u, Key: %#llx, Conds: %u", id, lv2_obj::name64(mutex.name), mutex.protocol, mutex.recursive == SYS_SYNC_RECURSIVE ? " Recursive," : "", control.owner, +mutex.lock_count, mutex.key, mutex.cond_count))), control.sq); break; } case SYS_COND_OBJECT: { auto& cond = static_cast(obj); - show_waiters(add_solid_node(node, qstr(fmt::format(u8"Cond 0x%08x: “%s”", id, lv2_obj::name64(cond.name))), qstr(fmt::format(u8"Cond 0x%08x: “%s”, %s, Mutex: 0x%08x, Key: %#llx", id, lv2_obj::name64(cond.name), cond.mutex->protocol, cond.mtx_id, cond.key))), cond.sq); + show_waiters(add_solid_node(node, QString::fromStdString(fmt::format(u8"Cond 0x%08x: “%s”", id, lv2_obj::name64(cond.name))), QString::fromStdString(fmt::format(u8"Cond 0x%08x: “%s”, %s, Mutex: 0x%08x, Key: %#llx", id, lv2_obj::name64(cond.name), cond.mutex->protocol, cond.mtx_id, cond.key))), cond.sq); break; } case SYS_RWLOCK_OBJECT: { auto& rw = static_cast(obj); const s64 val = rw.owner; - auto tree = add_solid_node(node, qstr(fmt::format(u8"RW Lock 0x%08x: “%s”", id, lv2_obj::name64(rw.name))), qstr(fmt::format(u8"RW Lock 0x%08x: “%s”, %s, Owner: %#x(%d), Key: %#llx", id, lv2_obj::name64(rw.name), rw.protocol, + auto tree = add_solid_node(node, QString::fromStdString(fmt::format(u8"RW Lock 0x%08x: “%s”", id, lv2_obj::name64(rw.name))), QString::fromStdString(fmt::format(u8"RW Lock 0x%08x: “%s”, %s, Owner: %#x(%d), Key: %#llx", id, lv2_obj::name64(rw.name), rw.protocol, std::max(0, val >> 1), -std::min(0, val >> 1), rw.key))); if (auto rq = +rw.rq) @@ -402,23 +400,23 @@ void kernel_explorer::update() if (lv2_obj::check(handler)) { - add_leaf(node, qstr(fmt::format("Intr Tag 0x%08x, Handler: 0x%08x", id, handler->id))); + add_leaf(node, QString::fromStdString(fmt::format("Intr Tag 0x%08x, Handler: 0x%08x", id, handler->id))); break; } - add_leaf(node, qstr(fmt::format("Intr Tag 0x%08x, Handler: Unbound", id))); + add_leaf(node, QString::fromStdString(fmt::format("Intr Tag 0x%08x, Handler: Unbound", id))); break; } case SYS_INTR_SERVICE_HANDLE_OBJECT: { auto& serv = static_cast(obj); - add_leaf(node, qstr(fmt::format("Intr Svc 0x%08x, PPU: 0x%07x, arg1: 0x%x, arg2: 0x%x", id, serv.thread->id, serv.arg1, serv.arg2))); + add_leaf(node, QString::fromStdString(fmt::format("Intr Svc 0x%08x, PPU: 0x%07x, arg1: 0x%x, arg2: 0x%x", id, serv.thread->id, serv.arg1, serv.arg2))); break; } case SYS_EVENT_QUEUE_OBJECT: { auto& eq = static_cast(obj); - show_waiters(add_solid_node(node, qstr(fmt::format(u8"Event Queue 0x%08x: “%s”", id, lv2_obj::name64(eq.name))), qstr(fmt::format(u8"Event Queue 0x%08x: “%s”, %s, %s, Key: %#llx, Events: %zu/%d", id, lv2_obj::name64(eq.name), eq.protocol, + show_waiters(add_solid_node(node, QString::fromStdString(fmt::format(u8"Event Queue 0x%08x: “%s”", id, lv2_obj::name64(eq.name))), QString::fromStdString(fmt::format(u8"Event Queue 0x%08x: “%s”, %s, %s, Key: %#llx, Events: %zu/%d", id, lv2_obj::name64(eq.name), eq.protocol, eq.type == SYS_SPU_QUEUE ? "SPU" : "PPU", eq.key, eq.events.size(), eq.size))), eq.type == SYS_SPU_QUEUE ? static_cast(+eq.sq) : +eq.pq); break; } @@ -431,30 +429,30 @@ void kernel_explorer::update() { if (queue == idm::check_unlocked(queue->id)) { - add_leaf(node, qstr(fmt::format("Event Port 0x%08x: %s, Name: %#llx, Event Queue (ID): 0x%08x", id, type, ep.name, queue->id))); + add_leaf(node, QString::fromStdString(fmt::format("Event Port 0x%08x: %s, Name: %#llx, Event Queue (ID): 0x%08x", id, type, ep.name, queue->id))); break; } // This code is unused until multi-process is implemented if (queue == lv2_event_queue::find(queue->key).get()) { - add_leaf(node, qstr(fmt::format("Event Port 0x%08x: %s, Name: %#llx, Event Queue (IPC): %s", id, type, ep.name, queue->key))); + add_leaf(node, QString::fromStdString(fmt::format("Event Port 0x%08x: %s, Name: %#llx, Event Queue (IPC): %s", id, type, ep.name, queue->key))); break; } } - add_leaf(node, qstr(fmt::format("Event Port 0x%08x: %s, Name: %#llx, Unbound", id, type, ep.name))); + add_leaf(node, QString::fromStdString(fmt::format("Event Port 0x%08x: %s, Name: %#llx, Unbound", id, type, ep.name))); break; } case SYS_TRACE_OBJECT: { - add_leaf(node, qstr(fmt::format("Trace 0x%08x", id))); + add_leaf(node, QString::fromStdString(fmt::format("Trace 0x%08x", id))); break; } case SYS_SPUIMAGE_OBJECT: { auto& spi = static_cast(obj); - add_leaf(node, qstr(fmt::format("SPU Image 0x%08x, Entry: 0x%x, Segs: *0x%x, Num Segs: %d", id, spi.e_entry, spi.segs, spi.nsegs))); + add_leaf(node, QString::fromStdString(fmt::format("SPU Image 0x%08x, Entry: 0x%x, Segs: *0x%x, Num Segs: %d", id, spi.e_entry, spi.segs, spi.nsegs))); break; } case SYS_PRX_OBJECT: @@ -463,24 +461,24 @@ void kernel_explorer::update() if (prx.segs.empty()) { - add_leaf(node, qstr(fmt::format("PRX 0x%08x: '%s' (HLE)", id, prx.name))); + add_leaf(node, QString::fromStdString(fmt::format("PRX 0x%08x: '%s' (HLE)", id, prx.name))); break; } - const QString text = qstr(fmt::format("PRX 0x%08x: '%s', attr=0x%x, lib=%s", id, prx.name, prx.module_info_attributes, prx.module_info_name)); + const QString text = QString::fromStdString(fmt::format("PRX 0x%08x: '%s', attr=0x%x, lib=%s", id, prx.name, prx.module_info_attributes, prx.module_info_name)); QTreeWidgetItem* prx_tree = add_solid_node(node, text, text); display_program_segments(prx_tree, prx); break; } case SYS_SPUPORT_OBJECT: { - add_leaf(node, qstr(fmt::format("SPU Port 0x%08x", id))); + add_leaf(node, QString::fromStdString(fmt::format("SPU Port 0x%08x", id))); break; } case SYS_OVERLAY_OBJECT: { auto& ovl = static_cast(obj); - const QString text = qstr(fmt::format("OVL 0x%08x: '%s'", id, ovl.name)); + const QString text = QString::fromStdString(fmt::format("OVL 0x%08x: '%s'", id, ovl.name)); QTreeWidgetItem* ovl_tree = add_solid_node(node, text, text); display_program_segments(ovl_tree, ovl); break; @@ -516,11 +514,11 @@ void kernel_explorer::update() } else { - show_waiters(add_solid_node(node, qstr(fmt::format(u8"LWMutex 0x%08x: “%s”", id, lv2_obj::name64(lwm.name))), qstr(fmt::format(u8"LWMutex 0x%08x: “%s”, %s, Signal: %#x (unmapped/invalid control data at *0x%x)", id, lv2_obj::name64(lwm.name), lwm.protocol, +lv2_control.signaled, lwm.control))), lv2_control.sq); + show_waiters(add_solid_node(node, QString::fromStdString(fmt::format(u8"LWMutex 0x%08x: “%s”", id, lv2_obj::name64(lwm.name))), QString::fromStdString(fmt::format(u8"LWMutex 0x%08x: “%s”, %s, Signal: %#x (unmapped/invalid control data at *0x%x)", id, lv2_obj::name64(lwm.name), lwm.protocol, +lv2_control.signaled, lwm.control))), lv2_control.sq); break; } - show_waiters(add_solid_node(node, qstr(fmt::format(u8"LWMutex 0x%08x: “%s”", id, lv2_obj::name64(lwm.name))), qstr(fmt::format(u8"LWMutex 0x%08x: “%s”, %s,%s Owner: %s, Locks: %u, Signal: %#x, Control: *0x%x", id, lv2_obj::name64(lwm.name), lwm.protocol, + show_waiters(add_solid_node(node, QString::fromStdString(fmt::format(u8"LWMutex 0x%08x: “%s”", id, lv2_obj::name64(lwm.name))), QString::fromStdString(fmt::format(u8"LWMutex 0x%08x: “%s”, %s,%s Owner: %s, Locks: %u, Signal: %#x, Control: *0x%x", id, lv2_obj::name64(lwm.name), lwm.protocol, (lwm_data.attribute & SYS_SYNC_RECURSIVE) ? " Recursive," : "", owner_str, lwm_data.recursive_count, +lv2_control.signaled, lwm.control))), lv2_control.sq); break; } @@ -550,7 +548,7 @@ void kernel_explorer::update() period = timer.period; // Period (oneshot if 0) } - add_leaf(node, qstr(fmt::format("Timer 0x%08x: State: %s, Period: 0x%llx, Next Expire: 0x%llx, Queue ID: 0x%08x, Source: 0x%08x, Data1: 0x%08x, Data2: 0x%08x", id, timer_state ? "Running" : "Stopped" + add_leaf(node, QString::fromStdString(fmt::format("Timer 0x%08x: State: %s, Period: 0x%llx, Next Expire: 0x%llx, Queue ID: 0x%08x, Source: 0x%08x, Data1: 0x%08x, Data2: 0x%08x", id, timer_state ? "Running" : "Stopped" , period, expire, port ? port->id : 0, source, data1, data2))); break; } @@ -558,20 +556,20 @@ void kernel_explorer::update() { auto& sema = static_cast(obj); const auto val = +sema.val; - show_waiters(add_solid_node(node, qstr(fmt::format(u8"Sema 0x%08x: “%s”", id, lv2_obj::name64(sema.name))), qstr(fmt::format(u8"Sema 0x%08x: “%s”, %s, Count: %d/%d, Key: %#llx", id, lv2_obj::name64(sema.name), sema.protocol, + show_waiters(add_solid_node(node, QString::fromStdString(fmt::format(u8"Sema 0x%08x: “%s”", id, lv2_obj::name64(sema.name))), QString::fromStdString(fmt::format(u8"Sema 0x%08x: “%s”, %s, Count: %d/%d, Key: %#llx", id, lv2_obj::name64(sema.name), sema.protocol, std::max(val, 0), sema.max, sema.key, -std::min(val, 0)))), sema.sq); break; } case SYS_LWCOND_OBJECT: { auto& lwc = static_cast(obj); - show_waiters(add_solid_node(node, qstr(fmt::format(u8"LWCond 0x%08x: “%s”", id, lv2_obj::name64(lwc.name))), qstr(fmt::format(u8"LWCond 0x%08x: “%s”, %s, OG LWMutex: 0x%08x, Control: *0x%x", id, lv2_obj::name64(lwc.name), lwc.protocol, lwc.lwid, lwc.control))), lwc.sq); + show_waiters(add_solid_node(node, QString::fromStdString(fmt::format(u8"LWCond 0x%08x: “%s”", id, lv2_obj::name64(lwc.name))), QString::fromStdString(fmt::format(u8"LWCond 0x%08x: “%s”, %s, OG LWMutex: 0x%08x, Control: *0x%x", id, lv2_obj::name64(lwc.name), lwc.protocol, lwc.lwid, lwc.control))), lwc.sq); break; } case SYS_EVENT_FLAG_OBJECT: { auto& ef = static_cast(obj); - show_waiters(add_solid_node(node, qstr(fmt::format(u8"Event Flag 0x%08x: “%s”", id, lv2_obj::name64(ef.name))), qstr(fmt::format(u8"Event Flag 0x%08x: “%s”, %s, Type: 0x%x, Key: %#llx, Pattern: 0x%llx", id, lv2_obj::name64(ef.name), ef.protocol, + show_waiters(add_solid_node(node, QString::fromStdString(fmt::format(u8"Event Flag 0x%08x: “%s”", id, lv2_obj::name64(ef.name))), QString::fromStdString(fmt::format(u8"Event Flag 0x%08x: “%s”, %s, Type: 0x%x, Key: %#llx, Pattern: 0x%llx", id, lv2_obj::name64(ef.name), ef.protocol, ef.type, ef.key, ef.pattern.load()))), ef.sq); break; } @@ -584,12 +582,12 @@ void kernel_explorer::update() break; } - QTreeWidgetItem* rao_obj = add_solid_node(node, qstr(fmt::format(u8"RSXAudio 0x%08x: Shmem: 0x%08x", id, u32{rao.shmem}))); + QTreeWidgetItem* rao_obj = add_solid_node(node, QString::fromStdString(fmt::format(u8"RSXAudio 0x%08x: Shmem: 0x%08x", id, u32{rao.shmem}))); for (u64 q_idx = 0; q_idx < rao.event_queue.size(); q_idx++) { if (const auto& eq = rao.event_queue[q_idx]) { - add_leaf(rao_obj, qstr(fmt::format(u8"Event Queue %u: ID: 0x%08x", q_idx, eq->id))); + add_leaf(rao_obj, QString::fromStdString(fmt::format(u8"Event Queue %u: ID: 0x%08x", q_idx, eq->id))); } } @@ -597,7 +595,7 @@ void kernel_explorer::update() } default: { - add_leaf(node, qstr(fmt::format("Unknown object 0x%08x", id))); + add_leaf(node, QString::fromStdString(fmt::format("Unknown object 0x%08x", id))); } } }); @@ -605,19 +603,19 @@ void kernel_explorer::update() idm::select([&](u32 /*id*/, sys_vm_t& vmo) { const u32 psize = vmo.psize; - add_leaf(find_node(root, additional_nodes::virtual_memory), qstr(fmt::format("Virtual Mem 0x%08x: Virtual Size: 0x%x (%0.2f MB), Physical Size: 0x%x (%0.2f MB), Mem Container: %s", vmo.addr + add_leaf(find_node(root, additional_nodes::virtual_memory), QString::fromStdString(fmt::format("Virtual Mem 0x%08x: Virtual Size: 0x%x (%0.2f MB), Physical Size: 0x%x (%0.2f MB), Mem Container: %s", vmo.addr , vmo.size, vmo.size * 1. / (1024 * 1024), psize, psize * 1. / (1024 * 1024), vmo.ct->id))); }); idm::select([&](u32 id, lv2_socket& sock) { - add_leaf(find_node(root, additional_nodes::sockets), qstr(fmt::format("Socket %u: Type: %s, Family: %s, Wq: %zu", id, sock.get_type(), sock.get_family(), sock.get_queue_size()))); + add_leaf(find_node(root, additional_nodes::sockets), QString::fromStdString(fmt::format("Socket %u: Type: %s, Family: %s, Wq: %zu", id, sock.get_type(), sock.get_family(), sock.get_queue_size()))); }); idm::select([&](u32 id, lv2_memory_container& container) { const u32 used = container.used; - add_leaf(find_node(root, additional_nodes::memory_containers), qstr(fmt::format("Memory Container 0x%08x: Used: 0x%x/0x%x (%0.2f/%0.2f MB)", id, used, container.size, used * 1. / (1024 * 1024), container.size * 1. / (1024 * 1024)))); + add_leaf(find_node(root, additional_nodes::memory_containers), QString::fromStdString(fmt::format("Memory Container 0x%08x: Used: 0x%x/0x%x (%0.2f/%0.2f MB)", id, used, container.size, used * 1. / (1024 * 1024), container.size * 1. / (1024 * 1024)))); }); std::optional> lock_idm_lv2(std::in_place, id_manager::g_mutex, lv2_obj::g_mutex); @@ -658,7 +656,7 @@ void kernel_explorer::update() const auto func = ppu.last_function; const ppu_thread_status status = lv2_obj::ppu_state(&ppu, false, false).first; - add_leaf(find_node(root, additional_nodes::ppu_threads), qstr(fmt::format(u8"PPU 0x%07x: “%s”, PRIO: %d, Joiner: %s, Status: %s, State: %s, %s func: “%s”%s", id, *ppu.ppu_tname.load(), ppu.prio.load().prio, ppu.joiner.load(), status, ppu.state.load() + add_leaf(find_node(root, additional_nodes::ppu_threads), QString::fromStdString(fmt::format(u8"PPU 0x%07x: “%s”, PRIO: %d, Joiner: %s, Status: %s, State: %s, %s func: “%s”%s", id, *ppu.ppu_tname.load(), ppu.prio.load().prio, ppu.joiner.load(), status, ppu.state.load() , ppu.ack_suspend ? "After" : (ppu.current_function ? "In" : "Last"), func ? func : "", get_wait_time_str(ppu.start_time)))); }, idm::unlocked); @@ -669,7 +667,7 @@ void kernel_explorer::update() const auto func = spu.current_func; const u64 start_time = spu.start_time; - QTreeWidgetItem* spu_thread_tree = add_solid_node(find_node(root, additional_nodes::spu_threads), qstr(fmt::format(u8"SPU 0x%07x: “%s”", spu.lv2_id, *spu.spu_tname.load())), qstr(fmt::format(u8"SPU 0x%07x: “%s”, State: %s, Type: %s, Func: \"%s\"%s", spu.lv2_id, *spu.spu_tname.load(), spu.state.load(), spu.get_type(), start_time && func ? func : "", start_time ? get_wait_time_str(get_guest_system_time(start_time)) : ""))); + QTreeWidgetItem* spu_thread_tree = add_solid_node(find_node(root, additional_nodes::spu_threads), QString::fromStdString(fmt::format(u8"SPU 0x%07x: “%s”", spu.lv2_id, *spu.spu_tname.load())), QString::fromStdString(fmt::format(u8"SPU 0x%07x: “%s”, State: %s, Type: %s, Func: \"%s\"%s", spu.lv2_id, *spu.spu_tname.load(), spu.state.load(), spu.get_type(), start_time && func ? func : "", start_time ? get_wait_time_str(get_guest_system_time(start_time)) : ""))); if (spu.get_type() == spu_type::threaded) { @@ -693,21 +691,21 @@ void kernel_explorer::update() { if (lv2_obj::check(port)) { - add_leaf(spu_thread_tree, qstr(fmt::format("SPU Port %u: Queue ID: 0x%08x", &port - spu.spup, port->id))); + add_leaf(spu_thread_tree, QString::fromStdString(fmt::format("SPU Port %u: Queue ID: 0x%08x", &port - spu.spup, port->id))); } } } else if (has_connected_ports) { // Avoid duplication of information between threads which is common - add_leaf(spu_thread_tree, qstr(fmt::format("SPU Ports: As SPU 0x%07x", first_spu->lv2_id))); + add_leaf(spu_thread_tree, QString::fromStdString(fmt::format("SPU Ports: As SPU 0x%07x", first_spu->lv2_id))); } for (const auto& [key, queue] : spu.spuq) { if (lv2_obj::check(queue)) { - add_leaf(spu_thread_tree, qstr(fmt::format("SPU Queue: Queue ID: 0x%08x, Key: 0x%x", queue->id, key))); + add_leaf(spu_thread_tree, QString::fromStdString(fmt::format("SPU Queue: Queue ID: 0x%08x, Key: 0x%x", queue->id, key))); } } } @@ -717,7 +715,7 @@ void kernel_explorer::update() { if (lv2_obj::check(ctrl.tag)) { - add_leaf(spu_thread_tree, qstr(fmt::format("Interrupt Tag %u: ID: 0x%x, Mask: 0x%x, Status: 0x%x", &ctrl - spu.int_ctrl.data(), ctrl.tag->id, +ctrl.mask, +ctrl.stat))); + add_leaf(spu_thread_tree, QString::fromStdString(fmt::format("Interrupt Tag %u: ID: 0x%x, Mask: 0x%x, Status: 0x%x", &ctrl - spu.int_ctrl.data(), ctrl.tag->id, +ctrl.mask, +ctrl.stat))); } } } @@ -725,7 +723,7 @@ void kernel_explorer::update() idm::select([&](u32 id, lv2_spu_group& tg) { - QTreeWidgetItem* spu_tree = add_solid_node(find_node(root, additional_nodes::spu_thread_groups), qstr(fmt::format(u8"SPU Group 0x%07x: “%s”, Type = 0x%x", id, tg.name, tg.type)), qstr(fmt::format(u8"SPU Group 0x%07x: “%s”, Status = %s, Priority = %d, Type = 0x%x", id, tg.name, tg.run_state.load(), tg.prio.load().prio, tg.type))); + QTreeWidgetItem* spu_tree = add_solid_node(find_node(root, additional_nodes::spu_thread_groups), QString::fromStdString(fmt::format(u8"SPU Group 0x%07x: “%s”, Type = 0x%x", id, tg.name, tg.type)), QString::fromStdString(fmt::format(u8"SPU Group 0x%07x: “%s”, Status = %s, Priority = %d, Type = 0x%x", id, tg.name, tg.run_state.load(), tg.prio.load().prio, tg.type))); if (tg.name.ends_with("CellSpursKernelGroup"sv)) { @@ -763,7 +761,7 @@ void kernel_explorer::update() { const QString branch_name = tr("SPURS %1").arg(pspurs.addr()); const u32 wklEnabled = spurs.wklEnabled; - QTreeWidgetItem* spurs_tree = add_solid_node(spu_tree, branch_name, qstr(fmt::format("SPURS, Instance: *0x%x, LWMutex: 0x%x, LWCond: 0x%x, wklEnabled: 0x%x" + QTreeWidgetItem* spurs_tree = add_solid_node(spu_tree, branch_name, QString::fromStdString(fmt::format("SPURS, Instance: *0x%x, LWMutex: 0x%x, LWCond: 0x%x, wklEnabled: 0x%x" , pspurs, spurs.mutex.sleep_queue, spurs.cond.lwcond_queue, wklEnabled))); const u32 signal_mask = u32{spurs.wklSignal1} << 16 | spurs.wklSignal2; @@ -788,7 +786,7 @@ void kernel_explorer::update() const u8 status = spurs.wklStatus(wid); const auto has_signal = (signal_mask & (0x80000000u >> wid)) ? "Signalled"sv : "No Signal"sv; - QTreeWidgetItem* wkl_tree = add_solid_node(spurs_tree, branch_name + qstr(fmt::format(" Work.%u", wid)), qstr(fmt::format("Work.%u, class: %s, %s, %s, Status: %#x, Event: %#x, %s, ReadyCnt: %u", wid, +name.nameClass, +name.nameInstance, state, status, evt, has_signal, ready_count))); + QTreeWidgetItem* wkl_tree = add_solid_node(spurs_tree, branch_name + QString::fromStdString(fmt::format(" Work.%u", wid)), QString::fromStdString(fmt::format("Work.%u, class: %s, %s, %s, Status: %#x, Event: %#x, %s, ReadyCnt: %u", wid, +name.nameClass, +name.nameInstance, state, status, evt, has_signal, ready_count))); auto contention = [&](u8 v) { @@ -799,11 +797,11 @@ void kernel_explorer::update() }; const auto& winfo = spurs.wklInfo(wid); - add_leaf(wkl_tree, qstr(fmt::format("Contention: %u/%u (pending: %u), Image: *0x%x (size: 0x%x, arg: 0x%x), Priority (BE64): %016x", contention(spurs.wklCurrentContention[wid % 16]) + add_leaf(wkl_tree, QString::fromStdString(fmt::format("Contention: %u/%u (pending: %u), Image: *0x%x (size: 0x%x, arg: 0x%x), Priority (BE64): %016x", contention(spurs.wklCurrentContention[wid % 16]) , contention(spurs.wklMaxContention[wid % 16]), contention(spurs.wklPendingContention[wid % 16]), +winfo.addr, winfo.size, winfo.arg, std::bit_cast>(winfo.priority)))); } - add_leaf(spurs_tree, qstr(fmt::format("Handler Info: PPU0: 0x%x, PPU1: 0x%x, DirtyState: %u, Waiting: %u, Exiting: %u", spurs.ppu0, spurs.ppu1 + add_leaf(spurs_tree, QString::fromStdString(fmt::format("Handler Info: PPU0: 0x%x, PPU1: 0x%x, DirtyState: %u, Waiting: %u, Exiting: %u", spurs.ppu0, spurs.ppu1 , +spurs.handlerDirty, +spurs.handlerWaiting, +spurs.handlerExiting))); } else @@ -834,7 +832,7 @@ void kernel_explorer::update() const QString branch_name = "RSX Context 0x55555555"; QTreeWidgetItem* rsx_tree = add_solid_node(rsx_context_node, branch_name, - branch_name + qstr(fmt::format(u8", Local Size: %u MB, Base Addr: 0x%x, Device Addr: 0x%x, Handlers: 0x%x", rsx->local_mem_size >> 20, base, rsx->device_addr, +vm::_ref(rsx->driver_info).handlers))); + branch_name + QString::fromStdString(fmt::format(u8", Local Size: %u MB, Base Addr: 0x%x, Device Addr: 0x%x, Handlers: 0x%x", rsx->local_mem_size >> 20, base, rsx->device_addr, +vm::_ref(rsx->driver_info).handlers))); QTreeWidgetItem* io_tree = add_volatile_node(rsx_tree, tr("IO-EA Table")); QTreeWidgetItem* zc_tree = add_volatile_node(rsx_tree, tr("Zcull Bindings")); @@ -859,7 +857,7 @@ void kernel_explorer::update() if (size_block) { // Print block - add_leaf(io_tree, qstr(fmt::format("IO: %08x, EA: %08x, Size: %uMB", first_io, first_ea, size_block))); + add_leaf(io_tree, QString::fromStdString(fmt::format("IO: %08x, EA: %08x, Size: %uMB", first_io, first_ea, size_block))); } if (i >= 512u) @@ -885,7 +883,7 @@ void kernel_explorer::update() else { // Print last block before we continue to a new one - add_leaf(io_tree, qstr(fmt::format("IO: %08x, EA: %08x, Size: %uMB", first_io, first_ea, old_block_size))); + add_leaf(io_tree, QString::fromStdString(fmt::format("IO: %08x, EA: %08x, Size: %uMB", first_io, first_ea, old_block_size))); size_block = 1; first_ea = addr; first_io = (i - 1) << 20; @@ -903,7 +901,7 @@ void kernel_explorer::update() { if (zc.bound) { - add_leaf(zc_tree, qstr(fmt::format("O: %07x, W: %u, H: %u, Zformat: 0x%x, AAformat: 0x%x, Dir: 0x%x, sFunc: 0x%x, sRef: %02x, sMask: %02x" + add_leaf(zc_tree, QString::fromStdString(fmt::format("O: %07x, W: %u, H: %u, Zformat: 0x%x, AAformat: 0x%x, Dir: 0x%x, sFunc: 0x%x, sRef: %02x, sMask: %02x" , zc.offset, zc.height, zc.width, zc.zFormat, zc.aaFormat, zc.zcullDir, zc.sFunc, zc.sRef, zc.sMask))); } } @@ -912,7 +910,7 @@ void kernel_explorer::update() { if (db.valid()) { - add_leaf(db_tree, qstr(fmt::format("Offset: %07x, Width: %u, Height: %u, Pitch: %u" + add_leaf(db_tree, QString::fromStdString(fmt::format("Offset: %07x, Width: %u, Height: %u, Pitch: %u" , db.offset, db.height, db.width, db.pitch))); } } @@ -936,7 +934,7 @@ void kernel_explorer::update() return "Unknown object!"; }()); - add_leaf(find_node(root, additional_nodes::file_descriptors), qstr(str)); + add_leaf(find_node(root, additional_nodes::file_descriptors), QString::fromStdString(str)); }); std::function final_touches; @@ -969,7 +967,7 @@ void kernel_explorer::update() if (count > 0) { // Append count - node->setText(0, node->text(0) + qstr(fmt::format(" (%zu)", count))); + node->setText(0, node->text(0) + QString::fromStdString(fmt::format(" (%zu)", count))); // Expand if necessary node->setExpanded(node->data(0, kernel_item_role::expanded_role).toBool()); @@ -1009,7 +1007,7 @@ void kernel_explorer::log(u32 level, QTreeWidgetItem* item) return; } - m_log_buf = qstr(fmt::format("Kernel Explorer: %s\n", Emu.GetTitleAndTitleID())); + m_log_buf = QString::fromStdString(fmt::format("Kernel Explorer: %s\n", Emu.GetTitleAndTitleID())); log(level + 1, item); sys_log.success("%s", m_log_buf); diff --git a/rpcs3/rpcs3qt/main_window.cpp b/rpcs3/rpcs3qt/main_window.cpp index 1326f112d9..547acd97d6 100644 --- a/rpcs3/rpcs3qt/main_window.cpp +++ b/rpcs3/rpcs3qt/main_window.cpp @@ -103,8 +103,6 @@ extern atomic_t g_user_asked_for_frame_capture; class CPUDisAsm; std::shared_ptr make_basic_ppu_disasm(); -inline std::string sstr(const QString& _in) { return _in.toStdString(); } - extern void qt_events_aware_op(int repeat_duration_ms, std::function wrapped_op) { ensure(wrapped_op); @@ -313,12 +311,12 @@ void main_window::update_gui_pad_thread() QString main_window::GetCurrentTitle() { - QString title = qstr(Emu.GetTitleAndTitleID()); - if (title.isEmpty()) + std::string title = Emu.GetTitleAndTitleID(); + if (title.empty()) { - title = qstr(Emu.GetLastBoot()); + title = Emu.GetLastBoot(); } - return title; + return QString::fromStdString(title); } // returns appIcon @@ -595,7 +593,7 @@ void main_window::BootElf() // game folder in case of having e.g. a Game Folder with collected links to elf files. // Don't set last path earlier in case of cancelled dialog m_gui_settings->SetValue(gui::fd_boot_elf, file_path); - const std::string path = sstr(QFileInfo(file_path).absoluteFilePath()); + const std::string path = QFileInfo(file_path).absoluteFilePath().toStdString(); gui_log.notice("Booting from BootElf..."); Boot(path, "", true, true); @@ -635,7 +633,7 @@ void main_window::BootTest() return; } - const std::string path = sstr(QFileInfo(file_path).absoluteFilePath()); + const std::string path = QFileInfo(file_path).absoluteFilePath().toStdString(); gui_log.notice("Booting from BootTest..."); Boot(path, "", true); @@ -651,7 +649,7 @@ void main_window::BootSavestate() stopped = true; } - const QString file_path = QFileDialog::getOpenFileName(this, tr("Select Savestate To Boot"), qstr(fs::get_config_dir() + "savestates/"), tr( + const QString file_path = QFileDialog::getOpenFileName(this, tr("Select Savestate To Boot"), QString::fromStdString(fs::get_config_dir() + "savestates/"), tr( "Savestate files (*.SAVESTAT *.SAVESTAT.zst *.SAVESTAT.gz);;" "All files (*.*)"), Q_NULLPTR, QFileDialog::DontResolveSymlinks); @@ -665,7 +663,7 @@ void main_window::BootSavestate() return; } - const std::string path = sstr(QFileInfo(file_path).absoluteFilePath()); + const std::string path = QFileInfo(file_path).absoluteFilePath().toStdString(); gui_log.notice("Booting from BootSavestate..."); Boot(path, "", true); @@ -696,7 +694,7 @@ void main_window::BootGame() m_gui_settings->SetValue(gui::fd_boot_game, QFileInfo(dir_path).path()); gui_log.notice("Booting from BootGame..."); - Boot(sstr(dir_path), "", false, true); + Boot(dir_path.toStdString(), "", false, true); } void main_window::BootVSH() @@ -717,7 +715,7 @@ void main_window::BootRsxCapture(std::string path) is_stopped = true; } - const QString file_path = QFileDialog::getOpenFileName(this, tr("Select RSX Capture"), qstr(fs::get_config_dir() + "captures/"), tr("RRC files (*.rrc *.RRC *.rrc.gz *.RRC.GZ);;All files (*.*)")); + const QString file_path = QFileDialog::getOpenFileName(this, tr("Select RSX Capture"), QString::fromStdString(fs::get_config_dir() + "captures/"), tr("RRC files (*.rrc *.RRC *.rrc.gz *.RRC.GZ);;All files (*.*)")); if (file_path.isEmpty()) { @@ -727,7 +725,7 @@ void main_window::BootRsxCapture(std::string path) } return; } - path = sstr(file_path); + path = file_path.toStdString(); } if (!m_gui_settings->GetBootConfirmation(this)) @@ -757,7 +755,7 @@ bool main_window::InstallFileInExData(const std::string& extension, const QStrin // Copy file atomically with thread/process-safe error checking for file size const std::string to_path = rpcs3::utils::get_hdd0_dir() + "/home/" + Emu.GetUsr() + "/exdata/" + filename.substr(0, filename.find_last_of('.')); fs::pending_file to(to_path + "." + extension); - fs::file from(sstr(path)); + fs::file from(path.toStdString()); if (!to.file || !from) { @@ -908,7 +906,7 @@ bool main_window::InstallPackages(QStringList file_paths, bool from_boot) for (const QString& file : file_paths.filter(QRegularExpression(pattern, QRegularExpression::PatternOption::CaseInsensitiveOption))) { const QFileInfo file_info(file); - const std::string filename = sstr(file_info.fileName()); + const std::string filename = file_info.fileName().toStdString(); if (InstallFileInExData(extension, file, filename)) { @@ -1054,7 +1052,7 @@ bool main_window::HandlePackageInstallation(QStringList file_paths, bool from_bo for (const compat::package_info& info : packages) { - readers.emplace_back(sstr(info.path)); + readers.emplace_back(info.path.toStdString()); } std::deque bootable_paths; @@ -1282,7 +1280,7 @@ void main_window::ExtractMSELF() if (!dir.isEmpty()) { m_gui_settings->SetValue(gui::fd_ext_mself, QFileInfo(file_path).path()); - extract_mself(sstr(file_path), sstr(dir) + '/'); + extract_mself(file_path.toStdString(), dir.toStdString() + '/'); } } @@ -1376,7 +1374,7 @@ void main_window::ExtractTar() const QString& file = *files_it; // Do not abort on failure here, in case the user selected a wrong file in multi-selection while the rest are valid - if (!extract_tar(sstr(file), sstr(dir) + '/')) + if (!extract_tar(file.toStdString(), dir.toStdString() + '/')) { if (error.isEmpty()) { @@ -1427,7 +1425,7 @@ void main_window::HandlePupInstallation(const QString& file_path, const QString& m_gui_settings->SetValue(gui::fd_install_pup, QFileInfo(file_path).path()); - const std::string path = sstr(file_path); + const std::string path = file_path.toStdString(); fs::file pup_f(path); if (!pup_f) @@ -1515,7 +1513,7 @@ void main_window::HandlePupInstallation(const QString& file_path, const QString& { // Extract only mode, extract direct TAR entries to a user directory - if (!vfs::mount("/pup_extract", sstr(dir_path) + '/')) + if (!vfs::mount("/pup_extract", dir_path.toStdString() + '/')) { gui_log.error("Error while extracting firmware: Failed to mount '%s'", dir_path); critical(tr("Firmware extraction failed: VFS mounting failed.")); @@ -1570,7 +1568,7 @@ void main_window::HandlePupInstallation(const QString& file_path, const QString& } if (version_string < cur_version && - QMessageBox::question(this, tr("RPCS3 Firmware Installer"), tr("Old firmware detected.\nThe newest firmware version is %1 and you are trying to install version %2\nContinue installation?").arg(QString::fromUtf8(cur_version.data(), ::size32(cur_version)), qstr(version_string)), + QMessageBox::question(this, tr("RPCS3 Firmware Installer"), tr("Old firmware detected.\nThe newest firmware version is %1 and you are trying to install version %2\nContinue installation?").arg(QString::fromUtf8(cur_version.data(), ::size32(cur_version)), QString::fromStdString(version_string)), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) == QMessageBox::No) { return; @@ -1580,7 +1578,7 @@ void main_window::HandlePupInstallation(const QString& file_path, const QString& { gui_log.warning("Reinstalling firmware: old=%s, new=%s", installed, version_string); - if (QMessageBox::question(this, tr("RPCS3 Firmware Installer"), tr("Firmware of version %1 has already been installed.\nOverwrite current installation with version %2?").arg(qstr(installed), qstr(version_string)), + if (QMessageBox::question(this, tr("RPCS3 Firmware Installer"), tr("Firmware of version %1 has already been installed.\nOverwrite current installation with version %2?").arg(QString::fromStdString(installed), QString::fromStdString(version_string)), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) == QMessageBox::No) { gui_log.warning("Reinstallation of firmware aborted."); @@ -1591,7 +1589,7 @@ void main_window::HandlePupInstallation(const QString& file_path, const QString& // Remove possibly PS3 fonts from database QFontDatabase::removeAllApplicationFonts(); - progress_dialog pdlg(tr("RPCS3 Firmware Installer"), tr("Installing firmware version %1\nPlease wait...").arg(qstr(version_string)), tr("Cancel"), 0, static_cast(update_filenames.size()), false, this); + progress_dialog pdlg(tr("RPCS3 Firmware Installer"), tr("Installing firmware version %1\nPlease wait...").arg(QString::fromStdString(version_string)), tr("Cancel"), 0, static_cast(update_filenames.size()), false, this); pdlg.show(); // Used by tar_object::extract() as destination directory @@ -1703,10 +1701,10 @@ void main_window::DecryptSPRXLibraries() { QString path_last_sprx = m_gui_settings->GetValue(gui::fd_decrypt_sprx).toString(); - if (!fs::is_dir(sstr(path_last_sprx))) + if (!fs::is_dir(path_last_sprx.toStdString())) { // Default: redirect to userland firmware SPRX directory - path_last_sprx = qstr(g_cfg_vfs.get_dev_flash() + "sys/external"); + path_last_sprx = QString::fromStdString(g_cfg_vfs.get_dev_flash() + "sys/external"); } const QStringList modules = QFileDialog::getOpenFileNames(this, tr("Select binary files"), path_last_sprx, tr("All Binaries (*.bin *.BIN *.self *.SELF *.sprx *.SPRX *.sdat *.SDAT *.edat *.EDAT);;" @@ -1734,14 +1732,14 @@ void main_window::DecryptSPRXLibraries() const std::string filename = path.substr(path.find_last_of(fs::delim) + 1); const QString hint = tr("Hint: KLIC (KLicense key) is a 16-byte long string. (32 hexadecimal characters, can be prefixed with \"KLIC=0x\" from the log message)" - "\nAnd is logged with some sceNpDrm* functions when the game/application which owns \"%0\" is running.").arg(qstr(filename)); + "\nAnd is logged with some sceNpDrm* functions when the game/application which owns \"%0\" is running.").arg(QString::fromStdString(filename)); if (repeat_count >= 2) { gui_log.error("Failed to decrypt %s with specified KLIC, retrying.\n%s", path, hint); } - input_dialog* dlg = new input_dialog(39, "", tr("Enter KLIC of %0").arg(qstr(filename)), + input_dialog* dlg = new input_dialog(39, "", tr("Enter KLIC of %0").arg(QString::fromStdString(filename)), repeat_count >= 2 ? tr("Decryption failed with provided KLIC.\n%0").arg(hint) : tr("Hexadecimal value."), "KLIC=0x00000000000000000000000000000000", this); QFont mono = QFontDatabase::systemFont(QFontDatabase::FixedFont); @@ -1759,7 +1757,7 @@ void main_window::DecryptSPRXLibraries() connect(dlg, &QDialog::accepted, this, [this, iterate, dlg, mod_index, decrypter, repeat_count]() { - std::string text = sstr(dlg->get_input_text()); + std::string text = dlg->get_input_text().toStdString(); if (usz new_index = decrypter->decrypt(std::move(text)); !decrypter->done()) { @@ -2424,7 +2422,7 @@ void main_window::ShowOptionalGamePreparations(const QString& title, const QStri { for (const game_info& gameinfo : m_game_list_frame->GetGameInfo()) { - if (gameinfo && gameinfo->info.serial == sstr(title_id)) + if (gameinfo && gameinfo->info.serial == title_id.toStdString()) { if (Emu.IsPathInsideDir(boot_path, gameinfo->info.path)) { @@ -2537,7 +2535,7 @@ void main_window::CreateConnects() } // Only select one folder for now - QString dir = QFileDialog::getExistingDirectory(this, tr("Select a folder containing one or more games"), qstr(fs::get_config_dir()), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); + QString dir = QFileDialog::getExistingDirectory(this, tr("Select a folder containing one or more games"), QString::fromStdString(fs::get_config_dir()), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); if (dir.isEmpty()) { return; @@ -2645,7 +2643,7 @@ void main_window::CreateConnects() } // Get new filename from title and title ID but simplified - QString log_filename_q = qstr(Emu.GetTitleID().empty() ? "RPCS3" : Emu.GetTitleAndTitleID()); + QString log_filename_q = QString::fromStdString(Emu.GetTitleID().empty() ? "RPCS3" : Emu.GetTitleAndTitleID()); ensure(!log_filename_q.isEmpty()); // Replace unfitting characters @@ -2697,7 +2695,7 @@ void main_window::CreateConnects() if (archived_stat.size) { - const QString dir_path = QFileDialog::getExistingDirectory(this, tr("Select RPCS3's log saving location (saving %0)").arg(qstr(log_filename + ".log.gz")), path_last_log, QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); + const QString dir_path = QFileDialog::getExistingDirectory(this, tr("Select RPCS3's log saving location (saving %0)").arg(QString::fromStdString(log_filename + ".log.gz")), path_last_log, QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); if (dir_path.isEmpty()) { @@ -2720,7 +2718,7 @@ void main_window::CreateConnects() return; } - const QString dir_path = QFileDialog::getExistingDirectory(this, tr("Select RPCS3's log saving location (saving %0)").arg(qstr(log_filename + ".log")), path_last_log, QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); + const QString dir_path = QFileDialog::getExistingDirectory(this, tr("Select RPCS3's log saving location (saving %0)").arg(QString::fromStdString(log_filename + ".log")), path_last_log, QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); if (dir_path.isEmpty()) { @@ -3245,7 +3243,7 @@ void main_window::CreateConnects() const QStringList categories = get_cats(act, id); for (const game_info& game : m_game_list_frame->GetGameInfo()) { - if (game && categories.contains(qstr(game->info.category))) count++; + if (game && categories.contains(QString::fromStdString(game->info.category))) count++; } act->setText(QString("%0 (%1)").arg(text).arg(count)); }; @@ -3472,14 +3470,14 @@ void main_window::CreateDockWindows() if (title_and_title_id == Emu.GetTitleAndTitleID()) // This should usually not cause trouble, but feel free to improve. { - tooltip = tr("Restart %0").arg(qstr(title_and_title_id)); + tooltip = tr("Restart %0").arg(QString::fromStdString(title_and_title_id)); ui->toolbar_start->setIcon(m_icon_restart); ui->toolbar_start->setText(tr("Restart")); } else { - tooltip = tr("Play %0").arg(qstr(title_and_title_id)); + tooltip = tr("Play %0").arg(QString::fromStdString(title_and_title_id)); ui->toolbar_start->setIcon(m_icon_play); ui->toolbar_start->setText(tr("Play")); @@ -3670,7 +3668,7 @@ void main_window::RemoveAllCaches() for (const game_info& game : m_game_list_frame->GetGameInfo()) // Loop on detected games { - if (game && qstr(game->info.category) != cat::cat_ps3_os && fs::exists(cache_base_dir + game->info.serial)) // If not OS category and cache exists + if (game && QString::fromStdString(game->info.category) != cat::cat_ps3_os && fs::exists(cache_base_dir + game->info.serial)) // If not OS category and cache exists { caches_count++; @@ -3726,7 +3724,7 @@ void main_window::CleanUpGameList() for (const game_info& game : m_game_list_frame->GetGameInfo()) // Loop on detected games { // If Disc Game and its serial is found in game list file - if (game && qstr(game->info.category) == cat::cat_disc_game && game->info.serial == serial) + if (game && QString::fromStdString(game->info.category) == cat::cat_disc_game && game->info.serial == serial) { found = true; break; @@ -3758,7 +3756,7 @@ void main_window::RemoveFirmwareCache() const QStringList filter{ QStringLiteral("ppu-*-lib*.sprx")}; - QDirIterator dir_iter(qstr(cache_dir), filter, QDir::Dirs | QDir::NoDotAndDotDot); + QDirIterator dir_iter(QString::fromStdString(cache_dir), filter, QDir::Dirs | QDir::NoDotAndDotDot); while (dir_iter.hasNext()) { @@ -3881,7 +3879,7 @@ void main_window::AddGamesFromDirs(QStringList&& paths) for (const QString& path : paths) { - games_added += Emu.AddGamesFromDir(sstr(path)); + games_added += Emu.AddGamesFromDir(path.toStdString()); } if (games_added) @@ -3900,7 +3898,7 @@ void main_window::AddGamesFromDirs(QStringList&& paths) { for (const auto& dir_path : paths) { - if (Emu.IsPathInsideDir(game->info.path, sstr(dir_path))) + if (Emu.IsPathInsideDir(game->info.path, dir_path.toStdString())) { // Try to claim operation on directory path @@ -3909,7 +3907,7 @@ void main_window::AddGamesFromDirs(QStringList&& paths) if (!resolved_path.empty() && !claimed_paths.count(resolved_path)) { claimed_paths.emplace(game->info.path); - paths_added.emplace(game->info.path, qstr(game->info.serial)); + paths_added.emplace(game->info.path, QString::fromStdString(game->info.serial)); } break; @@ -4090,13 +4088,13 @@ void main_window::dropEvent(QDropEvent* event) { for (const auto& psf : drop_paths) { - const std::string psf_path = sstr(psf); + const std::string psf_path = psf.toStdString(); std::string info = fmt::format("Dropped PARAM.SFO '%s':\n\n%s", psf_path, psf::load(psf_path).sfo); gui_log.success("%s", info); info.erase(info.begin(), info.begin() + info.find_first_of('\'')); - QMessageBox mb(QMessageBox::Information, tr("PARAM.SFO Information"), qstr(info), QMessageBox::Ok, this); + QMessageBox mb(QMessageBox::Information, tr("PARAM.SFO Information"), QString::fromStdString(info), QMessageBox::Ok, this); mb.setTextInteractionFlags(Qt::TextSelectableByMouse); mb.exec(); } @@ -4147,7 +4145,7 @@ void main_window::dropEvent(QDropEvent* event) } case drop_type::drop_rrc: // replay a rsx capture file { - BootRsxCapture(sstr(drop_paths.first())); + BootRsxCapture(drop_paths.first().toStdString()); break; } } diff --git a/rpcs3/rpcs3qt/memory_viewer_panel.cpp b/rpcs3/rpcs3qt/memory_viewer_panel.cpp index d2d03f01b9..533dccc4d2 100644 --- a/rpcs3/rpcs3qt/memory_viewer_panel.cpp +++ b/rpcs3/rpcs3qt/memory_viewer_panel.cpp @@ -30,8 +30,6 @@ LOG_CHANNEL(gui_log, "GUI"); -constexpr auto qstr = QString::fromStdString; - memory_viewer_panel::memory_viewer_panel(QWidget* parent, std::shared_ptr disasm, u32 addr, std::function func) : QDialog(parent) , m_addr(addr) @@ -67,7 +65,7 @@ memory_viewer_panel::memory_viewer_panel(QWidget* parent, std::shared_ptrget_name())) : + cpu && m_type == thread_class::spu ? tr("Memory Viewer Of %0").arg(QString::fromStdString(cpu->get_name())) : cpu && m_type == thread_class::rsx ? tr("Memory Viewer Of RSX[0x55555555]") : tr("Memory Viewer")); @@ -362,11 +360,11 @@ memory_viewer_panel::memory_viewer_panel(QWidget* parent, std::shared_ptr 1) { - m_cbox_input_mode->setItemText(std::countr_zero(i), qstr(fmt::format("* %s", search_mode{i}))); + m_cbox_input_mode->setItemText(std::countr_zero(i), QString::fromStdString(fmt::format("* %s", search_mode{i}))); } else { - m_cbox_input_mode->setItemText(std::countr_zero(i), qstr(fmt::format("%s", search_mode{i}))); + m_cbox_input_mode->setItemText(std::countr_zero(i), QString::fromStdString(fmt::format("%s", search_mode{i}))); } } @@ -633,7 +631,7 @@ void memory_viewer_panel::scroll(s32 steps) m_addr &= m_addr_mask; // Mask it m_addr -= m_addr % (m_colcount * 4); // Align by amount of bytes in a row - m_addr_line->setText(qstr(fmt::format("%08x", m_addr))); + m_addr_line->setText(QString::fromStdString(fmt::format("%08x", m_addr))); ShowMemory(); } @@ -818,7 +816,7 @@ void memory_viewer_panel::ShowMemory() for (u32 i = 0; i < 3; i++) { - t_mem_addr_str += qstr(fmt::format("%08x", addr)); + t_mem_addr_str += QString::fromStdString(fmt::format("%08x", addr)); std::string str(i == 1 ? header : ""); @@ -828,7 +826,7 @@ void memory_viewer_panel::ShowMemory() str.resize(expected_str_size); std::replace(str.begin(), str.end(), '\0', i == 1 ? ' ' : '='); - t_mem_hex_str += qstr(str); + t_mem_hex_str += QString::fromStdString(str); spu_passed++; row++; @@ -850,7 +848,7 @@ void memory_viewer_panel::ShowMemory() } } - t_mem_addr_str += qstr(fmt::format("%08x", (m_addr + (row - spu_passed) * m_colcount * 4) & m_addr_mask)); + t_mem_addr_str += QString::fromStdString(fmt::format("%08x", (m_addr + (row - spu_passed) * m_colcount * 4) & m_addr_mask)); } for (u32 col = 0; col < m_colcount; col++) @@ -865,7 +863,7 @@ void memory_viewer_panel::ShowMemory() if (const auto ptr = this->to_ptr(addr)) { const be_t rmem = read_from_ptr>(static_cast(ptr)); - t_mem_hex_str += qstr(fmt::format("%02x %02x %02x %02x", + t_mem_hex_str += QString::fromStdString(fmt::format("%02x %02x %02x %02x", static_cast(rmem >> 24), static_cast(rmem >> 16), static_cast(rmem >> 8), @@ -878,7 +876,7 @@ void memory_viewer_panel::ShowMemory() if (!std::isprint(static_cast(ch))) ch = '.'; } - t_mem_ascii_str += qstr(std::move(str)); + t_mem_ascii_str += QString::fromStdString(std::move(str)); } else { @@ -1190,7 +1188,7 @@ void memory_viewer_panel::ShowImage(QWidget* parent, u32 addr, color_format form QLineEdit* addr_line = static_cast(parent())->m_addr_line; const QPointF xy = static_cast(event)->position() / m_canvas_scale; - addr_line->setText(qstr(fmt::format("%08x", get_pointed_addr(xy.x(), xy.y())))); + addr_line->setText(QString::fromStdString(fmt::format("%08x", get_pointed_addr(xy.x(), xy.y())))); Q_EMIT addr_line->returnPressed(); close(); return false; @@ -1208,11 +1206,11 @@ void memory_viewer_panel::ShowImage(QWidget* parent, u32 addr, color_format form { if (x < 0 || y < 0) { - m_image_title->setText(qstr(fmt::format("[-, -]: NA"))); + m_image_title->setText(QString::fromStdString(fmt::format("[-, -]: NA"))); return; } - m_image_title->setText(qstr(fmt::format("[x:%d, y:%d]: 0x%x", x, y, get_pointed_addr(x, y)))); + m_image_title->setText(QString::fromStdString(fmt::format("[x:%d, y:%d]: 0x%x", x, y, get_pointed_addr(x, y)))); } void keyPressEvent(QKeyEvent* event) override @@ -1257,7 +1255,7 @@ void memory_viewer_panel::ShowImage(QWidget* parent, u32 addr, color_format form image_viewer* f_image_viewer = new image_viewer(parent, canvas, image_title, std::move(image), addr, texel_bytes, width, width, height); canvas->installEventFilter(f_image_viewer); - f_image_viewer->setWindowTitle(qstr(fmt::format("Raw Image @ 0x%x", addr))); + f_image_viewer->setWindowTitle(QString::fromStdString(fmt::format("Raw Image @ 0x%x", addr))); f_image_viewer->setLayout(layout); f_image_viewer->setAttribute(Qt::WA_DeleteOnClose); f_image_viewer->show(); diff --git a/rpcs3/rpcs3qt/pad_settings_dialog.cpp b/rpcs3/rpcs3qt/pad_settings_dialog.cpp index 4710ad4ec4..09032c0926 100644 --- a/rpcs3/rpcs3qt/pad_settings_dialog.cpp +++ b/rpcs3/rpcs3qt/pad_settings_dialog.cpp @@ -26,8 +26,6 @@ LOG_CHANNEL(cfg_log, "CFG"); -inline std::string sstr(const QString& _in) { return _in.toStdString(); } - cfg_input_configurations g_cfg_input_configs; inline bool CreateConfigFile(const QString& dir, const QString& name) @@ -1395,7 +1393,7 @@ void pad_settings_dialog::ChangeHandler() } else { - handler = sstr(ui->chooseHandler->currentData().toString()); + handler = ui->chooseHandler->currentData().toString().toStdString(); device = player_config->device.to_string(); buddy_device = player_config->buddy_device.to_string(); } @@ -1518,7 +1516,7 @@ void pad_settings_dialog::ChangeHandler() { const QString device_name = name_string + QString::number(i); const QString device_name_localized = GetLocalizedPadName(m_handler->m_type, device_name, i); - ui->chooseDevice->addItem(device_name_localized, QVariant::fromValue(pad_device_info{ sstr(device_name), device_name_localized, true })); + ui->chooseDevice->addItem(device_name_localized, QVariant::fromValue(pad_device_info{ device_name.toStdString(), device_name_localized, true })); } force_enable = true; break; @@ -1626,7 +1624,7 @@ void pad_settings_dialog::ChangeConfig(const QString& config_file) if (config_file.isEmpty()) return; - m_config_file = sstr(config_file); + m_config_file = config_file.toStdString(); // Load in order to get the pad handlers if (!g_cfg_input.load(m_title_id, m_config_file, true)) diff --git a/rpcs3/rpcs3qt/qt_utils.cpp b/rpcs3/rpcs3qt/qt_utils.cpp index 0094d83618..c4e8c5a571 100644 --- a/rpcs3/rpcs3qt/qt_utils.cpp +++ b/rpcs3/rpcs3qt/qt_utils.cpp @@ -16,8 +16,6 @@ LOG_CHANNEL(gui_log, "GUI"); -constexpr auto qstr = QString::fromStdString; - namespace gui { namespace utils @@ -397,7 +395,7 @@ namespace gui if (!found_file) { // Get Icon for the gs_frame from path. this handles presumably all possible use cases - const QString qpath = qstr(path); + const QString qpath = QString::fromStdString(path); const std::string path_list[] = { path, qpath.section("/", 0, -2, QString::SectionIncludeTrailingSep).toStdString(), qpath.section("/", 0, -3, QString::SectionIncludeTrailingSep).toStdString() }; @@ -422,7 +420,7 @@ namespace gui if (found_file) { // load the image from path. It will most likely be a rectangle - const QImage source = QImage(qstr(icon_path)); + const QImage source = QImage(QString::fromStdString(icon_path)); const int edge_max = std::max(source.width(), source.height()); // create a new transparent image with square size and same format as source (maybe handle other formats than RGB32 as well?) @@ -448,7 +446,7 @@ namespace gui void open_dir(const std::string& spath) { - QString path = qstr(spath); + QString path = QString::fromStdString(spath); if (fs::is_file(spath)) { @@ -470,7 +468,7 @@ namespace gui QProcess::execute("/usr/bin/osascript", { "-e", "tell application \"Finder\" to activate" }); #else // open parent directory - const QUrl url = QUrl::fromLocalFile(qstr(fs::get_parent_dir(spath))); + const QUrl url = QUrl::fromLocalFile(QString::fromStdString(fs::get_parent_dir(spath))); const std::string url_path = url.toString().toStdString(); gui_log.notice("gui::utils::open_dir: About to open parent dir url '%s' for path '%s'", url_path, spath); diff --git a/rpcs3/rpcs3qt/register_editor_dialog.cpp b/rpcs3/rpcs3qt/register_editor_dialog.cpp index 54f50e6f60..639fb7db35 100644 --- a/rpcs3/rpcs3qt/register_editor_dialog.cpp +++ b/rpcs3/rpcs3qt/register_editor_dialog.cpp @@ -18,10 +18,6 @@ #include "util/v128.hpp" #include "util/asm.hpp" -constexpr auto qstr = QString::fromStdString; -inline std::string sstr(const QString& _in) { return _in.toStdString(); } -inline std::string sstr(const QVariant& _in) { return sstr(_in.toString()); } - enum registers : int { ppu_r0, @@ -108,10 +104,10 @@ register_editor_dialog::register_editor_dialog(QWidget *parent, CPUDisAsm* _disa { if (cpu->get_class() == thread_class::ppu) { - for (int i = ppu_r0; i <= ppu_r31; i++) m_register_combo->addItem(qstr(fmt::format("r%d", i % 32)), i); - for (int i = ppu_f0; i <= ppu_f31; i++) m_register_combo->addItem(qstr(fmt::format("f%d", i % 32)), i); - for (int i = ppu_ff0; i <= ppu_ff31; i++) m_register_combo->addItem(qstr(fmt::format("ff%d", i % 32)), i); - for (int i = ppu_v0; i <= ppu_v31; i++) m_register_combo->addItem(qstr(fmt::format("v%d", i % 32)), i); + for (int i = ppu_r0; i <= ppu_r31; i++) m_register_combo->addItem(QString::fromStdString(fmt::format("r%d", i % 32)), i); + for (int i = ppu_f0; i <= ppu_f31; i++) m_register_combo->addItem(QString::fromStdString(fmt::format("f%d", i % 32)), i); + for (int i = ppu_ff0; i <= ppu_ff31; i++) m_register_combo->addItem(QString::fromStdString(fmt::format("ff%d", i % 32)), i); + for (int i = ppu_v0; i <= ppu_v31; i++) m_register_combo->addItem(QString::fromStdString(fmt::format("v%d", i % 32)), i); m_register_combo->addItem("CR", +PPU_CR); m_register_combo->addItem("LR", +PPU_LR); m_register_combo->addItem("CTR", PPU_CTR); @@ -124,7 +120,7 @@ register_editor_dialog::register_editor_dialog(QWidget *parent, CPUDisAsm* _disa } else if (cpu->get_class() == thread_class::spu) { - for (int i = spu_r0; i <= spu_r127; i++) m_register_combo->addItem(qstr(fmt::format("r%d", i % 128)), i); + for (int i = spu_r0; i <= spu_r127; i++) m_register_combo->addItem(QString::fromStdString(fmt::format("r%d", i % 128)), i); m_register_combo->addItem("MFC Pending Events", +MFC_PEVENTS); m_register_combo->addItem("MFC Events Mask", +MFC_EVENTS_MASK); m_register_combo->addItem("MFC Events Count", +MFC_EVENTS_COUNT); @@ -167,7 +163,7 @@ register_editor_dialog::register_editor_dialog(QWidget *parent, CPUDisAsm* _disa void register_editor_dialog::updateRegister(int reg) const { - std::string str = sstr(tr("Error parsing register value!")); + std::string str = tr("Error parsing register value!").toStdString(); const auto cpu = m_get_cpu(); @@ -196,7 +192,7 @@ void register_editor_dialog::updateRegister(int reg) const else if (reg == PPU_CTR) str = fmt::format("%016llx", ppu.ctr); else if (reg == PPU_VRSAVE) str = fmt::format("%08x", ppu.vrsave); else if (reg == PPU_PRIO) str = fmt::format("%08x", ppu.prio.load().prio); - else if (reg == RESERVATION_LOST) str = sstr(ppu.raddr ? tr("Lose reservation on OK") : tr("Reservation is inactive")); + else if (reg == RESERVATION_LOST) str = ppu.raddr ? tr("Lose reservation on OK").toStdString() : tr("Reservation is inactive").toStdString(); else if (reg == PC) str = fmt::format("%08x", ppu.cia); } else if (cpu->get_class() == thread_class::spu) @@ -218,17 +214,17 @@ void register_editor_dialog::updateRegister(int reg) const else if (reg == SPU_SNR2) str = fmt::format("%s", spu.ch_snr2); else if (reg == SPU_OUT_MBOX) str = fmt::format("%s", spu.ch_out_mbox); else if (reg == SPU_OUT_INTR_MBOX) str = fmt::format("%s", spu.ch_out_intr_mbox); - else if (reg == RESERVATION_LOST) str = sstr(spu.raddr ? tr("Lose reservation on OK") : tr("Reservation is inactive")); + else if (reg == RESERVATION_LOST) str = spu.raddr ? tr("Lose reservation on OK").toStdString() : tr("Reservation is inactive").toStdString(); else if (reg == PC) str = fmt::format("%08x", spu.pc); } - m_value_line->setText(qstr(str)); + m_value_line->setText(QString::fromStdString(str)); } void register_editor_dialog::OnOkay() { const int reg = m_register_combo->currentData().toInt(); - std::string value = sstr(m_value_line->text()); + std::string value = m_value_line->text().toStdString(); auto check_res = [](std::from_chars_result res, const char* end) { diff --git a/rpcs3/rpcs3qt/rsx_debugger.cpp b/rpcs3/rpcs3qt/rsx_debugger.cpp index bdea183d2e..234adbd8e2 100644 --- a/rpcs3/rpcs3qt/rsx_debugger.cpp +++ b/rpcs3/rpcs3qt/rsx_debugger.cpp @@ -28,8 +28,6 @@ enum GCMEnumTypes CELL_GCM_PRIMITIVE_ENUM, }; -constexpr auto qstr = QString::fromStdString; - LOG_CHANNEL(rsx_debugger, "RSX Debugger"); namespace utils @@ -604,9 +602,9 @@ void rsx_debugger::OnClickDrawCalls() // Programs m_transform_disasm->clear(); - m_transform_disasm->setText(qstr(frame_debug.draw_calls[draw_id].programs.first)); + m_transform_disasm->setText(QString::fromStdString(frame_debug.draw_calls[draw_id].programs.first)); m_fragment_disasm->clear(); - m_fragment_disasm->setText(qstr(frame_debug.draw_calls[draw_id].programs.second)); + m_fragment_disasm->setText(QString::fromStdString(frame_debug.draw_calls[draw_id].programs.second)); m_list_index_buffer->clear(); //m_list_index_buffer->insertColumn(0, "Index", 0, 700); @@ -615,7 +613,7 @@ void rsx_debugger::OnClickDrawCalls() auto index_buffer = ref_ptr(frame_debug.draw_calls[draw_id].index); for (u32 i = 0; i < frame_debug.draw_calls[draw_id].vertex_count; ++i) { - m_list_index_buffer->insertItem(i, qstr(std::to_string(index_buffer[i]))); + m_list_index_buffer->insertItem(i, QString::fromStdString(std::to_string(index_buffer[i]))); } } if (frame_debug.draw_calls[draw_id].state.index_type() == rsx::index_array_type::u32) @@ -623,7 +621,7 @@ void rsx_debugger::OnClickDrawCalls() auto index_buffer = ref_ptr(frame_debug.draw_calls[draw_id].index); for (u32 i = 0; i < frame_debug.draw_calls[draw_id].vertex_count; ++i) { - m_list_index_buffer->insertItem(i, qstr(std::to_string(index_buffer[i]))); + m_list_index_buffer->insertItem(i, QString::fromStdString(std::to_string(index_buffer[i]))); } } } @@ -647,7 +645,7 @@ void rsx_debugger::GetMemory() const { str.clear(); rsx::get_pretty_printing_function(command.first)(str, command.first, command.second); - m_list_captured_frame->setItem(cmd_i++, 0, new QTableWidgetItem(qstr(str))); + m_list_captured_frame->setItem(cmd_i++, 0, new QTableWidgetItem(QString::fromStdString(str))); dump += str; dump += '\n'; @@ -659,7 +657,7 @@ void rsx_debugger::GetMemory() const } for (u32 i = 0; i < frame_debug.draw_calls.size(); i++) - m_list_captured_draw_calls->setItem(i, 0, new QTableWidgetItem(qstr(frame_debug.draw_calls[i].name))); + m_list_captured_draw_calls->setItem(i, 0, new QTableWidgetItem(QString::fromStdString(frame_debug.draw_calls[i].name))); } void rsx_debugger::GetBuffers() const diff --git a/rpcs3/rpcs3qt/settings_dialog.cpp b/rpcs3/rpcs3qt/settings_dialog.cpp index abea4b47bf..7ad9023f4e 100644 --- a/rpcs3/rpcs3qt/settings_dialog.cpp +++ b/rpcs3/rpcs3qt/settings_dialog.cpp @@ -45,10 +45,6 @@ LOG_CHANNEL(cfg_log, "CFG"); -inline std::string sstr(const QString& _in) { return _in.toStdString(); } -inline std::string sstr(const QVariant& _in) { return sstr(_in.toString()); } -inline QString qsv(std::string_view sv) { return QString(sv.data()); } - std::pair get_data(const QComboBox* box, int index) { if (!box) return {}; @@ -137,7 +133,7 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std if (game) { m_emu_settings->LoadSettings(game->serial, create_cfg_from_global_cfg); - setWindowTitle(tr("Settings: [%0] %1", "Settings dialog").arg(qstr(game->serial)).arg(qstr(game->name))); + setWindowTitle(tr("Settings: [%0] %1", "Settings dialog").arg(QString::fromStdString(game->serial)).arg(QString::fromStdString(game->name))); } else { @@ -171,7 +167,7 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std if (item->checkState() != Qt::CheckState::Unchecked) { // suffix indicates forced HLE mode - selected.emplace(sstr(item->text()) + ":hle"); + selected.emplace(item->text().toStdString() + ":hle"); } } @@ -181,7 +177,7 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std if (item->checkState() != Qt::CheckState::Unchecked) { // suffix indicates forced LLE mode - selected.emplace(sstr(item->text()) + ":lle"); + selected.emplace(item->text().toStdString() + ":lle"); } } @@ -206,7 +202,7 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std if (m_use_discord) { discord::initialize(); - discord::update_presence(sstr(m_discord_state)); + discord::update_presence(m_discord_state.toStdString()); } else { @@ -215,7 +211,7 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std } else if (m_discord_state != discord_state_old && Emu.IsStopped()) { - discord::update_presence(sstr(m_discord_state), "Idle", false); + discord::update_presence(m_discord_state.toStdString(), "Idle", false); } #endif @@ -802,7 +798,7 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std { if (renderer->has_adapters) { - renderer->old_adapter = qstr(m_emu_settings->GetSetting(renderer->type)); + renderer->old_adapter = QString::fromStdString(m_emu_settings->GetSetting(renderer->type)); } continue; } @@ -833,7 +829,7 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std { if (renderer.name != render->name && render->has_adapters && render->supported) { - m_emu_settings->SetSetting(render->type, sstr(render->old_adapter)); + m_emu_settings->SetSetting(render->type, render->old_adapter.toStdString()); } } @@ -866,7 +862,7 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std } } ui->graphicsAdapterBox->setCurrentIndex(idx); - m_emu_settings->SetSetting(renderer.type, sstr(ui->graphicsAdapterBox->currentText())); + m_emu_settings->SetSetting(renderer.type, ui->graphicsAdapterBox->currentText().toStdString()); }; for (const auto& renderer : r_creator->renderers) @@ -897,7 +893,7 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std { if (render->name == new_renderer && render->has_adapters && render->adapters.contains(text)) { - m_emu_settings->SetSetting(render->type, sstr(text)); + m_emu_settings->SetSetting(render->type, text.toStdString()); break; } } @@ -1012,15 +1008,15 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std ui->audioDeviceBox->clear(); ui->audioDeviceBox->blockSignals(true); - ui->audioDeviceBox->addItem(tr("Default"), qsv(audio_device_enumerator::DEFAULT_DEV_ID)); + ui->audioDeviceBox->addItem(tr("Default"), QString(audio_device_enumerator::DEFAULT_DEV_ID.data())); const std::string selected_device = m_emu_settings->GetSetting(emu_settings_type::AudioDevice); int device_index = 0; for (const audio_device_enumerator::audio_device& dev : dev_array) { - const QString cur_item = qstr(dev.id); - ui->audioDeviceBox->addItem(qstr(dev.name), cur_item); + const QString cur_item = QString::fromStdString(dev.id); + ui->audioDeviceBox->addItem(QString::fromStdString(dev.name), cur_item); if (selected_device == dev.id) { device_index = ui->audioDeviceBox->findData(cur_item); @@ -1030,7 +1026,7 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std if (device_index == 0 && keep_old && selected_device != audio_device_enumerator::DEFAULT_DEV_ID) { cfg_log.error("The selected audio device (%s) was not found", selected_device); - ui->audioDeviceBox->addItem(tr("Unknown device"), qsv(selected_device)); + ui->audioDeviceBox->addItem(tr("Unknown device"), QString::fromStdString(selected_device)); device_index = ui->audioDeviceBox->count() - 1; } @@ -1046,7 +1042,7 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std } const QVariant item_data = ui->audioDeviceBox->itemData(index); - m_emu_settings->SetSetting(emu_settings_type::AudioDevice, sstr(item_data.toString())); + m_emu_settings->SetSetting(emu_settings_type::AudioDevice, item_data.toString().toStdString()); ui->audioDeviceBox->setCurrentIndex(index); }; @@ -1157,7 +1153,7 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std for (s32 index = static_cast(mic_sel_list.size()) - 1; index >= 0; index--) { - const QString qmic = qstr(mic_sel_list[index]); + const QString qmic = QString::fromStdString(mic_sel_list[index]); if (qmic.isEmpty() || m_mics_combo[index]->findText(qmic) == -1) { @@ -1228,7 +1224,7 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std const std::string default_camera = m_emu_settings->GetSettingDefault(emu_settings_type::CameraID); const std::string selected_camera = m_emu_settings->GetSetting(emu_settings_type::CameraID); ui->cameraIdBox->addItem(tr("None", "Camera Device"), ""); - ui->cameraIdBox->addItem(tr("Default", "Camera Device"), qstr(default_camera)); + ui->cameraIdBox->addItem(tr("Default", "Camera Device"), QString::fromStdString(default_camera)); for (const QCameraDevice& camera_info : QMediaDevices::videoInputs()) { if (!camera_info.isNull()) @@ -1236,14 +1232,14 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std ui->cameraIdBox->addItem(camera_info.description(), QString(camera_info.id())); } } - if (const int index = ui->cameraIdBox->findData(qstr(selected_camera)); index >= 0) + if (const int index = ui->cameraIdBox->findData(QString::fromStdString(selected_camera)); index >= 0) { ui->cameraIdBox->setCurrentIndex(index); } else { cfg_log.error("The selected camera was not found. Selecting default camera as fallback."); - ui->cameraIdBox->setCurrentIndex(ui->cameraIdBox->findData(qstr(default_camera))); + ui->cameraIdBox->setCurrentIndex(ui->cameraIdBox->findData(QString::fromStdString(default_camera))); } connect(ui->cameraIdBox, QOverload::of(&QComboBox::currentIndexChanged), this, [this](int index) { @@ -1252,7 +1248,7 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std connect(this, &settings_dialog::signal_restore_dependant_defaults, this, [this, default_camera]() { m_emu_settings->SetSetting(emu_settings_type::CameraID, default_camera); - ui->cameraIdBox->setCurrentIndex(ui->cameraIdBox->findData(qstr(default_camera))); + ui->cameraIdBox->setCurrentIndex(ui->cameraIdBox->findData(QString::fromStdString(default_camera))); }); SubscribeTooltip(ui->gb_camera_id, tooltips.settings.camera_id); } @@ -1701,7 +1697,7 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std const auto list = (lib.second ? ui->hleList : ui->lleList); - QListWidgetItem* item = new QListWidgetItem(qsv(lib.first), list); + QListWidgetItem* item = new QListWidgetItem(QString(lib.first.data()), list); item->setFlags(item->flags() | Qt::ItemIsUserCheckable); // set checkable flag // If no override selected (res=0), checkbox is unchecked @@ -2063,7 +2059,7 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std const auto get_game_window_title = [this, game](const QString& format) { rpcs3::title_format_data title_data; - title_data.format = sstr(format); + title_data.format = format.toStdString(); title_data.renderer = m_emu_settings->GetSetting(emu_settings_type::Renderer); title_data.vulkan_adapter = m_emu_settings->GetSetting(emu_settings_type::VulkanAdapter); title_data.fps = 60.; @@ -2075,7 +2071,7 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std } else { - title_data.title = sstr(tr("My Game", "Game window title")); + title_data.title = tr("My Game", "Game window title").toStdString(); title_data.title_id = "ABCD12345"; } @@ -2086,12 +2082,12 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std return QStringLiteral("RPCS3"); } - return qstr(game_window_title); + return QString::fromStdString(game_window_title); }; const auto set_game_window_title = [get_game_window_title, this](const std::string& format) { - const QString game_window_title_format = qstr(format); + const QString game_window_title_format = QString::fromStdString(format); const QString game_window_title = get_game_window_title(game_window_title_format); const int width = ui->label_game_window_title_format->sizeHint().width(); const QFontMetrics metrics = ui->label_game_window_title_format->fontMetrics(); @@ -2133,7 +2129,7 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std const std::string game_title_format = m_emu_settings->GetSetting(emu_settings_type::WindowTitleFormat); - QString edited_format = qstr(game_title_format); + QString edited_format = QString::fromStdString(game_title_format); input_dialog dlg(-1, edited_format, tr("Game Window Title Format", "Game window title"), get_game_window_title_label(edited_format), "", this); dlg.resize(width() * .75, dlg.height()); @@ -2146,7 +2142,7 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std if (dlg.exec() == QDialog::Accepted) { - m_emu_settings->SetSetting(emu_settings_type::WindowTitleFormat, sstr(edited_format)); + m_emu_settings->SetSetting(emu_settings_type::WindowTitleFormat, edited_format.toStdString()); set_game_window_title(m_emu_settings->GetSetting(emu_settings_type::WindowTitleFormat)); } }); diff --git a/rpcs3/rpcs3qt/user_manager_dialog.cpp b/rpcs3/rpcs3qt/user_manager_dialog.cpp index b8ccebdf43..48e017ea8f 100644 --- a/rpcs3/rpcs3qt/user_manager_dialog.cpp +++ b/rpcs3/rpcs3qt/user_manager_dialog.cpp @@ -25,8 +25,6 @@ #include "Utilities/File.h" #include "util/logs.hpp" -constexpr auto qstr = QString::fromStdString; - LOG_CHANNEL(gui_log, "GUI"); user_manager_dialog::user_manager_dialog(std::shared_ptr gui_settings, std::shared_ptr persistent_settings, QWidget* parent) @@ -144,7 +142,7 @@ void user_manager_dialog::UpdateTable(bool mark_only) if (mark_only) { - const QString active_user = qstr(m_active_user); + const QString active_user = QString::fromStdString(m_active_user); for (int i = 0; i < m_table->rowCount(); i++) { @@ -176,12 +174,12 @@ void user_manager_dialog::UpdateTable(bool mark_only) int row = 0; for (auto& [id, account] : m_user_list) { - QTableWidgetItem* user_id_item = new QTableWidgetItem(qstr(account.GetUserId())); + QTableWidgetItem* user_id_item = new QTableWidgetItem(QString::fromStdString(account.GetUserId())); user_id_item->setData(Qt::UserRole, id); // For sorting to work properly user_id_item->setFlags(user_id_item->flags() & ~Qt::ItemIsEditable); m_table->setItem(row, 0, user_id_item); - QTableWidgetItem* username_item = new QTableWidgetItem(qstr(account.GetUsername())); + QTableWidgetItem* username_item = new QTableWidgetItem(QString::fromStdString(account.GetUsername())); username_item->setData(Qt::UserRole, id); // For sorting to work properly username_item->setFlags(username_item->flags() & ~Qt::ItemIsEditable); m_table->setItem(row, 1, username_item); @@ -218,12 +216,12 @@ void user_manager_dialog::OnUserRemove() return; } - const QString username = qstr(m_user_list[key].GetUsername()); - const QString user_id = qstr(m_user_list[key].GetUserId()); + const QString username = QString::fromStdString(m_user_list[key].GetUsername()); + const QString user_id = QString::fromStdString(m_user_list[key].GetUserId()); const std::string user_dir = m_user_list[key].GetUserDir(); if (QMessageBox::question(this, tr("Delete Confirmation"), tr("Are you sure you want to delete the following user?\n\nUser ID: %0\nUsername: %1\n\n" - "This will remove all files in:\n%2").arg(user_id).arg(username).arg(qstr(user_dir)), QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) + "This will remove all files in:\n%2").arg(user_id).arg(username).arg(QString::fromStdString(user_dir)), QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) { gui_log.warning("Deleting user: %s", user_dir); fs::remove_all(user_dir); @@ -267,11 +265,11 @@ void user_manager_dialog::OnUserRename() const std::string user_id = m_user_list[key].GetUserId(); const std::string username = m_user_list[key].GetUsername(); - const QString q_username = qstr(username); + const QString q_username = QString::fromStdString(username); QInputDialog* dialog = new QInputDialog(this); dialog->setWindowTitle(tr("Rename User")); - dialog->setLabelText(tr("User Id: %0\nOld Username: %1\n\nNew Username: ").arg(qstr(user_id)).arg(q_username)); + dialog->setLabelText(tr("User Id: %0\nOld Username: %1\n\nNew Username: ").arg(QString::fromStdString(user_id)).arg(q_username)); dialog->setTextValue(q_username); dialog->resize(200, 100); @@ -329,7 +327,7 @@ void user_manager_dialog::OnUserCreate() QInputDialog* dialog = new QInputDialog(this); dialog->setWindowTitle(tr("New User")); - dialog->setLabelText(tr("New User ID: %0\n\nNew Username: ").arg(qstr(next_user_id))); + dialog->setLabelText(tr("New User ID: %0\n\nNew Username: ").arg(QString::fromStdString(next_user_id))); dialog->resize(200, 100); while (dialog->exec() != QDialog::Rejected) @@ -370,7 +368,7 @@ void user_manager_dialog::OnUserLogin() main_application::InitializeEmulator(new_user, Emu.HasGui()); m_active_user = new_user; - m_persistent_settings->SetValue(gui::persistent::active_user, qstr(m_active_user)); + m_persistent_settings->SetValue(gui::persistent::active_user, QString::fromStdString(m_active_user)); UpdateTable(true); Q_EMIT OnUserLoginSuccess(); } @@ -425,7 +423,7 @@ void user_manager_dialog::ShowContextMenu(const QPoint &pos) connect(login_act, &QAction::triggered, this, &user_manager_dialog::OnUserLogin); connect(show_dir_act, &QAction::triggered, this, [this, key]() { - const QString path = qstr(m_user_list[key].GetUserDir()); + const QString path = QString::fromStdString(m_user_list[key].GetUserDir()); gui::utils::open_dir(path); });