diff --git a/CMakeLists.txt b/CMakeLists.txt
index bf7eb3c59..bf0b5537f 100755
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -10,7 +10,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED True)
if(APPLE)
list(APPEND ADDITIONAL_LANGUAGES OBJC)
# Starting with 15.4, Rosetta 2 has support for all the necessary instruction sets.
- set(CMAKE_OSX_DEPLOYMENT_TARGET 15.4)
+ set(CMAKE_OSX_DEPLOYMENT_TARGET 15.4 CACHE STRING "")
endif()
if (NOT CMAKE_BUILD_TYPE)
@@ -54,9 +54,9 @@ else()
endif()
if (ARCHITECTURE STREQUAL "x86_64")
- # Target Sandy Bridge as a reasonable subset of instructions supported by PS4 and host CPUs.
- # Note that the native PS4 architecture 'btver2' has been attempted but causes issues with M1 CPUs.
- add_compile_options(-march=sandybridge -mtune=generic)
+ # Target the same CPU architecture as the PS4, to maintain the same level of compatibility.
+ # Exclude SSE4a as it is only available on AMD CPUs.
+ add_compile_options(-march=btver2 -mtune=generic -mno-sse4a)
endif()
if (APPLE AND ARCHITECTURE STREQUAL "x86_64" AND CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "arm64")
@@ -105,11 +105,8 @@ if (CLANG_FORMAT)
unset(CCOMMENT)
endif()
-list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
-
# generate git revision information
-list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/externals/cmake-modules/")
-include(GetGitRevisionDescription)
+include("${CMAKE_CURRENT_SOURCE_DIR}/externals/cmake-modules/GetGitRevisionDescription.cmake")
get_git_head_revision(GIT_REF_SPEC GIT_REV)
git_describe(GIT_DESC --always --long --dirty)
git_branch_name(GIT_BRANCH)
@@ -209,6 +206,7 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/common/scm_rev.cpp.in" "${CMAKE_
message("end git things, remote: ${GIT_REMOTE_NAME}, branch: ${GIT_BRANCH}")
+list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
find_package(Boost 1.84.0 CONFIG)
find_package(FFmpeg 5.1.2 MODULE)
find_package(fmt 10.2.0 CONFIG)
@@ -229,10 +227,10 @@ find_package(ZLIB 1.3 MODULE)
find_package(Zydis 5.0.0 CONFIG)
find_package(pugixml 1.14 CONFIG)
find_package(libusb 1.0.27 MODULE)
-
if (APPLE)
find_package(date 3.0.1 CONFIG)
endif()
+list(POP_BACK CMAKE_MODULE_PATH)
# Note: Windows always has these functions through winpthreads
include(CheckSymbolExists)
@@ -1180,7 +1178,7 @@ target_include_directories(shadps4 PRIVATE ${HOST_SHADERS_INCLUDE})
# embed resources
-include(CMakeRC)
+include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/CMakeRC.cmake")
cmrc_add_resource_library(embedded-resources
ALIAS res::embedded
NAMESPACE res
diff --git a/REUSE.toml b/REUSE.toml
index ad2bc3678..662987611 100644
--- a/REUSE.toml
+++ b/REUSE.toml
@@ -57,11 +57,18 @@ path = [
"src/images/utils_icon.png",
"src/images/shadPS4.icns",
"src/images/shadps4.ico",
+ "src/images/shadps4.png",
"src/images/net.shadps4.shadPS4.svg",
"src/images/themes_icon.png",
"src/images/update_icon.png",
"src/images/youtube.png",
"src/images/website.png",
+ "src/images/discord.svg",
+ "src/images/github.svg",
+ "src/images/ko-fi.svg",
+ "src/images/shadps4.svg",
+ "src/images/website.svg",
+ "src/images/youtube.svg",
"src/shadps4.qrc",
"src/shadps4.rc",
"src/qt_gui/translations/update_translation.sh",
diff --git a/documents/Quickstart/Quickstart.md b/documents/Quickstart/Quickstart.md
index 9c6bc5a6f..55825ac7d 100644
--- a/documents/Quickstart/Quickstart.md
+++ b/documents/Quickstart/Quickstart.md
@@ -24,7 +24,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
- A CPU supporting the following instruction sets: MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, AVX, F16C, CLMUL, AES, BMI1, MOVBE, XSAVE, ABM
- **Intel**: Haswell generation or newer
- **AMD**: Jaguar generation or newer
- - **Apple**: Rosetta 2 on macOS 15 or newer
+ - **Apple**: Rosetta 2 on macOS 15.4 or newer
### GPU
diff --git a/externals/MoltenVK/SPIRV-Cross b/externals/MoltenVK/SPIRV-Cross
index cb71abe30..68300dc07 160000
--- a/externals/MoltenVK/SPIRV-Cross
+++ b/externals/MoltenVK/SPIRV-Cross
@@ -1 +1 @@
-Subproject commit cb71abe3063094bf383379b15473d39cb1144120
+Subproject commit 68300dc07ac3dc592dbbdb87e02d5180f984ad12
diff --git a/externals/MoltenVK/cereal b/externals/MoltenVK/cereal
index d1fcec807..a56bad8bb 160000
--- a/externals/MoltenVK/cereal
+++ b/externals/MoltenVK/cereal
@@ -1 +1 @@
-Subproject commit d1fcec807b372f04e4c1041b3058e11c12853e6e
+Subproject commit a56bad8bbb770ee266e930c95d37fff2a5be7fea
diff --git a/externals/date b/externals/date
index 28b7b2325..a45ea7c17 160000
--- a/externals/date
+++ b/externals/date
@@ -1 +1 @@
-Subproject commit 28b7b232521ace2c8ef3f2ad4126daec3569c14f
+Subproject commit a45ea7c17b4a7f320e199b71436074bd624c9e15
diff --git a/externals/dear_imgui b/externals/dear_imgui
index 636cd4a7d..f4d935909 160000
--- a/externals/dear_imgui
+++ b/externals/dear_imgui
@@ -1 +1 @@
-Subproject commit 636cd4a7d623a2bc9bf59bb3acbb4ca075befba3
+Subproject commit f4d9359095eff3eb03f685921edc1cf0e37b1687
diff --git a/externals/discord-rpc b/externals/discord-rpc
index d3b5af882..19f66e6dc 160000
--- a/externals/discord-rpc
+++ b/externals/discord-rpc
@@ -1 +1 @@
-Subproject commit d3b5af8827031f3bccbf8c15d5dc1bfdc9467f17
+Subproject commit 19f66e6dcabb2268965f453db9e5774ede43238f
diff --git a/externals/ffmpeg-core b/externals/ffmpeg-core
index 27de97c82..b0de1dcca 160000
--- a/externals/ffmpeg-core
+++ b/externals/ffmpeg-core
@@ -1 +1 @@
-Subproject commit 27de97c826b6b40c255891c37ac046a25836a575
+Subproject commit b0de1dcca26c0ebfb8011b8e59dd17fc399db0ff
diff --git a/externals/fmt b/externals/fmt
index 8ee89546f..64db979e3 160000
--- a/externals/fmt
+++ b/externals/fmt
@@ -1 +1 @@
-Subproject commit 8ee89546ffcf046309d1f0d38c0393f02fde56c8
+Subproject commit 64db979e38ec644b1798e41610b28c8d2c8a2739
diff --git a/externals/glslang b/externals/glslang
index a0995c49e..ba1640446 160000
--- a/externals/glslang
+++ b/externals/glslang
@@ -1 +1 @@
-Subproject commit a0995c49ebcaca2c6d3b03efbabf74f3843decdb
+Subproject commit ba1640446f3826a518721d1f083f3a8cca1120c3
diff --git a/externals/libpng b/externals/libpng
index c1cc0f3f4..34005e3d3 160000
--- a/externals/libpng
+++ b/externals/libpng
@@ -1 +1 @@
-Subproject commit c1cc0f3f4c3d4abd11ca68c59446a29ff6f95003
+Subproject commit 34005e3d3d373c0c36898cc55eae48a79c8238a1
diff --git a/externals/libusb b/externals/libusb
index 8f0b4a38f..a63a7e43e 160000
--- a/externals/libusb
+++ b/externals/libusb
@@ -1 +1 @@
-Subproject commit 8f0b4a38fc3eefa2b26a99dff89e1c12bf37afd4
+Subproject commit a63a7e43e0950a595cf4b98a0eaf4051749ace5f
diff --git a/externals/magic_enum b/externals/magic_enum
index 1a1824df7..a413fcc9c 160000
--- a/externals/magic_enum
+++ b/externals/magic_enum
@@ -1 +1 @@
-Subproject commit 1a1824df7ac798177a521eed952720681b0bf482
+Subproject commit a413fcc9c46a020a746907136a384c227f3cd095
diff --git a/externals/pugixml b/externals/pugixml
index 4bc14418d..caade5a28 160000
--- a/externals/pugixml
+++ b/externals/pugixml
@@ -1 +1 @@
-Subproject commit 4bc14418d12d289dd9978fdce9490a45deeb653e
+Subproject commit caade5a28aad86b92a4b5337a9dc70c4ba73c5eb
diff --git a/externals/robin-map b/externals/robin-map
index fe845fd78..4ec1bf19c 160000
--- a/externals/robin-map
+++ b/externals/robin-map
@@ -1 +1 @@
-Subproject commit fe845fd7852ef541c5479ae23b3d36b57f8608ee
+Subproject commit 4ec1bf19c6a96125ea22062f38c2cf5b958e448e
diff --git a/externals/sdl3 b/externals/sdl3
index a336b62d8..4093e4a19 160000
--- a/externals/sdl3
+++ b/externals/sdl3
@@ -1 +1 @@
-Subproject commit a336b62d8b0b97b09214e053203e442e2b6e2be5
+Subproject commit 4093e4a193971ef1d4928158e0a1832be42e4599
diff --git a/externals/toml11 b/externals/toml11
index 7f6c574ff..a01fe3b4c 160000
--- a/externals/toml11
+++ b/externals/toml11
@@ -1 +1 @@
-Subproject commit 7f6c574ff5aa1053534e7e19c0a4f22bf4c6aaca
+Subproject commit a01fe3b4c14c6d7b99ee3f07c9e80058c6403097
diff --git a/externals/vma b/externals/vma
index 5a53a1989..f378e7b3f 160000
--- a/externals/vma
+++ b/externals/vma
@@ -1 +1 @@
-Subproject commit 5a53a198945ba8260fbc58fadb788745ce6aa263
+Subproject commit f378e7b3f18f6e2b06b957f6ba7b1c7207d2a536
diff --git a/externals/vulkan-headers b/externals/vulkan-headers
index 952f776f6..5ceb9ed48 160000
--- a/externals/vulkan-headers
+++ b/externals/vulkan-headers
@@ -1 +1 @@
-Subproject commit 952f776f6573aafbb62ea717d871cd1d6816c387
+Subproject commit 5ceb9ed481e58e705d0d9b5326537daedd06b97d
diff --git a/externals/winpthreads b/externals/winpthreads
index f00c973a6..f35b0948d 160000
--- a/externals/winpthreads
+++ b/externals/winpthreads
@@ -1 +1 @@
-Subproject commit f00c973a6ab2a23573708568b8ef4acc20a9d36b
+Subproject commit f35b0948d36a736e6a2d052ae295a3ffde09703f
diff --git a/externals/xbyak b/externals/xbyak
index 4e44f4614..44a72f369 160000
--- a/externals/xbyak
+++ b/externals/xbyak
@@ -1 +1 @@
-Subproject commit 4e44f4614ddbf038f2a6296f5b906d5c72691e0f
+Subproject commit 44a72f369268f7d552650891b296693e91db86bb
diff --git a/externals/xxhash b/externals/xxhash
index 2bf8313b9..953a09abc 160000
--- a/externals/xxhash
+++ b/externals/xxhash
@@ -1 +1 @@
-Subproject commit 2bf8313b934633b2a5b7e8fd239645b85e10c852
+Subproject commit 953a09abc39096da9e216b6eb0002c681cdc1199
diff --git a/externals/zlib-ng b/externals/zlib-ng
index d54e3769b..fd0d263ce 160000
--- a/externals/zlib-ng
+++ b/externals/zlib-ng
@@ -1 +1 @@
-Subproject commit d54e3769be0c522015b784eca2af258b1c026107
+Subproject commit fd0d263cedab1a136f40d65199987e3eaeecfcbd
diff --git a/externals/zydis b/externals/zydis
index bffbb610c..120e0e705 160000
--- a/externals/zydis
+++ b/externals/zydis
@@ -1 +1 @@
-Subproject commit bffbb610cfea643b98e87658b9058382f7522807
+Subproject commit 120e0e705f8e3b507dc49377ac2879979f0d545c
diff --git a/src/core/devtools/widget/text_editor.cpp b/src/core/devtools/widget/text_editor.cpp
index 7171cac47..12031d1ef 100644
--- a/src/core/devtools/widget/text_editor.cpp
+++ b/src/core/devtools/widget/text_editor.cpp
@@ -627,65 +627,56 @@ void TextEditor::HandleKeyboardInputs() {
io.WantCaptureKeyboard = true;
io.WantTextInput = true;
- if (!IsReadOnly() && ctrl && !shift && !alt &&
- ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Z)))
+ if (!IsReadOnly() && ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_Z))
Undo();
- else if (!IsReadOnly() && !ctrl && !shift && alt &&
- ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Backspace)))
+ else if (!IsReadOnly() && !ctrl && !shift && alt && ImGui::IsKeyPressed(ImGuiKey_Backspace))
Undo();
- else if (!IsReadOnly() && ctrl && !shift && !alt &&
- ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Y)))
+ else if (!IsReadOnly() && ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_Y))
Redo();
- else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_UpArrow)))
+ else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGuiKey_UpArrow))
MoveUp(1, shift);
- else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_DownArrow)))
+ else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGuiKey_DownArrow))
MoveDown(1, shift);
- else if (!alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_LeftArrow)))
+ else if (!alt && ImGui::IsKeyPressed(ImGuiKey_LeftArrow))
MoveLeft(1, shift, ctrl);
- else if (!alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_RightArrow)))
+ else if (!alt && ImGui::IsKeyPressed(ImGuiKey_RightArrow))
MoveRight(1, shift, ctrl);
- else if (!alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_PageUp)))
+ else if (!alt && ImGui::IsKeyPressed(ImGuiKey_PageUp))
MoveUp(GetPageSize() - 4, shift);
- else if (!alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_PageDown)))
+ else if (!alt && ImGui::IsKeyPressed(ImGuiKey_PageDown))
MoveDown(GetPageSize() - 4, shift);
- else if (!alt && ctrl && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Home)))
+ else if (!alt && ctrl && ImGui::IsKeyPressed(ImGuiKey_Home))
MoveTop(shift);
- else if (ctrl && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_End)))
+ else if (ctrl && !alt && ImGui::IsKeyPressed(ImGuiKey_End))
MoveBottom(shift);
- else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Home)))
+ else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGuiKey_Home))
MoveHome(shift);
- else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_End)))
+ else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGuiKey_End))
MoveEnd(shift);
- else if (!IsReadOnly() && !ctrl && !shift && !alt &&
- ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Delete)))
+ else if (!IsReadOnly() && !ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_Delete))
Delete();
else if (!IsReadOnly() && !ctrl && !shift && !alt &&
- ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Backspace)))
+ ImGui::IsKeyPressed(ImGuiKey_Backspace))
Backspace();
- else if (!ctrl && !shift && !alt &&
- ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Insert)))
+ else if (!ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_Insert))
mOverwrite ^= true;
- else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Insert)))
+ else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_Insert))
Copy();
- else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_C)))
+ else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_C))
Copy();
- else if (!IsReadOnly() && !ctrl && shift && !alt &&
- ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Insert)))
+ else if (!IsReadOnly() && !ctrl && shift && !alt && ImGui::IsKeyPressed(ImGuiKey_Insert))
Paste();
- else if (!IsReadOnly() && ctrl && !shift && !alt &&
- ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_V)))
+ else if (!IsReadOnly() && ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_V))
Paste();
- else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_X)))
+ else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_X))
Cut();
- else if (!ctrl && shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Delete)))
+ else if (!ctrl && shift && !alt && ImGui::IsKeyPressed(ImGuiKey_Delete))
Cut();
- else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_A)))
+ else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_A))
SelectAll();
- else if (!IsReadOnly() && !ctrl && !shift && !alt &&
- ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Enter)))
+ else if (!IsReadOnly() && !ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_Enter))
EnterCharacter('\n', false);
- else if (!IsReadOnly() && !ctrl && !alt &&
- ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Tab)))
+ else if (!IsReadOnly() && !ctrl && !alt && ImGui::IsKeyPressed(ImGuiKey_Tab))
EnterCharacter('\t', shift);
if (!IsReadOnly() && !io.InputQueueCharacters.empty()) {
diff --git a/src/core/libraries/move/move.cpp b/src/core/libraries/move/move.cpp
index 626fed9b4..500d89586 100644
--- a/src/core/libraries/move/move.cpp
+++ b/src/core/libraries/move/move.cpp
@@ -9,7 +9,7 @@
namespace Libraries::Move {
int PS4_SYSV_ABI sceMoveOpen() {
- LOG_ERROR(Lib_Move, "(STUBBED) called");
+ LOG_TRACE(Lib_Move, "(STUBBED) called");
return ORBIS_FAIL;
}
@@ -18,6 +18,11 @@ int PS4_SYSV_ABI sceMoveGetDeviceInfo() {
return ORBIS_OK;
}
+int PS4_SYSV_ABI sceMoveReadStateLatest() {
+ LOG_TRACE(Lib_Move, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
int PS4_SYSV_ABI sceMoveReadStateRecent() {
LOG_TRACE(Lib_Move, "(STUBBED) called");
return ORBIS_OK;
@@ -36,6 +41,7 @@ int PS4_SYSV_ABI sceMoveInit() {
void RegisterlibSceMove(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("HzC60MfjJxU", "libSceMove", 1, "libSceMove", 1, 1, sceMoveOpen);
LIB_FUNCTION("GWXTyxs4QbE", "libSceMove", 1, "libSceMove", 1, 1, sceMoveGetDeviceInfo);
+ LIB_FUNCTION("ttU+JOhShl4", "libSceMove", 1, "libSceMove", 1, 1, sceMoveReadStateLatest);
LIB_FUNCTION("f2bcpK6kJfg", "libSceMove", 1, "libSceMove", 1, 1, sceMoveReadStateRecent);
LIB_FUNCTION("tsZi60H4ypY", "libSceMove", 1, "libSceMove", 1, 1, sceMoveTerm);
LIB_FUNCTION("j1ITE-EoJmE", "libSceMove", 1, "libSceMove", 1, 1, sceMoveInit);
diff --git a/src/core/libraries/pad/pad.cpp b/src/core/libraries/pad/pad.cpp
index 2e5973144..5dfc68e90 100644
--- a/src/core/libraries/pad/pad.cpp
+++ b/src/core/libraries/pad/pad.cpp
@@ -250,7 +250,6 @@ int PS4_SYSV_ABI scePadMbusTerm() {
}
int PS4_SYSV_ABI scePadOpen(s32 userId, s32 type, s32 index, const OrbisPadOpenParam* pParam) {
- LOG_INFO(Lib_Pad, "(DUMMY) called user_id = {} type = {} index = {}", userId, type, index);
if (userId == -1) {
return ORBIS_PAD_ERROR_DEVICE_NO_HANDLE;
}
@@ -261,6 +260,7 @@ int PS4_SYSV_ABI scePadOpen(s32 userId, s32 type, s32 index, const OrbisPadOpenP
if (type != ORBIS_PAD_PORT_TYPE_STANDARD && type != ORBIS_PAD_PORT_TYPE_REMOTE_CONTROL)
return ORBIS_PAD_ERROR_DEVICE_NOT_CONNECTED;
}
+ LOG_INFO(Lib_Pad, "(DUMMY) called user_id = {} type = {} index = {}", userId, type, index);
scePadResetLightBar(1);
return 1; // dummy
}
diff --git a/src/images/discord.png b/src/images/discord.png
index 2fa455fd1..9858f217e 100644
Binary files a/src/images/discord.png and b/src/images/discord.png differ
diff --git a/src/images/discord.svg b/src/images/discord.svg
new file mode 100644
index 000000000..a2f630923
--- /dev/null
+++ b/src/images/discord.svg
@@ -0,0 +1,24 @@
+
+
+
+
diff --git a/src/images/github.png b/src/images/github.png
index 22b101798..7b61598cc 100644
Binary files a/src/images/github.png and b/src/images/github.png differ
diff --git a/src/images/github.svg b/src/images/github.svg
new file mode 100644
index 000000000..1872a00ce
--- /dev/null
+++ b/src/images/github.svg
@@ -0,0 +1,22 @@
+
+
+
+
diff --git a/src/images/ko-fi.png b/src/images/ko-fi.png
index d19991b5f..ec0c94773 100644
Binary files a/src/images/ko-fi.png and b/src/images/ko-fi.png differ
diff --git a/src/images/ko-fi.svg b/src/images/ko-fi.svg
new file mode 100644
index 000000000..b8fd694fd
--- /dev/null
+++ b/src/images/ko-fi.svg
@@ -0,0 +1,22 @@
+
+
+
+
diff --git a/src/images/shadps4.ico b/src/images/shadps4.ico
index bb50f9995..870569def 100644
Binary files a/src/images/shadps4.ico and b/src/images/shadps4.ico differ
diff --git a/src/images/shadps4.png b/src/images/shadps4.png
new file mode 100644
index 000000000..037732e3b
Binary files /dev/null and b/src/images/shadps4.png differ
diff --git a/src/images/shadps4.svg b/src/images/shadps4.svg
new file mode 100644
index 000000000..0243f550b
--- /dev/null
+++ b/src/images/shadps4.svg
@@ -0,0 +1,105 @@
+
+
diff --git a/src/images/website.png b/src/images/website.png
index 9584f6b82..e872e60a2 100644
Binary files a/src/images/website.png and b/src/images/website.png differ
diff --git a/src/images/website.svg b/src/images/website.svg
new file mode 100644
index 000000000..eddc0e194
--- /dev/null
+++ b/src/images/website.svg
@@ -0,0 +1,22 @@
+
+
+
+
diff --git a/src/images/youtube.png b/src/images/youtube.png
index 362ac5781..2a69760e6 100644
Binary files a/src/images/youtube.png and b/src/images/youtube.png differ
diff --git a/src/images/youtube.svg b/src/images/youtube.svg
new file mode 100644
index 000000000..977e2b7ff
--- /dev/null
+++ b/src/images/youtube.svg
@@ -0,0 +1,28 @@
+
+
+
+
diff --git a/src/imgui/imgui_std.h b/src/imgui/imgui_std.h
index cd7208064..743702657 100644
--- a/src/imgui/imgui_std.h
+++ b/src/imgui/imgui_std.h
@@ -50,14 +50,14 @@ inline void KeepWindowInside(ImVec2 display_size = GetIO().DisplaySize) {
}
inline void KeepNavHighlight() {
- GetCurrentContext()->NavDisableHighlight = false;
+ GetCurrentContext()->NavCursorVisible = true;
}
inline void SetItemCurrentNavFocus(const ImGuiID id = -1) {
const auto ctx = GetCurrentContext();
SetFocusID(id == -1 ? ctx->LastItemData.ID : id, ctx->CurrentWindow);
ctx->NavInitResult.Clear();
- ctx->NavDisableHighlight = false;
+ ctx->NavCursorVisible = true;
}
inline void DrawPrettyBackground() {
diff --git a/src/qt_gui/about_dialog.ui b/src/qt_gui/about_dialog.ui
index 3842513a5..0e9ef222c 100644
--- a/src/qt_gui/about_dialog.ui
+++ b/src/qt_gui/about_dialog.ui
@@ -35,7 +35,7 @@
- :/images/shadps4.ico
+ :/images/shadps4.png
true
diff --git a/src/qt_gui/check_update.cpp b/src/qt_gui/check_update.cpp
index 7d3a42798..550fdddb5 100644
--- a/src/qt_gui/check_update.cpp
+++ b/src/qt_gui/check_update.cpp
@@ -188,7 +188,7 @@ void CheckUpdate::setupUI(const QString& downloadUrl, const QString& latestDate,
QHBoxLayout* titleLayout = new QHBoxLayout();
QLabel* imageLabel = new QLabel(this);
- QPixmap pixmap(":/images/shadps4.ico");
+ QPixmap pixmap(":/images/shadps4.png");
imageLabel->setPixmap(pixmap);
imageLabel->setScaledContents(true);
imageLabel->setFixedSize(50, 50);
diff --git a/src/shadps4.qrc b/src/shadps4.qrc
index 83dea01c4..2aee394c8 100644
--- a/src/shadps4.qrc
+++ b/src/shadps4.qrc
@@ -1,6 +1,7 @@
images/shadps4.ico
+ images/shadps4.png
images/about_icon.png
images/dump_icon.png
images/play_icon.png
diff --git a/src/video_core/renderer_vulkan/liverpool_to_vk.cpp b/src/video_core/renderer_vulkan/liverpool_to_vk.cpp
index 843bedb20..a6ae0c304 100644
--- a/src/video_core/renderer_vulkan/liverpool_to_vk.cpp
+++ b/src/video_core/renderer_vulkan/liverpool_to_vk.cpp
@@ -156,6 +156,18 @@ vk::CullModeFlags CullMode(Liverpool::CullMode mode) {
}
}
+vk::FrontFace FrontFace(Liverpool::FrontFace face) {
+ switch (face) {
+ case Liverpool::FrontFace::Clockwise:
+ return vk::FrontFace::eClockwise;
+ case Liverpool::FrontFace::CounterClockwise:
+ return vk::FrontFace::eCounterClockwise;
+ default:
+ UNREACHABLE();
+ return vk::FrontFace::eClockwise;
+ }
+}
+
vk::BlendFactor BlendFactor(Liverpool::BlendControl::BlendFactor factor) {
using BlendFactor = Liverpool::BlendControl::BlendFactor;
switch (factor) {
diff --git a/src/video_core/renderer_vulkan/liverpool_to_vk.h b/src/video_core/renderer_vulkan/liverpool_to_vk.h
index 42da7aa06..fca0a8378 100644
--- a/src/video_core/renderer_vulkan/liverpool_to_vk.h
+++ b/src/video_core/renderer_vulkan/liverpool_to_vk.h
@@ -26,6 +26,8 @@ vk::PolygonMode PolygonMode(Liverpool::PolygonMode mode);
vk::CullModeFlags CullMode(Liverpool::CullMode mode);
+vk::FrontFace FrontFace(Liverpool::FrontFace mode);
+
vk::BlendFactor BlendFactor(Liverpool::BlendControl::BlendFactor factor);
vk::BlendOp BlendOp(Liverpool::BlendControl::BlendFunc func);
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
index 7cd4bd872..354e22331 100644
--- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
+++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
@@ -28,6 +28,15 @@ static constexpr std::array LogicalStageToStageBit = {
vk::ShaderStageFlagBits::eCompute,
};
+static bool IsPrimitiveTopologyList(const vk::PrimitiveTopology topology) {
+ return topology == vk::PrimitiveTopology::ePointList ||
+ topology == vk::PrimitiveTopology::eLineList ||
+ topology == vk::PrimitiveTopology::eTriangleList ||
+ topology == vk::PrimitiveTopology::eLineListWithAdjacency ||
+ topology == vk::PrimitiveTopology::eTriangleListWithAdjacency ||
+ topology == vk::PrimitiveTopology::ePatchList;
+}
+
GraphicsPipeline::GraphicsPipeline(
const Instance& instance, Scheduler& scheduler, DescriptorHeap& desc_heap,
const Shader::Profile& profile, const GraphicsPipelineKey& key_,
@@ -75,19 +84,15 @@ GraphicsPipeline::GraphicsPipeline(
.pVertexAttributeDescriptions = vertex_attributes.data(),
};
- auto prim_restart = key.enable_primitive_restart != 0;
- if (prim_restart && IsPrimitiveListTopology() && !instance.IsListRestartSupported()) {
- LOG_DEBUG(Render_Vulkan,
- "Primitive restart is enabled for list topology but not supported by driver.");
- prim_restart = false;
- }
+ const auto topology = LiverpoolToVK::PrimitiveType(key.prim_type);
const vk::PipelineInputAssemblyStateCreateInfo input_assembly = {
- .topology = LiverpoolToVK::PrimitiveType(key.prim_type),
- .primitiveRestartEnable = prim_restart,
+ .topology = topology,
+ // Avoid warning spam on all pipelines about unsupported restart disable, if not supported.
+ // However, must be false for list topologies to avoid validation errors.
+ .primitiveRestartEnable =
+ !instance.IsPrimitiveRestartDisableSupported() && !IsPrimitiveTopologyList(topology),
};
- ASSERT_MSG(!prim_restart || key.primitive_restart_index == 0xFFFF ||
- key.primitive_restart_index == 0xFFFFFFFF,
- "Primitive restart index other than -1 is not supported yet");
+
const bool is_rect_list = key.prim_type == AmdGpu::PrimitiveType::RectList;
const bool is_quad_list = key.prim_type == AmdGpu::PrimitiveType::QuadList;
const auto& fs_info = runtime_infos[u32(Shader::LogicalStage::Fragment)].fs_info;
@@ -99,12 +104,6 @@ GraphicsPipeline::GraphicsPipeline(
.depthClampEnable = false,
.rasterizerDiscardEnable = false,
.polygonMode = LiverpoolToVK::PolygonMode(key.polygon_mode),
- .cullMode = LiverpoolToVK::IsPrimitiveCulled(key.prim_type)
- ? LiverpoolToVK::CullMode(key.cull_mode)
- : vk::CullModeFlagBits::eNone,
- .frontFace = key.front_face == Liverpool::FrontFace::Clockwise
- ? vk::FrontFace::eClockwise
- : vk::FrontFace::eCounterClockwise,
.lineWidth = 1.0f,
};
@@ -122,16 +121,20 @@ GraphicsPipeline::GraphicsPipeline(
.pNext = instance.IsDepthClipControlSupported() ? &clip_control : nullptr,
};
- boost::container::static_vector dynamic_states = {
+ boost::container::static_vector dynamic_states = {
vk::DynamicState::eViewportWithCountEXT, vk::DynamicState::eScissorWithCountEXT,
vk::DynamicState::eBlendConstants, vk::DynamicState::eDepthTestEnableEXT,
vk::DynamicState::eDepthWriteEnableEXT, vk::DynamicState::eDepthCompareOpEXT,
vk::DynamicState::eDepthBiasEnableEXT, vk::DynamicState::eDepthBias,
vk::DynamicState::eStencilTestEnableEXT, vk::DynamicState::eStencilReference,
vk::DynamicState::eStencilCompareMask, vk::DynamicState::eStencilWriteMask,
- vk::DynamicState::eStencilOpEXT,
+ vk::DynamicState::eStencilOpEXT, vk::DynamicState::eCullModeEXT,
+ vk::DynamicState::eFrontFaceEXT,
};
+ if (instance.IsPrimitiveRestartDisableSupported()) {
+ dynamic_states.push_back(vk::DynamicState::ePrimitiveRestartEnableEXT);
+ }
if (instance.IsDepthBoundsSupported()) {
dynamic_states.push_back(vk::DynamicState::eDepthBoundsTestEnableEXT);
dynamic_states.push_back(vk::DynamicState::eDepthBounds);
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h
index 7ffd14064..59230ae46 100644
--- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h
+++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h
@@ -42,11 +42,7 @@ struct GraphicsPipelineKey {
u32 num_samples;
u32 mrt_mask;
AmdGpu::PrimitiveType prim_type;
- u32 enable_primitive_restart;
- u32 primitive_restart_index;
Liverpool::PolygonMode polygon_mode;
- Liverpool::CullMode cull_mode;
- Liverpool::FrontFace front_face;
Liverpool::ClipSpace clip_space;
Liverpool::ColorBufferMask cb_shader_mask;
std::array blend_controls;
@@ -82,16 +78,6 @@ public:
return key.mrt_mask;
}
- [[nodiscard]] bool IsPrimitiveListTopology() const {
- return key.prim_type == AmdGpu::PrimitiveType::PointList ||
- key.prim_type == AmdGpu::PrimitiveType::LineList ||
- key.prim_type == AmdGpu::PrimitiveType::TriangleList ||
- key.prim_type == AmdGpu::PrimitiveType::AdjLineList ||
- key.prim_type == AmdGpu::PrimitiveType::AdjTriangleList ||
- key.prim_type == AmdGpu::PrimitiveType::RectList ||
- key.prim_type == AmdGpu::PrimitiveType::QuadList;
- }
-
/// Gets the attributes and bindings for vertex inputs.
template
void GetVertexInputs(VertexInputs& attributes, VertexInputs& bindings,
diff --git a/src/video_core/renderer_vulkan/vk_instance.h b/src/video_core/renderer_vulkan/vk_instance.h
index 04b68c1d0..6de419041 100644
--- a/src/video_core/renderer_vulkan/vk_instance.h
+++ b/src/video_core/renderer_vulkan/vk_instance.h
@@ -292,6 +292,11 @@ public:
properties.limits.framebufferStencilSampleCounts;
}
+ /// Returns whether disabling primitive restart is supported.
+ bool IsPrimitiveRestartDisableSupported() const {
+ return driver_id != vk::DriverId::eMoltenvk;
+ }
+
private:
/// Creates the logical device opportunistically enabling extensions
bool CreateDevice();
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index 17a1fdec4..bad2a549c 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -283,12 +283,8 @@ bool PipelineCache::RefreshGraphicsKey() {
}
key.prim_type = regs.primitive_type;
- key.enable_primitive_restart = regs.enable_primitive_restart & 1;
- key.primitive_restart_index = regs.primitive_restart_index;
key.polygon_mode = regs.polygon_control.PolyMode();
- key.cull_mode = regs.polygon_control.CullingMode();
key.clip_space = regs.clipper_control.clip_space;
- key.front_face = regs.polygon_control.front_face;
key.num_samples = regs.NumSamples();
const bool skip_cb_binding =
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index ecb0c0a75..30102960a 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -946,19 +946,20 @@ void Rasterizer::UnmapMemory(VAddr addr, u64 size) {
mapped_ranges -= boost::icl::interval::right_open(addr, addr + size);
}
-void Rasterizer::UpdateDynamicState(const GraphicsPipeline& pipeline) {
+void Rasterizer::UpdateDynamicState(const GraphicsPipeline& pipeline) const {
UpdateViewportScissorState();
UpdateDepthStencilState();
+ UpdatePrimitiveState();
- const auto& regs = liverpool->regs;
- const auto cmdbuf = scheduler.CommandBuffer();
- cmdbuf.setBlendConstants(®s.blend_constants.red);
- if (instance.IsDynamicColorWriteMaskSupported()) {
- cmdbuf.setColorWriteMaskEXT(0, pipeline.GetWriteMasks());
- }
+ auto& dynamic_state = scheduler.GetDynamicState();
+ dynamic_state.SetBlendConstants(&liverpool->regs.blend_constants.red);
+ dynamic_state.SetColorWriteMasks(pipeline.GetWriteMasks());
+
+ // Commit new dynamic state to the command buffer.
+ dynamic_state.Commit(instance, scheduler.CommandBuffer());
}
-void Rasterizer::UpdateViewportScissorState() {
+void Rasterizer::UpdateViewportScissorState() const {
const auto& regs = liverpool->regs;
const auto combined_scissor_value_tl = [](s16 scr, s16 win, s16 gen, s16 win_offset) {
@@ -1071,95 +1072,86 @@ void Rasterizer::UpdateViewportScissorState() {
scissors.push_back(empty_scissor);
}
- const auto cmdbuf = scheduler.CommandBuffer();
- cmdbuf.setViewportWithCountEXT(viewports);
- cmdbuf.setScissorWithCountEXT(scissors);
+ auto& dynamic_state = scheduler.GetDynamicState();
+ dynamic_state.SetViewports(viewports);
+ dynamic_state.SetScissors(scissors);
}
-void Rasterizer::UpdateDepthStencilState() {
- auto& regs = liverpool->regs;
- const auto cmdbuf = scheduler.CommandBuffer();
+void Rasterizer::UpdateDepthStencilState() const {
+ const auto& regs = liverpool->regs;
+ auto& dynamic_state = scheduler.GetDynamicState();
- bool depth_test = regs.depth_control.depth_enable && regs.depth_buffer.DepthValid();
- cmdbuf.setDepthTestEnableEXT(depth_test);
- cmdbuf.setDepthWriteEnableEXT(regs.depth_control.depth_write_enable &&
- !regs.depth_render_control.depth_clear_enable);
- if (depth_test) {
- cmdbuf.setDepthCompareOpEXT(LiverpoolToVK::CompareOp(regs.depth_control.depth_func));
+ const auto depth_test_enabled =
+ regs.depth_control.depth_enable && regs.depth_buffer.DepthValid();
+ dynamic_state.SetDepthTestEnabled(depth_test_enabled);
+ if (depth_test_enabled) {
+ dynamic_state.SetDepthWriteEnabled(regs.depth_control.depth_write_enable &&
+ !regs.depth_render_control.depth_clear_enable);
+ dynamic_state.SetDepthCompareOp(LiverpoolToVK::CompareOp(regs.depth_control.depth_func));
}
- if (instance.IsDepthBoundsSupported()) {
- cmdbuf.setDepthBoundsTestEnableEXT(regs.depth_control.depth_bounds_enable);
- if (regs.depth_control.depth_bounds_enable) {
- cmdbuf.setDepthBounds(regs.depth_bounds_min, regs.depth_bounds_max);
- }
+ const auto depth_bounds_test_enabled = regs.depth_control.depth_bounds_enable;
+ dynamic_state.SetDepthBoundsTestEnabled(depth_bounds_test_enabled);
+ if (depth_bounds_test_enabled) {
+ dynamic_state.SetDepthBounds(regs.depth_bounds_min, regs.depth_bounds_max);
}
- cmdbuf.setDepthBiasEnableEXT(regs.polygon_control.NeedsBias());
- if (regs.polygon_control.enable_polygon_offset_front) {
- cmdbuf.setDepthBias(regs.poly_offset.front_offset, regs.poly_offset.depth_bias,
- regs.poly_offset.front_scale / 16.f);
- } else if (regs.polygon_control.enable_polygon_offset_back) {
- cmdbuf.setDepthBias(regs.poly_offset.back_offset, regs.poly_offset.depth_bias,
- regs.poly_offset.back_scale / 16.f);
+ const auto depth_bias_enabled = regs.polygon_control.NeedsBias();
+ dynamic_state.SetDepthBiasEnabled(depth_bias_enabled);
+ if (depth_bias_enabled) {
+ const bool front = regs.polygon_control.enable_polygon_offset_front;
+ dynamic_state.SetDepthBias(
+ front ? regs.poly_offset.front_offset : regs.poly_offset.back_offset,
+ regs.poly_offset.depth_bias,
+ (front ? regs.poly_offset.front_scale : regs.poly_offset.back_scale) / 16.f);
}
- cmdbuf.setStencilTestEnableEXT(regs.depth_control.stencil_enable &&
- regs.depth_buffer.StencilValid());
- if (regs.depth_control.stencil_enable) {
- const auto front_fail_op =
- LiverpoolToVK::StencilOp(regs.stencil_control.stencil_fail_front);
- const auto front_pass_op =
- LiverpoolToVK::StencilOp(regs.stencil_control.stencil_zpass_front);
- const auto front_depth_fail_op =
- LiverpoolToVK::StencilOp(regs.stencil_control.stencil_zfail_front);
- const auto front_compare_op = LiverpoolToVK::CompareOp(regs.depth_control.stencil_ref_func);
- if (regs.depth_control.backface_enable) {
- const auto back_fail_op =
- LiverpoolToVK::StencilOp(regs.stencil_control.stencil_fail_back);
- const auto back_pass_op =
- LiverpoolToVK::StencilOp(regs.stencil_control.stencil_zpass_back);
- const auto back_depth_fail_op =
- LiverpoolToVK::StencilOp(regs.stencil_control.stencil_zfail_back);
- const auto back_compare_op =
- LiverpoolToVK::CompareOp(regs.depth_control.stencil_bf_func);
- cmdbuf.setStencilOpEXT(vk::StencilFaceFlagBits::eFront, front_fail_op, front_pass_op,
- front_depth_fail_op, front_compare_op);
- cmdbuf.setStencilOpEXT(vk::StencilFaceFlagBits::eBack, back_fail_op, back_pass_op,
- back_depth_fail_op, back_compare_op);
- } else {
- cmdbuf.setStencilOpEXT(vk::StencilFaceFlagBits::eFrontAndBack, front_fail_op,
- front_pass_op, front_depth_fail_op, front_compare_op);
- }
+ const auto stencil_test_enabled =
+ regs.depth_control.stencil_enable && regs.depth_buffer.StencilValid();
+ dynamic_state.SetStencilTestEnabled(stencil_test_enabled);
+ if (stencil_test_enabled) {
+ const StencilOps front_ops{
+ .fail_op = LiverpoolToVK::StencilOp(regs.stencil_control.stencil_fail_front),
+ .pass_op = LiverpoolToVK::StencilOp(regs.stencil_control.stencil_zpass_front),
+ .depth_fail_op = LiverpoolToVK::StencilOp(regs.stencil_control.stencil_zfail_front),
+ .compare_op = LiverpoolToVK::CompareOp(regs.depth_control.stencil_ref_func),
+ };
+ const StencilOps back_ops = regs.depth_control.backface_enable ? StencilOps{
+ .fail_op = LiverpoolToVK::StencilOp(regs.stencil_control.stencil_fail_back),
+ .pass_op = LiverpoolToVK::StencilOp(regs.stencil_control.stencil_zpass_back),
+ .depth_fail_op = LiverpoolToVK::StencilOp(regs.stencil_control.stencil_zfail_back),
+ .compare_op = LiverpoolToVK::CompareOp(regs.depth_control.stencil_bf_func),
+ } : front_ops;
+ dynamic_state.SetStencilOps(front_ops, back_ops);
const auto front = regs.stencil_ref_front;
- const auto back = regs.stencil_ref_back;
- if (front.stencil_test_val == back.stencil_test_val) {
- cmdbuf.setStencilReference(vk::StencilFaceFlagBits::eFrontAndBack,
- front.stencil_test_val);
- } else {
- cmdbuf.setStencilReference(vk::StencilFaceFlagBits::eFront, front.stencil_test_val);
- cmdbuf.setStencilReference(vk::StencilFaceFlagBits::eBack, back.stencil_test_val);
- }
-
- if (front.stencil_write_mask == back.stencil_write_mask) {
- cmdbuf.setStencilWriteMask(vk::StencilFaceFlagBits::eFrontAndBack,
- front.stencil_write_mask);
- } else {
- cmdbuf.setStencilWriteMask(vk::StencilFaceFlagBits::eFront, front.stencil_write_mask);
- cmdbuf.setStencilWriteMask(vk::StencilFaceFlagBits::eBack, back.stencil_write_mask);
- }
-
- if (front.stencil_mask == back.stencil_mask) {
- cmdbuf.setStencilCompareMask(vk::StencilFaceFlagBits::eFrontAndBack,
- front.stencil_mask);
- } else {
- cmdbuf.setStencilCompareMask(vk::StencilFaceFlagBits::eFront, front.stencil_mask);
- cmdbuf.setStencilCompareMask(vk::StencilFaceFlagBits::eBack, back.stencil_mask);
- }
+ const auto back =
+ regs.depth_control.backface_enable ? regs.stencil_ref_back : regs.stencil_ref_front;
+ dynamic_state.SetStencilReferences(front.stencil_test_val, back.stencil_test_val);
+ dynamic_state.SetStencilWriteMasks(front.stencil_write_mask, back.stencil_write_mask);
+ dynamic_state.SetStencilCompareMasks(front.stencil_mask, back.stencil_mask);
}
}
+void Rasterizer::UpdatePrimitiveState() const {
+ const auto& regs = liverpool->regs;
+ auto& dynamic_state = scheduler.GetDynamicState();
+
+ const auto prim_restart = (regs.enable_primitive_restart & 1) != 0;
+ ASSERT_MSG(!prim_restart || regs.primitive_restart_index == 0xFFFF ||
+ regs.primitive_restart_index == 0xFFFFFFFF,
+ "Primitive restart index other than -1 is not supported yet");
+
+ const auto cull_mode = LiverpoolToVK::IsPrimitiveCulled(regs.primitive_type)
+ ? LiverpoolToVK::CullMode(regs.polygon_control.CullingMode())
+ : vk::CullModeFlagBits::eNone;
+ const auto front_face = LiverpoolToVK::FrontFace(regs.polygon_control.front_face);
+
+ dynamic_state.SetPrimitiveRestartEnabled(prim_restart);
+ dynamic_state.SetCullMode(cull_mode);
+ dynamic_state.SetFrontFace(front_face);
+}
+
void Rasterizer::ScopeMarkerBegin(const std::string_view& str, bool from_guest) {
if ((from_guest && !Config::getVkGuestMarkersEnabled()) ||
(!from_guest && !Config::getVkHostMarkersEnabled())) {
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h
index 8e5d0065b..54bf3d253 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.h
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.h
@@ -75,9 +75,10 @@ private:
void DepthStencilCopy(bool is_depth, bool is_stencil);
void EliminateFastClear();
- void UpdateDynamicState(const GraphicsPipeline& pipeline);
- void UpdateViewportScissorState();
- void UpdateDepthStencilState();
+ void UpdateDynamicState(const GraphicsPipeline& pipeline) const;
+ void UpdateViewportScissorState() const;
+ void UpdateDepthStencilState() const;
+ void UpdatePrimitiveState() const;
bool FilterDraw();
diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp
index fd84c54ed..a48d93dee 100644
--- a/src/video_core/renderer_vulkan/vk_scheduler.cpp
+++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp
@@ -97,6 +97,9 @@ void Scheduler::AllocateWorkerCommandBuffers() {
ASSERT_MSG(begin_result == vk::Result::eSuccess, "Failed to begin command buffer: {}",
vk::to_string(begin_result));
+ // Invalidate dynamic state so it gets applied to the new command buffer.
+ dynamic_state.Invalidate();
+
#if TRACY_GPU_ENABLED
auto* profiler_ctx = instance.GetProfilerContext();
if (profiler_ctx) {
@@ -164,4 +167,151 @@ void Scheduler::SubmitExecution(SubmitInfo& info) {
}
}
+void DynamicState::Commit(const Instance& instance, const vk::CommandBuffer& cmdbuf) {
+ if (dirty_state.viewports) {
+ dirty_state.viewports = false;
+ cmdbuf.setViewportWithCountEXT(viewports);
+ }
+ if (dirty_state.scissors) {
+ dirty_state.scissors = false;
+ cmdbuf.setScissorWithCountEXT(scissors);
+ }
+ if (dirty_state.depth_test_enabled) {
+ dirty_state.depth_test_enabled = false;
+ cmdbuf.setDepthTestEnableEXT(depth_test_enabled);
+ }
+ if (dirty_state.depth_write_enabled) {
+ dirty_state.depth_write_enabled = false;
+ // Note that this must be set in a command buffer even if depth test is disabled.
+ cmdbuf.setDepthWriteEnableEXT(depth_write_enabled);
+ }
+ if (depth_test_enabled && dirty_state.depth_compare_op) {
+ dirty_state.depth_compare_op = false;
+ cmdbuf.setDepthCompareOpEXT(depth_compare_op);
+ }
+ if (dirty_state.depth_bounds_test_enabled) {
+ dirty_state.depth_bounds_test_enabled = false;
+ if (instance.IsDepthBoundsSupported()) {
+ cmdbuf.setDepthBoundsTestEnableEXT(depth_bounds_test_enabled);
+ }
+ }
+ if (depth_bounds_test_enabled && dirty_state.depth_bounds) {
+ dirty_state.depth_bounds = false;
+ if (instance.IsDepthBoundsSupported()) {
+ cmdbuf.setDepthBounds(depth_bounds_min, depth_bounds_max);
+ }
+ }
+ if (dirty_state.depth_bias_enabled) {
+ dirty_state.depth_bias_enabled = false;
+ cmdbuf.setDepthBiasEnableEXT(depth_bias_enabled);
+ }
+ if (depth_bias_enabled && dirty_state.depth_bias) {
+ dirty_state.depth_bias = false;
+ cmdbuf.setDepthBias(depth_bias_constant, depth_bias_clamp, depth_bias_slope);
+ }
+ if (dirty_state.stencil_test_enabled) {
+ dirty_state.stencil_test_enabled = false;
+ cmdbuf.setStencilTestEnableEXT(stencil_test_enabled);
+ }
+ if (stencil_test_enabled) {
+ if (dirty_state.stencil_front_ops && dirty_state.stencil_back_ops &&
+ stencil_front_ops == stencil_back_ops) {
+ dirty_state.stencil_front_ops = false;
+ dirty_state.stencil_back_ops = false;
+ cmdbuf.setStencilOpEXT(vk::StencilFaceFlagBits::eFrontAndBack,
+ stencil_front_ops.fail_op, stencil_front_ops.pass_op,
+ stencil_front_ops.depth_fail_op, stencil_front_ops.compare_op);
+ } else {
+ if (dirty_state.stencil_front_ops) {
+ dirty_state.stencil_front_ops = false;
+ cmdbuf.setStencilOpEXT(vk::StencilFaceFlagBits::eFront, stencil_front_ops.fail_op,
+ stencil_front_ops.pass_op, stencil_front_ops.depth_fail_op,
+ stencil_front_ops.compare_op);
+ }
+ if (dirty_state.stencil_back_ops) {
+ dirty_state.stencil_back_ops = false;
+ cmdbuf.setStencilOpEXT(vk::StencilFaceFlagBits::eBack, stencil_back_ops.fail_op,
+ stencil_back_ops.pass_op, stencil_back_ops.depth_fail_op,
+ stencil_back_ops.compare_op);
+ }
+ }
+ if (dirty_state.stencil_front_reference && dirty_state.stencil_back_reference &&
+ stencil_front_reference == stencil_back_reference) {
+ dirty_state.stencil_front_reference = false;
+ dirty_state.stencil_back_reference = false;
+ cmdbuf.setStencilReference(vk::StencilFaceFlagBits::eFrontAndBack,
+ stencil_front_reference);
+ } else {
+ if (dirty_state.stencil_front_reference) {
+ dirty_state.stencil_front_reference = false;
+ cmdbuf.setStencilReference(vk::StencilFaceFlagBits::eFront,
+ stencil_front_reference);
+ }
+ if (dirty_state.stencil_back_reference) {
+ dirty_state.stencil_back_reference = false;
+ cmdbuf.setStencilReference(vk::StencilFaceFlagBits::eBack, stencil_back_reference);
+ }
+ }
+ if (dirty_state.stencil_front_write_mask && dirty_state.stencil_back_write_mask &&
+ stencil_front_write_mask == stencil_back_write_mask) {
+ dirty_state.stencil_front_write_mask = false;
+ dirty_state.stencil_back_write_mask = false;
+ cmdbuf.setStencilWriteMask(vk::StencilFaceFlagBits::eFrontAndBack,
+ stencil_front_write_mask);
+ } else {
+ if (dirty_state.stencil_front_write_mask) {
+ dirty_state.stencil_front_write_mask = false;
+ cmdbuf.setStencilWriteMask(vk::StencilFaceFlagBits::eFront,
+ stencil_front_write_mask);
+ }
+ if (dirty_state.stencil_back_write_mask) {
+ dirty_state.stencil_back_write_mask = false;
+ cmdbuf.setStencilWriteMask(vk::StencilFaceFlagBits::eBack, stencil_back_write_mask);
+ }
+ }
+ if (dirty_state.stencil_front_compare_mask && dirty_state.stencil_back_compare_mask &&
+ stencil_front_compare_mask == stencil_back_compare_mask) {
+ dirty_state.stencil_front_compare_mask = false;
+ dirty_state.stencil_back_compare_mask = false;
+ cmdbuf.setStencilCompareMask(vk::StencilFaceFlagBits::eFrontAndBack,
+ stencil_front_compare_mask);
+ } else {
+ if (dirty_state.stencil_front_compare_mask) {
+ dirty_state.stencil_front_compare_mask = false;
+ cmdbuf.setStencilCompareMask(vk::StencilFaceFlagBits::eFront,
+ stencil_front_compare_mask);
+ }
+ if (dirty_state.stencil_back_compare_mask) {
+ dirty_state.stencil_back_compare_mask = false;
+ cmdbuf.setStencilCompareMask(vk::StencilFaceFlagBits::eBack,
+ stencil_back_compare_mask);
+ }
+ }
+ }
+ if (dirty_state.primitive_restart_enable) {
+ dirty_state.primitive_restart_enable = false;
+ if (instance.IsPrimitiveRestartDisableSupported()) {
+ cmdbuf.setPrimitiveRestartEnableEXT(primitive_restart_enable);
+ }
+ }
+ if (dirty_state.cull_mode) {
+ dirty_state.cull_mode = false;
+ cmdbuf.setCullModeEXT(cull_mode);
+ }
+ if (dirty_state.front_face) {
+ dirty_state.front_face = false;
+ cmdbuf.setFrontFaceEXT(front_face);
+ }
+ if (dirty_state.blend_constants) {
+ dirty_state.blend_constants = false;
+ cmdbuf.setBlendConstants(blend_constants);
+ }
+ if (dirty_state.color_write_masks) {
+ dirty_state.color_write_masks = false;
+ if (instance.IsDynamicColorWriteMaskSupported()) {
+ cmdbuf.setColorWriteMaskEXT(0, color_write_masks);
+ }
+ }
+}
+
} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_scheduler.h b/src/video_core/renderer_vulkan/vk_scheduler.h
index fd5e68373..7709e1d41 100644
--- a/src/video_core/renderer_vulkan/vk_scheduler.h
+++ b/src/video_core/renderer_vulkan/vk_scheduler.h
@@ -7,6 +7,7 @@
#include
#include "common/types.h"
#include "common/unique_function.h"
+#include "video_core/amdgpu/liverpool.h"
#include "video_core/renderer_vulkan/vk_master_semaphore.h"
#include "video_core/renderer_vulkan/vk_resource_pool.h"
@@ -55,6 +56,248 @@ struct SubmitInfo {
}
};
+using Viewports = boost::container::static_vector;
+using Scissors = boost::container::static_vector;
+using ColorWriteMasks = std::array;
+struct StencilOps {
+ vk::StencilOp fail_op{};
+ vk::StencilOp pass_op{};
+ vk::StencilOp depth_fail_op{};
+ vk::CompareOp compare_op{};
+
+ bool operator==(const StencilOps& other) const {
+ return fail_op == other.fail_op && pass_op == other.pass_op &&
+ depth_fail_op == other.depth_fail_op && compare_op == other.compare_op;
+ }
+};
+struct DynamicState {
+ struct {
+ bool viewports : 1;
+ bool scissors : 1;
+
+ bool depth_test_enabled : 1;
+ bool depth_write_enabled : 1;
+ bool depth_compare_op : 1;
+
+ bool depth_bounds_test_enabled : 1;
+ bool depth_bounds : 1;
+
+ bool depth_bias_enabled : 1;
+ bool depth_bias : 1;
+
+ bool stencil_test_enabled : 1;
+ bool stencil_front_ops : 1;
+ bool stencil_front_reference : 1;
+ bool stencil_front_write_mask : 1;
+ bool stencil_front_compare_mask : 1;
+ bool stencil_back_ops : 1;
+ bool stencil_back_reference : 1;
+ bool stencil_back_write_mask : 1;
+ bool stencil_back_compare_mask : 1;
+
+ bool primitive_restart_enable : 1;
+ bool cull_mode : 1;
+ bool front_face : 1;
+
+ bool blend_constants : 1;
+ bool color_write_masks : 1;
+ } dirty_state{};
+
+ Viewports viewports{};
+ Scissors scissors{};
+
+ bool depth_test_enabled{};
+ bool depth_write_enabled{};
+ vk::CompareOp depth_compare_op{};
+
+ bool depth_bounds_test_enabled{};
+ float depth_bounds_min{};
+ float depth_bounds_max{};
+
+ bool depth_bias_enabled{};
+ float depth_bias_constant{};
+ float depth_bias_clamp{};
+ float depth_bias_slope{};
+
+ bool stencil_test_enabled{};
+ StencilOps stencil_front_ops{};
+ u32 stencil_front_reference{};
+ u32 stencil_front_write_mask{};
+ u32 stencil_front_compare_mask{};
+ StencilOps stencil_back_ops{};
+ u32 stencil_back_reference{};
+ u32 stencil_back_write_mask{};
+ u32 stencil_back_compare_mask{};
+
+ bool primitive_restart_enable{};
+ vk::CullModeFlags cull_mode{};
+ vk::FrontFace front_face{};
+
+ float blend_constants[4]{};
+ ColorWriteMasks color_write_masks{};
+
+ /// Commits the dynamic state to the provided command buffer.
+ void Commit(const Instance& instance, const vk::CommandBuffer& cmdbuf);
+
+ /// Invalidates all dynamic state to be flushed into the next command buffer.
+ void Invalidate() {
+ std::memset(&dirty_state, 0xFF, sizeof(dirty_state));
+ }
+
+ void SetViewports(const Viewports& viewports_) {
+ if (!std::ranges::equal(viewports, viewports_)) {
+ viewports = viewports_;
+ dirty_state.viewports = true;
+ }
+ }
+
+ void SetScissors(const Scissors& scissors_) {
+ if (!std::ranges::equal(scissors, scissors_)) {
+ scissors = scissors_;
+ dirty_state.scissors = true;
+ }
+ }
+
+ void SetDepthTestEnabled(const bool enabled) {
+ if (depth_test_enabled != enabled) {
+ depth_test_enabled = enabled;
+ dirty_state.depth_test_enabled = true;
+ }
+ }
+
+ void SetDepthWriteEnabled(const bool enabled) {
+ if (depth_write_enabled != enabled) {
+ depth_write_enabled = enabled;
+ dirty_state.depth_write_enabled = true;
+ }
+ }
+
+ void SetDepthCompareOp(const vk::CompareOp compare_op) {
+ if (depth_compare_op != compare_op) {
+ depth_compare_op = compare_op;
+ dirty_state.depth_compare_op = true;
+ }
+ }
+
+ void SetDepthBoundsTestEnabled(const bool enabled) {
+ if (depth_bounds_test_enabled != enabled) {
+ depth_bounds_test_enabled = enabled;
+ dirty_state.depth_bounds_test_enabled = true;
+ }
+ }
+
+ void SetDepthBounds(const float min, const float max) {
+ if (depth_bounds_min != min || depth_bounds_max != max) {
+ depth_bounds_min = min;
+ depth_bounds_max = max;
+ dirty_state.depth_bounds = true;
+ }
+ }
+
+ void SetDepthBiasEnabled(const bool enabled) {
+ if (depth_bias_enabled != enabled) {
+ depth_bias_enabled = enabled;
+ dirty_state.depth_bias_enabled = true;
+ }
+ }
+
+ void SetDepthBias(const float constant, const float clamp, const float slope) {
+ if (depth_bias_constant != constant || depth_bias_clamp != clamp ||
+ depth_bias_slope != slope) {
+ depth_bias_constant = constant;
+ depth_bias_clamp = clamp;
+ depth_bias_slope = slope;
+ dirty_state.depth_bias = true;
+ }
+ }
+
+ void SetStencilTestEnabled(const bool enabled) {
+ if (stencil_test_enabled != enabled) {
+ stencil_test_enabled = enabled;
+ dirty_state.stencil_test_enabled = true;
+ }
+ }
+
+ void SetStencilOps(const StencilOps& front_ops, const StencilOps& back_ops) {
+ if (stencil_front_ops != front_ops) {
+ stencil_front_ops = front_ops;
+ dirty_state.stencil_front_ops = true;
+ }
+ if (stencil_back_ops != back_ops) {
+ stencil_back_ops = back_ops;
+ dirty_state.stencil_back_ops = true;
+ }
+ }
+
+ void SetStencilReferences(const u32 front_reference, const u32 back_reference) {
+ if (stencil_front_reference != front_reference) {
+ stencil_front_reference = front_reference;
+ dirty_state.stencil_front_reference = true;
+ }
+ if (stencil_back_reference != back_reference) {
+ stencil_back_reference = back_reference;
+ dirty_state.stencil_back_reference = true;
+ }
+ }
+
+ void SetStencilWriteMasks(const u32 front_write_mask, const u32 back_write_mask) {
+ if (stencil_front_write_mask != front_write_mask) {
+ stencil_front_write_mask = front_write_mask;
+ dirty_state.stencil_front_write_mask = true;
+ }
+ if (stencil_back_write_mask != back_write_mask) {
+ stencil_back_write_mask = back_write_mask;
+ dirty_state.stencil_back_write_mask = true;
+ }
+ }
+
+ void SetStencilCompareMasks(const u32 front_compare_mask, const u32 back_compare_mask) {
+ if (stencil_front_compare_mask != front_compare_mask) {
+ stencil_front_compare_mask = front_compare_mask;
+ dirty_state.stencil_front_compare_mask = true;
+ }
+ if (stencil_back_compare_mask != back_compare_mask) {
+ stencil_back_compare_mask = back_compare_mask;
+ dirty_state.stencil_back_compare_mask = true;
+ }
+ }
+
+ void SetPrimitiveRestartEnabled(const bool enabled) {
+ if (primitive_restart_enable != enabled) {
+ primitive_restart_enable = enabled;
+ dirty_state.primitive_restart_enable = true;
+ }
+ }
+
+ void SetCullMode(const vk::CullModeFlags cull_mode_) {
+ if (cull_mode != cull_mode_) {
+ cull_mode = cull_mode_;
+ dirty_state.cull_mode = true;
+ }
+ }
+
+ void SetFrontFace(const vk::FrontFace front_face_) {
+ if (front_face != front_face_) {
+ front_face = front_face_;
+ dirty_state.front_face = true;
+ }
+ }
+
+ void SetBlendConstants(const float blend_constants_[4]) {
+ if (!std::equal(blend_constants, std::end(blend_constants), blend_constants_)) {
+ std::memcpy(blend_constants, blend_constants_, sizeof(blend_constants));
+ dirty_state.blend_constants = true;
+ }
+ }
+
+ void SetColorWriteMasks(const ColorWriteMasks& color_write_masks_) {
+ if (!std::ranges::equal(color_write_masks, color_write_masks_)) {
+ color_write_masks = color_write_masks_;
+ dirty_state.color_write_masks = true;
+ }
+ }
+};
+
class Scheduler {
public:
explicit Scheduler(const Instance& instance);
@@ -81,6 +324,10 @@ public:
return render_state;
}
+ DynamicState& GetDynamicState() {
+ return dynamic_state;
+ }
+
/// Returns the current command buffer.
vk::CommandBuffer CommandBuffer() const {
return current_cmdbuf;
@@ -125,6 +372,7 @@ private:
};
std::queue pending_ops;
RenderState render_state;
+ DynamicState dynamic_state;
bool is_rendering = false;
tracy::VkCtxScope* profiler_scope{};
};